libsysprof-ui: land new UI design

This comprises a massive rewrite of the UI for browsing captures. We use
the SysprofAid class to scan capture files for content and then auto-
matically add visualizers and details pages.

To avoid breaking things incrementally, we just land this as a very large
commit. Not necessarily ideal, but given the amount of stuff that could
break, this is easier.

As part of this process, we're removing a lot of the surface API so that
we can limit how much we need to maintain in terms of ABI.
This commit is contained in:
Christian Hergert
2019-06-24 20:28:18 -07:00
parent a40564cdda
commit e8528609ec
99 changed files with 10571 additions and 5538 deletions

View File

@ -0,0 +1,89 @@
SysprofDisplay dzlmultipaned {
-DzlMultiPaned-handle-size: 0;
}
SysprofVisualizer {
background: @content_view_bg;
}
SysprofVisualizer:not(:last-child) {
border-bottom: 1px solid alpha(@borders, 0.3);
}
SysprofVisualizerGroup {
border-bottom: 1px solid @borders;
}
SysprofVisualizerGroup:last-child {
box-shadow: 0 20px 15px 15px alpha(@borders, 0.3);
}
SysprofVisualizersFrame box.horizontal.inline-toolbar {
padding: 0;
margin: 0;
border: none;
border-radius: 0;
border-width: 0;
}
SysprofVisualizersFrame scrollbar.horizontal {
color: mix(@theme_fg_color, @theme_selected_bg_color, 0.5);
background: transparent;
}
SysprofVisualizersFrame scrollbar.horizontal contents trough {
background: transparent;
}
SysprofVisualizersFrame scrollbar.horizontal contents trough slider {
margin-left: 1px;
margin-right: 1px;
padding: 6px;
min-height: 14px;
background: alpha(@content_view_bg, 0.2);
border-radius: 3px;
border: 2px solid @theme_selected_bg_color;
box-shadow: inset 0 10px 5px alpha(@content_view_bg,.3),
inset 0 -15px 5px alpha(@content_view_bg,.1),
0px 2px 4px @borders;
}
SysprofVisualizerTicks {
color: mix(@theme_fg_color, @borders, 0.5);
background-color: @theme_bg_color;
}
SysprofVisualizersFrame list {
background-color: @theme_bg_color;
}
SysprofVisualizersFrame list.visualizer-groups row {
padding: 0;
border-bottom: 1px solid @borders;
}
SysprofVisualizersFrame list.visualizer-groups row:not(:selected) {
background-color: @theme_bg_color;
}
SysprofVisualizersFrame list.visualizer-groups row:last-child {
box-shadow: 0 20px 15px 15px alpha(@borders, 0.3);
}
SysprofVisualizersFrame .left-column .small-button.flat {
border-color: transparent;
min-height: 8px;
min-width: 8px;
}
SysprofVisualizersFrame .left-column .small-button.flat:checked,
SysprofVisualizersFrame .left-column .small-button.flat:hover {
border-color: @borders;
}
SysprofDisplay > dzlmultipaned > :nth-child(2) {
border-top: 1px solid @borders;
}
SysprofVisualizersFrame .selection {
border-radius: 3px;
background-color: alpha(@theme_selected_bg_color, 0.35);
box-shadow: inset 0 10px 5px alpha(@content_view_bg,.3),
inset 0 -15px 5px alpha(@content_view_bg,.1),
inset 0 0 1px 1px @theme_selected_bg_color;
}

View File

@ -1,6 +0,0 @@
visualizers list row {
background-color: #201f21;
background-size: 8px 8px;
background-image: repeating-linear-gradient(0deg, #232224, #232224 1px, transparent 1px, transparent 8px),
repeating-linear-gradient(-90deg, #232224, #232224 1px, transparent 1px, transparent 8px);
}

View File

@ -1,7 +0,0 @@
visualizers list row {
background-color: #f6f7f8;
background-size: 8px 8px;
background-image: repeating-linear-gradient(0deg, #f0f1f2, #f0f1f2 1px, transparent 1px, transparent 8px),
repeating-linear-gradient(-90deg, #f0f1f2, #f0f1f2 1px, transparent 1px, transparent 8px);
}

View File

@ -1,13 +0,0 @@
visualizers.selection {
background: none;
background-color: alpha(@theme_selected_bg_color, 0.35);
box-shadow: 0 0 0 1px @theme_selected_bg_color inset;
}
visualizers.selection:backdrop {
background: none;
background-color: alpha(@theme_selected_bg_color, 0.15);
border: none;
}
visualizers list row:not(:first-child) {
border-top: 1px solid alpha(@borders, 0.4);
}

View File

@ -2,9 +2,7 @@
<gresources>
<gresource prefix="/org/gnome/sysprof">
<file compressed="true">css/SysprofEnvironEditor-shared.css</file>
<file compressed="true">css/SysprofVisualizerView-shared.css</file>
<file compressed="true">css/SysprofVisualizerView-Adwaita.css</file>
<file compressed="true">css/SysprofVisualizerView-Adwaita-dark.css</file>
<file compressed="true">css/SysprofDisplay-shared.css</file>
<!-- Application icons -->
<file alias="icons/scalable/apps/org.gnome.Sysprof.svg">../../data/icons/scalable/apps/org.gnome.Sysprof.svg</file>
@ -14,20 +12,18 @@
<gresource prefix="/org/gnome/sysprof/ui">
<file preprocess="xml-stripblanks">sysprof-aid-icon.ui</file>
<file preprocess="xml-stripblanks">sysprof-callgraph-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-capture-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-callgraph-page.ui</file>
<file preprocess="xml-stripblanks">sysprof-details-page.ui</file>
<file preprocess="xml-stripblanks">sysprof-display.ui</file>
<file preprocess="xml-stripblanks">sysprof-details-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-empty-state-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-environ-editor-row.ui</file>
<file preprocess="xml-stripblanks">sysprof-failed-state-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-logs-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-marks-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-logs-page.ui</file>
<file preprocess="xml-stripblanks">sysprof-marks-page.ui</file>
<file preprocess="xml-stripblanks">sysprof-process-model-row.ui</file>
<file preprocess="xml-stripblanks">sysprof-profiler-assistant.ui</file>
<file preprocess="xml-stripblanks">sysprof-recording-state-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-tab.ui</file>
<file preprocess="xml-stripblanks">sysprof-time-label.ui</file>
<file preprocess="xml-stripblanks">sysprof-visualizer-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-visualizers-frame.ui</file>
</gresource>
</gresources>

View File

@ -1,84 +1,71 @@
if get_option('enable_gtk') and get_option('libsysprof')
libsysprof_ui_public_sources = [
'sysprof-aid.c',
'sysprof-capture-view.c',
'sysprof-callgraph-aid.c',
'sysprof-callgraph-view.c',
'sysprof-check.c',
'sysprof-color-cycle.c',
'sysprof-cpu-aid.c',
'sysprof-cpu-visualizer-row.c',
'sysprof-display.c',
'sysprof-empty-state-view.c',
'sysprof-failed-state-view.c',
'sysprof-line-visualizer-row.c',
'sysprof-marks-model.c',
'sysprof-marks-view.c',
'sysprof-mark-visualizer-row.c',
'sysprof-memory-aid.c',
'sysprof-model-filter.c',
'sysprof-notebook.c',
'sysprof-page.c',
'sysprof-process-model-row.c',
'sysprof-proxy-aid.c',
'sysprof-profiler-assistant.c',
'sysprof-recording-state-view.c',
'sysprof-visualizer-list.c',
'sysprof-visualizer-row.c',
'sysprof-visualizer-ticks.c',
'sysprof-visualizer-view.c',
'sysprof-visualizer.c',
'sysprof-visualizer-group.c',
'sysprof-zoom-manager.c',
]
libsysprof_ui_private_sources = [
'pointcache.c',
'rectangles.c',
'sysprof-aid.c',
'sysprof-aid-icon.c',
'sysprof-details-view.c',
'sysprof-battery-aid.c',
'sysprof-cairo.c',
'sysprof-callgraph-aid.c',
'sysprof-callgraph-page.c',
'sysprof-cell-renderer-duration.c',
'sysprof-cell-renderer-percent.c',
'sysprof-depth-visualizer-row.c',
'sysprof-environ-editor-row.c',
'sysprof-environ-editor.c',
'sysprof-environ-variable.c',
'sysprof-color-cycle.c',
'sysprof-counters-aid.c',
'sysprof-cpu-aid.c',
'sysprof-depth-visualizer.c',
'sysprof-details-page.c',
'sysprof-display.c',
'sysprof-environ.c',
'sysprof-environ-editor.c',
'sysprof-environ-editor-row.c',
'sysprof-environ-variable.c',
'sysprof-failed-state-view.c',
'sysprof-line-visualizer.c',
'sysprof-log-model.c',
'sysprof-logs-view.c',
'sysprof-logs-aid.c',
'sysprof-logs-page.c',
'sysprof-marks-aid.c',
'sysprof-marks-model.c',
'sysprof-marks-page.c',
'sysprof-mark-visualizer.c',
'sysprof-memory-aid.c',
'sysprof-profiler-assistant.c',
'sysprof-proxy-aid.c',
'sysprof-recording-state-view.c',
'sysprof-scrollmap.c',
'sysprof-tab.c',
'sysprof-time-label.c',
'sysprof-theme-manager.c',
'sysprof-time-label.c',
'sysprof-time-visualizer.c',
'sysprof-visualizer-group-header.c',
'sysprof-visualizers-frame.c',
'sysprof-visualizer-ticks.c',
'../stackstash.c',
]
libsysprof_ui_public_headers = [
'sysprof-aid.h',
'sysprof-capture-view.h',
'sysprof-callgraph-aid.h',
'sysprof-callgraph-view.h',
'sysprof-cell-renderer-percent.h',
'sysprof-check.h',
'sysprof-cpu-aid.h',
'sysprof-cpu-visualizer-row.h',
'sysprof-display.h',
'sysprof-empty-state-view.h',
'sysprof-failed-state-view.h',
'sysprof-line-visualizer-row.h',
'sysprof-marks-model.h',
'sysprof-marks-view.h',
'sysprof-mark-visualizer-row.h',
'sysprof-memory-aid.h',
'sysprof-model-filter.c',
'sysprof-model-filter.h',
'sysprof-notebook.h',
'sysprof-page.h',
'sysprof-process-model-row.h',
'sysprof-proxy-aid.h',
'sysprof-profiler-assistant.h',
'sysprof-recording-state-view.h',
'sysprof-visualizer-list.h',
'sysprof-visualizer-row.h',
'sysprof-visualizer-ticks.h',
'sysprof-visualizer-view.h',
'sysprof-visualizer.h',
'sysprof-visualizer-group.h',
'sysprof-zoom-manager.h',
'sysprof-ui.h',
]

View File

@ -20,7 +20,7 @@
#include "rectangles.h"
#include "sysprof-color-cycle.h"
#include "sysprof-visualizer-row.h"
#include "sysprof-visualizer.h"
typedef struct
{
@ -153,18 +153,18 @@ rectangles_draw (Rectangles *self,
{
GtkAllocation alloc;
gdouble range;
guint n_rows;
guint ns;
g_assert (self != NULL);
g_assert (SYSPROF_IS_VISUALIZER_ROW (row));
g_assert (SYSPROF_IS_VISUALIZER (row));
g_assert (cr != NULL);
if (!self->sorted)
rectangles_sort (self);
gtk_widget_get_allocation (row, &alloc);
n_rows = g_hash_table_size (self->y_indexes);
if (n_rows == 0 || alloc.height == 0)
ns = g_hash_table_size (self->y_indexes);
if (ns == 0 || alloc.height == 0)
return;
range = self->end_time - self->begin_time;
@ -173,24 +173,24 @@ rectangles_draw (Rectangles *self,
{
Rectangle *rect = &g_array_index (self->rectangles, Rectangle, i);
guint y_index = GPOINTER_TO_UINT (g_hash_table_lookup (self->y_indexes, rect->name));
SysprofVisualizerRowRelativePoint in_points[2];
SysprofVisualizerRowAbsolutePoint out_points[2];
SysprofVisualizerRelativePoint in_points[2];
SysprofVisualizerAbsolutePoint out_points[2];
GdkRectangle r;
GdkRGBA *rgba;
g_assert (y_index > 0);
g_assert (y_index <= n_rows);
g_assert (y_index <= ns);
in_points[0].x = (rect->begin - self->begin_time) / range;
in_points[0].y = (y_index - 1) / (gdouble)n_rows;
in_points[0].y = (y_index - 1) / (gdouble)ns;
in_points[1].x = (rect->end - self->begin_time) / range;
in_points[1].y = 0;
sysprof_visualizer_row_translate_points (SYSPROF_VISUALIZER_ROW (row),
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (row),
in_points, G_N_ELEMENTS (in_points),
out_points, G_N_ELEMENTS (out_points));
r.height = alloc.height / (gdouble)n_rows;
r.height = alloc.height / (gdouble)ns;
r.x = out_points[0].x;
r.y = out_points[0].y - r.height;

View File

@ -49,6 +49,29 @@ enum {
static GParamSpec *properties [N_PROPS];
static void
sysprof_aid_real_present_async (SysprofAid *self,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_task_report_new_error (self, callback, user_data,
sysprof_aid_real_present_async,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Not supported");
}
static gboolean
sysprof_aid_real_present_finish (SysprofAid *self,
GAsyncResult *result,
GError **error)
{
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
sysprof_aid_finalize (GObject *object)
{
@ -121,6 +144,9 @@ sysprof_aid_class_init (SysprofAidClass *klass)
object_class->get_property = sysprof_aid_get_property;
object_class->set_property = sysprof_aid_set_property;
klass->present_async = sysprof_aid_real_present_async;
klass->present_finish = sysprof_aid_real_present_finish;
properties [PROP_DISPLAY_NAME] =
g_param_spec_string ("display-name",
"Display Name",
@ -146,7 +172,7 @@ sysprof_aid_class_init (SysprofAidClass *klass)
}
static void
sysprof_aid_init (SysprofAid *self)
sysprof_aid_init (SysprofAid *self G_GNUC_UNUSED)
{
}
@ -258,10 +284,10 @@ sysprof_aid_prepare (SysprofAid *self,
}
static void
sysprof_aid_add_child (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *object,
const gchar *type)
sysprof_aid_add_child (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *object,
const gchar *type G_GNUC_UNUSED)
{
SysprofAid *self = (SysprofAid *)buildable;
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
@ -298,3 +324,30 @@ sysprof_aid_new (const gchar *display_name,
"icon-name", icon_name,
NULL);
}
void
sysprof_aid_present_async (SysprofAid *self,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (SYSPROF_IS_AID (self));
g_return_if_fail (reader != NULL);
g_return_if_fail (SYSPROF_IS_DISPLAY (display));
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
SYSPROF_AID_GET_CLASS (self)->present_async (self, reader, display, cancellable, callback, user_data);
}
gboolean
sysprof_aid_present_finish (SysprofAid *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (SYSPROF_IS_AID (self), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
return SYSPROF_AID_GET_CLASS (self)->present_finish (self, result, error);
}

View File

@ -20,49 +20,57 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gio/gio.h>
#include <sysprof.h>
#include "sysprof-display.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_AID (sysprof_aid_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofAid, sysprof_aid, SYSPROF, AID, GObject)
struct _SysprofAidClass
{
GObjectClass parent_class;
void (*prepare) (SysprofAid *self,
SysprofProfiler *profiler);
void (*prepare) (SysprofAid *self,
SysprofProfiler *profiler);
void (*present_async) (SysprofAid *self,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (*present_finish) (SysprofAid *self,
GAsyncResult *result,
GError **error);
/*< gpointer >*/
/*< private >*/
gpointer _reserved[16];
};
SYSPROF_AVAILABLE_IN_ALL
SysprofAid *sysprof_aid_new (const gchar *display_name,
const gchar *icon_name);
SYSPROF_AVAILABLE_IN_ALL
const gchar *sysprof_aid_get_display_name (SysprofAid *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_aid_set_display_name (SysprofAid *self,
const gchar *display_name);
SYSPROF_AVAILABLE_IN_ALL
GIcon *sysprof_aid_get_icon (SysprofAid *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_aid_set_icon (SysprofAid *self,
GIcon *icon);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_aid_set_icon_name (SysprofAid *self,
const gchar *icon_name);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_aid_prepare (SysprofAid *self,
SysprofProfiler *profiler);
SysprofAid *sysprof_aid_new (const gchar *display_name,
const gchar *icon_name);
const gchar *sysprof_aid_get_display_name (SysprofAid *self);
void sysprof_aid_set_display_name (SysprofAid *self,
const gchar *display_name);
GIcon *sysprof_aid_get_icon (SysprofAid *self);
void sysprof_aid_set_icon (SysprofAid *self,
GIcon *icon);
void sysprof_aid_set_icon_name (SysprofAid *self,
const gchar *icon_name);
void sysprof_aid_prepare (SysprofAid *self,
SysprofProfiler *profiler);
void sysprof_aid_present_async (SysprofAid *self,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean sysprof_aid_present_finish (SysprofAid *self,
GAsyncResult *result,
GError **error);
G_END_DECLS

View File

@ -0,0 +1,239 @@
/* sysprof-battery-aid.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-battery-aid"
#include "config.h"
#include <glib/gi18n.h>
#include "sysprof-color-cycle.h"
#include "sysprof-battery-aid.h"
#include "sysprof-line-visualizer.h"
struct _SysprofBatteryAid
{
SysprofAid parent_instance;
};
typedef struct
{
SysprofCaptureCursor *cursor;
SysprofDisplay *display;
} Present;
G_DEFINE_TYPE (SysprofBatteryAid, sysprof_battery_aid, SYSPROF_TYPE_AID)
static void
present_free (gpointer data)
{
Present *p = data;
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
g_clear_object (&p->display);
g_slice_free (Present, p);
}
/**
* sysprof_battery_aid_new:
*
* Create a new #SysprofBatteryAid.
*
* Returns: (transfer full): a newly created #SysprofBatteryAid
*
* Since: 3.34
*/
SysprofAid *
sysprof_battery_aid_new (void)
{
return g_object_new (SYSPROF_TYPE_BATTERY_AID, NULL);
}
static void
sysprof_battery_aid_prepare (SysprofAid *self,
SysprofProfiler *profiler)
{
#ifdef __linux__
g_autoptr(SysprofSource) source = NULL;
g_assert (SYSPROF_IS_BATTERY_AID (self));
g_assert (SYSPROF_IS_PROFILER (profiler));
source = sysprof_battery_source_new ();
sysprof_profiler_add_source (profiler, source);
#endif
}
static gboolean
collect_battery_counters (const SysprofCaptureFrame *frame,
gpointer user_data)
{
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
GArray *counters = user_data;
g_assert (frame != NULL);
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
g_assert (counters != NULL);
for (guint i = 0; i < def->n_counters; i++)
{
const SysprofCaptureCounter *counter = &def->counters[i];
if (g_strcmp0 (counter->category, "Battery Charge") == 0)
g_array_append_vals (counters, counter, 1);
}
return TRUE;
}
static void
sysprof_battery_aid_present_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
Present *present = task_data;
g_autoptr(GArray) counters = NULL;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_BATTERY_AID (source_object));
g_assert (present != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
sysprof_capture_cursor_foreach (present->cursor, collect_battery_counters, counters);
g_task_return_pointer (task,
g_steal_pointer (&counters),
(GDestroyNotify) g_array_unref);
}
static void
sysprof_battery_aid_present_async (SysprofAid *aid,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
g_autoptr(SysprofCaptureCondition) condition = NULL;
g_autoptr(SysprofCaptureCursor) cursor = NULL;
g_autoptr(GTask) task = NULL;
Present present;
g_assert (SYSPROF_IS_BATTERY_AID (aid));
g_assert (reader != NULL);
g_assert (SYSPROF_IS_DISPLAY (display));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
condition = sysprof_capture_condition_new_where_type_in (1, types);
cursor = sysprof_capture_cursor_new (reader);
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
present.cursor = g_steal_pointer (&cursor);
present.display = g_object_ref (display);
task = g_task_new (aid, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_battery_aid_present_async);
g_task_set_task_data (task,
g_slice_dup (Present, &present),
present_free);
g_task_run_in_thread (task, sysprof_battery_aid_present_worker);
}
static gboolean
sysprof_battery_aid_present_finish (SysprofAid *aid,
GAsyncResult *result,
GError **error)
{
g_autoptr(GArray) counters = NULL;
Present *present;
g_assert (SYSPROF_IS_AID (aid));
g_assert (G_IS_TASK (result));
present = g_task_get_task_data (G_TASK (result));
if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
{
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
SysprofVisualizerGroup *group;
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
"can-focus", TRUE,
"title", _("Battery Charge"),
"visible", TRUE,
NULL);
for (guint i = 0; i < counters->len; i++)
{
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
if (g_strcmp0 (ctr->category, "Battery Charge") == 0)
{
g_autofree gchar *title = NULL;
gboolean is_combined = g_str_equal (ctr->name, "Combined");
GtkWidget *row;
GdkRGBA rgba;
if (is_combined)
title = g_strdup (_("Battery Charge (All)"));
else
title = g_strdup_printf ("Battery Charge (%s)", ctr->name);
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
"title", title,
"height-request", 35,
"visible", is_combined,
NULL);
sysprof_color_cycle_next (cycle, &rgba);
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
sysprof_visualizer_group_insert (group,
SYSPROF_VISUALIZER (row),
is_combined ? 0 : -1,
!is_combined);
}
}
if (counters->len > 0)
sysprof_display_add_group (present->display, group);
else
gtk_widget_destroy (GTK_WIDGET (group));
}
return counters != NULL;
}
static void
sysprof_battery_aid_class_init (SysprofBatteryAidClass *klass)
{
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
aid_class->prepare = sysprof_battery_aid_prepare;
aid_class->present_async = sysprof_battery_aid_present_async;
aid_class->present_finish = sysprof_battery_aid_present_finish;
}
static void
sysprof_battery_aid_init (SysprofBatteryAid *self)
{
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Battery"));
sysprof_aid_set_icon_name (SYSPROF_AID (self), "battery-low-charging-symbolic");
}

View File

@ -1,4 +1,4 @@
/* sysprof-depth-visualizer-row.h
/* sysprof-battery-aid.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
@ -20,12 +20,14 @@
#pragma once
#include "sysprof-visualizer-row.h"
#include "sysprof-aid.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_DEPTH_VISUALIZER_ROW (sysprof_depth_visualizer_row_get_type())
#define SYSPROF_TYPE_BATTERY_AID (sysprof_battery_aid_get_type())
G_DECLARE_FINAL_TYPE (SysprofDepthVisualizerRow, sysprof_depth_visualizer_row, SYSPROF, DEPTH_VISUALIZER_ROW, SysprofVisualizerRow)
G_DECLARE_FINAL_TYPE (SysprofBatteryAid, sysprof_battery_aid, SYSPROF, BATTERY_AID, SysprofAid)
SysprofAid *sysprof_battery_aid_new (void);
G_END_DECLS

View File

@ -25,14 +25,46 @@
#include <glib/gi18n.h>
#include "sysprof-callgraph-aid.h"
#include "sysprof-callgraph-page.h"
#include "sysprof-depth-visualizer.h"
struct _SysprofCallgraphAid
{
SysprofAid parent_instance;
};
typedef struct
{
SysprofCaptureCursor *cursor;
SysprofDisplay *display;
guint has_samples : 1;
} Present;
G_DEFINE_TYPE (SysprofCallgraphAid, sysprof_callgraph_aid, SYSPROF_TYPE_AID)
static void
present_free (gpointer data)
{
Present *p = data;
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
g_clear_object (&p->display);
g_slice_free (Present, p);
}
static void
on_group_activated_cb (SysprofVisualizerGroup *group,
SysprofPage *page)
{
SysprofDisplay *display;
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
g_assert (SYSPROF_IS_PAGE (page));
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
sysprof_display_set_visible_page (display, page);
}
/**
* sysprof_callgraph_aid_new:
*
@ -82,12 +114,157 @@ sysprof_callgraph_aid_prepare (SysprofAid *self,
#endif
}
static gboolean
discover_samples_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
Present *p = user_data;
g_assert (frame != NULL);
g_assert (p != NULL);
if (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE)
{
p->has_samples = TRUE;
return FALSE;
}
return TRUE;
}
static void
sysprof_callgraph_aid_present_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
Present *p = task_data;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_CALLGRAPH_AID (source_object));
g_assert (p != NULL);
g_assert (p->cursor != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
/* If we find a sample frame, then we should enable the callgraph
* and stack visualizers.
*/
sysprof_capture_cursor_foreach (p->cursor, discover_samples_cb, p);
g_task_return_boolean (task, TRUE);
}
static void
sysprof_callgraph_aid_present_async (SysprofAid *aid,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_SAMPLE };
g_autoptr(SysprofCaptureCondition) condition = NULL;
g_autoptr(SysprofCaptureCursor) cursor = NULL;
g_autoptr(GTask) task = NULL;
Present present;
g_assert (SYSPROF_IS_CALLGRAPH_AID (aid));
g_assert (reader != NULL);
g_assert (SYSPROF_IS_DISPLAY (display));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
condition = sysprof_capture_condition_new_where_type_in (1, types);
cursor = sysprof_capture_cursor_new (reader);
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
present.cursor = g_steal_pointer (&cursor);
present.display = g_object_ref (display);
task = g_task_new (aid, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_callgraph_aid_present_async);
g_task_set_task_data (task,
g_slice_dup (Present, &present),
present_free);
g_task_run_in_thread (task, sysprof_callgraph_aid_present_worker);
}
static gboolean
sysprof_callgraph_aid_present_finish (SysprofAid *aid,
GAsyncResult *result,
GError **error)
{
Present *p;
g_assert (SYSPROF_IS_CALLGRAPH_AID (aid));
g_assert (G_IS_TASK (result));
p = g_task_get_task_data (G_TASK (result));
if (p->has_samples)
{
SysprofVisualizerGroup *group;
SysprofVisualizer *depth;
SysprofPage *page;
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
"can-focus", TRUE,
"has-page", TRUE,
"priority", -500,
"title", _("Stack Traces"),
"visible", TRUE,
NULL);
depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_COMBINED);
g_object_set (depth,
"title", _("Stack Traces"),
"height-request", 35,
"visible", TRUE,
NULL);
sysprof_visualizer_group_insert (group, depth, 0, FALSE);
depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY);
g_object_set (depth,
"title", _("Stack Traces (In Kernel)"),
"height-request", 35,
"visible", FALSE,
NULL);
sysprof_visualizer_group_insert (group, depth, 1, TRUE);
depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_USER_ONLY);
g_object_set (depth,
"title", _("Stack Traces (In User)"),
"height-request", 35,
"visible", FALSE,
NULL);
sysprof_visualizer_group_insert (group, depth, 2, TRUE);
sysprof_display_add_group (p->display, group);
page = g_object_new (SYSPROF_TYPE_CALLGRAPH_PAGE,
"title", _("Callgraph"),
"vexpand", TRUE,
"visible", TRUE,
NULL);
sysprof_display_add_page (p->display, page);
sysprof_display_set_visible_page (p->display, page);
g_signal_connect_object (group,
"group-activated",
G_CALLBACK (on_group_activated_cb),
page,
0);
}
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
sysprof_callgraph_aid_class_init (SysprofCallgraphAidClass *klass)
{
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
aid_class->prepare = sysprof_callgraph_aid_prepare;
aid_class->present_async = sysprof_callgraph_aid_present_async;
aid_class->present_finish = sysprof_callgraph_aid_present_finish;
}
static void

View File

@ -26,10 +26,8 @@ G_BEGIN_DECLS
#define SYSPROF_TYPE_CALLGRAPH_AID (sysprof_callgraph_aid_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (SysprofCallgraphAid, sysprof_callgraph_aid, SYSPROF, CALLGRAPH_AID, SysprofAid)
SYSPROF_AVAILABLE_IN_ALL
SysprofAid *sysprof_callgraph_aid_new (void);
G_END_DECLS

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
/* sysprof-callgraph-page.h
*
* Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
#include <sysprof.h>
#include "sysprof-page.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_CALLGRAPH_PAGE (sysprof_callgraph_page_get_type())
G_DECLARE_DERIVABLE_TYPE (SysprofCallgraphPage, sysprof_callgraph_page, SYSPROF, CALLGRAPH_PAGE, SysprofPage)
struct _SysprofCallgraphPageClass
{
SysprofPageClass parent_class;
void (*go_previous) (SysprofCallgraphPage *self);
/*< private >*/
gpointer _reserved[16];
};
GtkWidget *sysprof_callgraph_page_new (void);
SysprofCallgraphProfile *sysprof_callgraph_page_get_profile (SysprofCallgraphPage *self);
void sysprof_callgraph_page_set_profile (SysprofCallgraphPage *self,
SysprofCallgraphProfile *profile);
gchar *sysprof_callgraph_page_screenshot (SysprofCallgraphPage *self);
guint sysprof_callgraph_page_get_n_functions (SysprofCallgraphPage *self);
G_END_DECLS

View File

@ -0,0 +1,235 @@
<interface>
<template class="SysprofCallgraphPage" parent="SysprofPage">
<child>
<object class="GtkStack" id="stack">
<property name="visible">true</property>
<child>
<object class="GtkPaned">
<property name="orientation">horizontal</property>
<property name="position">450</property>
<property name="visible">true</property>
<child>
<object class="GtkPaned">
<property name="orientation">vertical</property>
<property name="visible">true</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">true</property>
<child>
<object class="GtkTreeView" id="functions_view">
<property name="fixed-height-mode">true</property>
<property name="visible">true</property>
<child>
<object class="GtkTreeViewColumn" id="function_name_column">
<property name="expand">true</property>
<property name="sizing">fixed</property>
<property name="sort-column-id">0</property>
<property name="title" translatable="yes">Functions</property>
<child>
<object class="GtkCellRendererText">
<property name="ellipsize">middle</property>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="function_self_column">
<property name="expand">false</property>
<property name="sizing">fixed</property>
<property name="sort-column-id">1</property>
<property name="title" translatable="yes">Self</property>
<child>
<object class="SysprofCellRendererPercent">
<property name="width">65</property>
</object>
<attributes>
<attribute name="percent">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="function_total_column">
<property name="expand">false</property>
<property name="sizing">fixed</property>
<property name="sort-column-id">2</property>
<property name="title" translatable="yes">Total</property>
<child>
<object class="SysprofCellRendererPercent">
<property name="width">65</property>
</object>
<attributes>
<attribute name="percent">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="resize">true</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">true</property>
<child>
<object class="GtkTreeView" id="callers_view">
<property name="visible">true</property>
<child>
<object class="GtkTreeViewColumn" id="callers_name_column">
<property name="expand">true</property>
<property name="sizing">fixed</property>
<property name="sort-column-id">0</property>
<property name="title" translatable="yes">Callers</property>
<child>
<object class="GtkCellRendererText">
<property name="ellipsize">middle</property>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="callers_self_column">
<property name="expand">false</property>
<property name="sizing">fixed</property>
<property name="sort-column-id">1</property>
<property name="title" translatable="yes">Self</property>
<child>
<object class="SysprofCellRendererPercent">
<property name="width">65</property>
</object>
<attributes>
<attribute name="percent">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="callers_total_column">
<property name="expand">false</property>
<property name="sizing">fixed</property>
<property name="sort-column-id">2</property>
<property name="title" translatable="yes">Total</property>
<child>
<object class="SysprofCellRendererPercent">
<property name="width">65</property>
</object>
<attributes>
<attribute name="percent">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="resize">true</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">true</property>
<child>
<object class="GtkTreeView" id="descendants_view">
<property name="visible">true</property>
<child>
<object class="GtkTreeViewColumn" id="descendants_name_column">
<property name="expand">true</property>
<property name="sizing">autosize</property>
<property name="sort-column-id">0</property>
<property name="title" translatable="yes">Descendants</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="descendants_self_column">
<property name="expand">false</property>
<property name="sizing">fixed</property>
<property name="sort-column-id">1</property>
<property name="title" translatable="yes">Self</property>
<child>
<object class="SysprofCellRendererPercent">
<property name="width">65</property>
</object>
<attributes>
<attribute name="percent">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="descendants_total_column">
<property name="expand">false</property>
<property name="sizing">fixed</property>
<property name="sort-column-id">2</property>
<property name="title" translatable="yes">Total</property>
<child>
<object class="SysprofCellRendererPercent">
<property name="width">65</property>
</object>
<attributes>
<attribute name="percent">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="function_hits_column">
<property name="expand">false</property>
<property name="sizing">fixed</property>
<property name="title" translatable="yes">Hits</property>
<child>
<object class="GtkCellRendererText">
<property name="xalign">1.0</property>
</object>
<attributes>
<attribute name="text">4</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">callgraph</property>
</packing>
</child>
<child>
<object class="DzlEmptyState">
<property name="icon-name">content-loading-symbolic</property>
<property name="title" translatable="yes">Generating Callgraph</property>
<property name="subtitle" translatable="yes">Sysprof is busy creating the selected callgraph.</property>
<property name="visible">true</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="DzlEmptyState">
<property name="icon-name">computer-fail-symbolic</property>
<property name="title" translatable="yes">Not Enough Samples</property>
<property name="subtitle" translatable="yes">More samples are necessary to display a callgraph.</property>
<property name="visible">false</property>
</object>
<packing>
<property name="name">empty-state</property>
</packing>
</child>
</object>
</child>
</template>
</interface>

View File

@ -20,10 +20,6 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include <sysprof.h>
@ -31,7 +27,6 @@ G_BEGIN_DECLS
#define SYSPROF_TYPE_CALLGRAPH_VIEW (sysprof_callgraph_view_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofCallgraphView, sysprof_callgraph_view, SYSPROF, CALLGRAPH_VIEW, GtkBin)
struct _SysprofCallgraphViewClass
@ -39,20 +34,13 @@ struct _SysprofCallgraphViewClass
GtkBinClass parent_class;
void (*go_previous) (SysprofCallgraphView *self);
gpointer padding[8];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_callgraph_view_new (void);
SYSPROF_AVAILABLE_IN_ALL
SysprofCallgraphProfile *sysprof_callgraph_view_get_profile (SysprofCallgraphView *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_callgraph_view_set_profile (SysprofCallgraphView *self,
SysprofCallgraphProfile *profile);
SYSPROF_AVAILABLE_IN_ALL
gchar *sysprof_callgraph_view_screenshot (SysprofCallgraphView *self);
SYSPROF_AVAILABLE_IN_ALL
guint sysprof_callgraph_view_get_n_functions (SysprofCallgraphView *self);
G_END_DECLS

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +0,0 @@
/* sysprof-capture-view.h
*
* Copyright 2019 Christian Hergert <unknown@domain.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
#include <sysprof-capture.h>
#include "sysprof-zoom-manager.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_CAPTURE_VIEW (sysprof_capture_view_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofCaptureView, sysprof_capture_view, SYSPROF, CAPTURE_VIEW, GtkBin)
struct _SysprofCaptureViewClass
{
GtkBinClass parent_class;
void (*load_async) (SysprofCaptureView *self,
SysprofCaptureReader *reader,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (*load_finish) (SysprofCaptureView *self,
GAsyncResult *result,
GError **error);
/*< private >*/
gpointer _reserved[32];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_capture_view_new (void);
SYSPROF_AVAILABLE_IN_ALL
SysprofZoomManager *sysprof_capture_view_get_zoom_manager (SysprofCaptureView *self);
SYSPROF_AVAILABLE_IN_ALL
SysprofCaptureReader *sysprof_capture_view_get_reader (SysprofCaptureView *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_capture_view_load_async (SysprofCaptureView *self,
SysprofCaptureReader *reader,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_capture_view_load_finish (SysprofCaptureView *self,
GAsyncResult *result,
GError **error);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_capture_view_get_busy (SysprofCaptureView *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_capture_view_fit_to_width (SysprofCaptureView *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_capture_view_get_can_replay (SysprofCaptureView *self);
G_END_DECLS

View File

@ -1,187 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SysprofCaptureView" parent="GtkBin">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="visible">true</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="visible">true</property>
<child>
<object class="GtkBox">
<property name="margin-start">12</property>
<property name="margin-end">6</property>
<property name="orientation">horizontal</property>
<property name="valign">center</property>
<property name="visible">true</property>
<child>
<object class="GtkButton">
<property name="action-name">zoom.zoom-out</property>
<property name="focus-on-click">false</property>
<property name="visible">true</property>
<property name="tooltip-text" translatable="yes">Zoom Out</property>
<style>
<class name="flat"/>
<class name="image-button"/>
</style>
<child>
<object class="GtkImage">
<property name="icon-name">zoom-out-symbolic</property>
<property name="visible">true</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="action-name">capture-view.fit-zoom</property>
<property name="focus-on-click">false</property>
<property name="tooltip-text" translatable="yes">Resize to Fit</property>
<property name="visible">true</property>
<style>
<class name="flat"/>
<class name="image-button"/>
</style>
<child>
<object class="GtkImage">
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="icon-name">zoom-fit-best-symbolic</property>
<property name="visible">true</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="action-name">zoom.zoom-in</property>
<property name="focus-on-click">false</property>
<property name="tooltip-text" translatable="yes">Zoom In</property>
<property name="visible">true</property>
<style>
<class name="flat"/>
<class name="image-button"/>
</style>
<child>
<object class="GtkImage">
<property name="icon-name">zoom-in-symbolic</property>
<property name="visible">true</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="pack-type">end</property>
</packing>
</child>
<child type="center">
<object class="GtkStackSwitcher" id="stack_switcher">
<property name="stack">stack</property>
<property name="halign">center</property>
<property name="visible">true</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
</object>
</child>
</object>
</child>
<child>
<object class="DzlMultiPaned">
<property name="visible">true</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="visible">true</property>
<child>
<object class="GtkSeparator">
<property name="orientation">horizontal</property>
<property name="visible">true</property>
</object>
</child>
<child>
<object class="SysprofVisualizerView" id="visualizer_view">
<property name="zoom-manager">zoom_manager</property>
<property name="visible">true</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">true</property>
</object>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="homogeneous">true</property>
<property name="visible">true</property>
<property name="vexpand">true</property>
<child>
<object class="SysprofCallgraphView" id="callgraph_view">
<property name="visible">true</property>
</object>
<packing>
<!-- translators: the _ is used to denote the accelerator key -->
<property name="title" translatable="yes">_Callgraph</property>
<property name="name">callgraph</property>
</packing>
</child>
<child>
<object class="SysprofMarksView" id="marks_view">
<property name="kind">marks</property>
<property name="zoom-manager">zoom_manager</property>
<property name="visible">true</property>
</object>
<packing>
<!-- translators: the _ is used to denote the accelerator key -->
<property name="title" translatable="yes">_Timings</property>
<property name="name">timings</property>
</packing>
</child>
<child>
<object class="SysprofMarksView" id="counters_view">
<property name="kind">counters</property>
<property name="zoom-manager">zoom_manager</property>
<property name="visible">true</property>
</object>
<packing>
<!-- translators: the _ is used to denote the accelerator key -->
<property name="title" translatable="yes">C_ounters</property>
<property name="name">counters</property>
</packing>
</child>
<child>
<object class="SysprofLogsView" id="logs_view">
<property name="visible">true</property>
</object>
<packing>
<!-- translators: the _ is used to denote the accelerator key -->
<property name="title" translatable="yes">_Logs</property>
<property name="name">logs</property>
</packing>
</child>
<child>
<object class="SysprofDetailsView" id="details_view">
<property name="visible">true</property>
</object>
<packing>
<!-- translators: the _ is used to denote the accelerator key -->
<property name="title" translatable="yes">_Details</property>
<property name="name">details</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
<object class="SysprofZoomManager" id="zoom_manager"/>
<object class="GtkAdjustment" id="time_adj">
<property name="step-increment">20</property>
</object>
</interface>

View File

@ -110,7 +110,7 @@ sysprof_cell_renderer_duration_render (GtkCellRenderer *renderer,
if (r.width > 3)
{
_sysprof_rounded_rectangle (cr, &r, 2, 2);
dzl_cairo_rounded_rectangle (cr, &r, 2, 2);
cairo_fill (cr);
}
else if (r.width > 1)

View File

@ -18,6 +18,8 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-cell-renderer-percent"
#include "config.h"
#include <glib/gi18n.h>

View File

@ -20,14 +20,8 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include "sysprof-version-macros.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_CELL_RENDERER_PERCENT (sysprof_cell_renderer_percent_get_type())
@ -50,16 +44,13 @@ struct _SysprofCellRendererPercentClass
{
GtkCellRendererProgressClass parent_class;
gpointer padding[4];
/*< private >*/
gpointer _reserved[4];
};
SYSPROF_AVAILABLE_IN_ALL
GType sysprof_cell_renderer_percent_get_type (void);
SYSPROF_AVAILABLE_IN_ALL
GtkCellRenderer *sysprof_cell_renderer_percent_new (void);
SYSPROF_AVAILABLE_IN_ALL
gdouble sysprof_cell_renderer_percent_get_percent (SysprofCellRendererPercent *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_cell_renderer_percent_set_percent (SysprofCellRendererPercent *self,
gdouble percent);

View File

@ -27,30 +27,47 @@
G_DEFINE_BOXED_TYPE (SysprofColorCycle, sysprof_color_cycle, sysprof_color_cycle_ref, sysprof_color_cycle_unref)
static const gchar *default_colors[] = {
"#73d216",
"#f57900",
"#3465a4",
"#ef2929",
"#75507b",
"#ce5c00",
"#c17d11",
"#cc0000",
"#edd400",
"#555753",
"#4e9a06",
"#204a87",
"#5c3566",
"#a40000",
"#c4a000",
"#8f5902",
"#2e3436",
"#8ae234",
"#729fcf",
"#ad7fa8",
"#fce94f",
"#fcaf3e",
"#e9b96e",
"#888a85",
"#1a5fb4", /* Blue 5 */
"#26a269", /* Green 5 */
"#e5a50a", /* Yellow 5 */
"#c64600", /* Orange 5 */
"#a51d2d", /* Red 5 */
"#613583", /* Purple 5 */
"#63452c", /* Brown 5 */
"#1c71d8", /* Blue 4 */
"#2ec27e", /* Green 4 */
"#f5c211", /* Yellow 4 */
"#e66100", /* Orange 4 */
"#c01c28", /* Red 4 */
"#813d9c", /* Purple 4 */
"#865e3c", /* Brown 4 */
"#3584e4", /* Blue 3 */
"#33d17a", /* Green 3 */
"#f6d32d", /* Yellow 3 */
"#ff7800", /* Orange 3 */
"#e01b24", /* Red 3 */
"#9141ac", /* Purple 3 */
"#986a44", /* Brown 3 */
"#62a0ea", /* Blue 2 */
"#57e389", /* Green 2 */
"#f8e45c", /* Yellow 2 */
"#ffa348", /* Orange 2 */
"#ed333b", /* Red 2 */
"#c061cb", /* Purple 2 */
"#b5835a", /* Brown 2 */
"#99c1f1", /* Blue 1 */
"#8ff0a4", /* Green 1 */
"#f9f06b", /* Yellow 1 */
"#ffbe6f", /* Orange 1 */
"#f66151", /* Red 1 */
"#dc8add", /* Purple 1 */
"#cdab8f", /* Brown 1 */
NULL
};

View File

@ -20,32 +20,22 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include "sysprof-version-macros.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_COLOR_CYCLE (sysprof_color_cycle_get_type())
typedef struct _SysprofColorCycle SysprofColorCycle;
SYSPROF_AVAILABLE_IN_ALL
GType sysprof_color_cycle_get_type (void);
SYSPROF_AVAILABLE_IN_ALL
SysprofColorCycle *sysprof_color_cycle_ref (SysprofColorCycle *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_color_cycle_unref (SysprofColorCycle *self);
SYSPROF_AVAILABLE_IN_ALL
SysprofColorCycle *sysprof_color_cycle_new (void);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_color_cycle_reset (SysprofColorCycle *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_color_cycle_next (SysprofColorCycle *self,
GdkRGBA *rgba);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofColorCycle, sysprof_color_cycle_unref)
G_END_DECLS

View File

@ -0,0 +1,248 @@
/* sysprof-counters-aid.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-counters-aid"
#include "config.h"
#include <glib/gi18n.h>
#include "sysprof-color-cycle.h"
#include "sysprof-counters-aid.h"
#include "sysprof-line-visualizer.h"
#include "sysprof-marks-page.h"
#include "sysprof-time-visualizer.h"
struct _SysprofCountersAid
{
SysprofAid parent_instance;
};
typedef struct
{
SysprofCaptureCursor *cursor;
SysprofDisplay *display;
} Present;
G_DEFINE_TYPE (SysprofCountersAid, sysprof_counters_aid, SYSPROF_TYPE_AID)
static void
present_free (gpointer data)
{
Present *p = data;
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
g_clear_object (&p->display);
g_slice_free (Present, p);
}
static void
on_group_activated_cb (SysprofVisualizerGroup *group,
SysprofPage *page)
{
SysprofDisplay *display;
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
g_assert (SYSPROF_IS_PAGE (page));
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
sysprof_display_set_visible_page (display, page);
}
/**
* sysprof_counters_aid_new:
*
* Create a new #SysprofCountersAid.
*
* Returns: (transfer full): a newly created #SysprofCountersAid
*
* Since: 3.34
*/
SysprofAid *
sysprof_counters_aid_new (void)
{
return g_object_new (SYSPROF_TYPE_COUNTERS_AID, NULL);
}
static void
sysprof_counters_aid_prepare (SysprofAid *self,
SysprofProfiler *profiler)
{
}
static gboolean
collect_counters (const SysprofCaptureFrame *frame,
gpointer user_data)
{
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
GArray *counters = user_data;
g_assert (frame != NULL);
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
g_assert (counters != NULL);
if (def->n_counters > 0)
g_array_append_vals (counters, def->counters, def->n_counters);
return TRUE;
}
static void
sysprof_counters_aid_present_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
Present *present = task_data;
g_autoptr(GArray) counters = NULL;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_COUNTERS_AID (source_object));
g_assert (present != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
sysprof_capture_cursor_foreach (present->cursor, collect_counters, counters);
g_task_return_pointer (task,
g_steal_pointer (&counters),
(GDestroyNotify) g_array_unref);
}
static void
sysprof_counters_aid_present_async (SysprofAid *aid,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
g_autoptr(SysprofCaptureCondition) condition = NULL;
g_autoptr(SysprofCaptureCursor) cursor = NULL;
g_autoptr(GTask) task = NULL;
Present present;
g_assert (SYSPROF_IS_COUNTERS_AID (aid));
g_assert (reader != NULL);
g_assert (SYSPROF_IS_DISPLAY (display));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
condition = sysprof_capture_condition_new_where_type_in (1, types);
cursor = sysprof_capture_cursor_new (reader);
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
present.cursor = g_steal_pointer (&cursor);
present.display = g_object_ref (display);
task = g_task_new (aid, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_counters_aid_present_async);
g_task_set_task_data (task,
g_slice_dup (Present, &present),
present_free);
g_task_run_in_thread (task, sysprof_counters_aid_present_worker);
}
static gboolean
sysprof_counters_aid_present_finish (SysprofAid *aid,
GAsyncResult *result,
GError **error)
{
g_autoptr(GArray) counters = NULL;
Present *present;
g_assert (SYSPROF_IS_AID (aid));
g_assert (G_IS_TASK (result));
present = g_task_get_task_data (G_TASK (result));
if ((counters = g_task_propagate_pointer (G_TASK (result), error)) && counters->len > 0)
{
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
SysprofVisualizerGroup *group;
SysprofVisualizer *combined;
GtkWidget *page;
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
"can-focus", TRUE,
"has-page", TRUE,
"title", _("Counters"),
"visible", TRUE,
NULL);
combined = g_object_new (SYSPROF_TYPE_TIME_VISUALIZER,
"title", _("Counters"),
"height-request", 35,
"visible", TRUE,
NULL);
sysprof_visualizer_group_insert (group, combined, -1, TRUE);
for (guint i = 0; i < counters->len; i++)
{
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
g_autofree gchar *title = g_strdup_printf ("%s — %s", ctr->category, ctr->name);
GtkWidget *row;
GdkRGBA rgba;
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
"title", title,
"height-request", 35,
"visible", FALSE,
NULL);
sysprof_color_cycle_next (cycle, &rgba);
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
rgba.alpha = .5;
sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
sysprof_time_visualizer_add_counter (SYSPROF_TIME_VISUALIZER (combined), ctr->id, &rgba);
sysprof_visualizer_group_insert (group, SYSPROF_VISUALIZER (row), -1, TRUE);
}
sysprof_display_add_group (present->display, group);
page = sysprof_marks_page_new (sysprof_display_get_zoom_manager (present->display),
SYSPROF_MARKS_MODEL_COUNTERS);
gtk_widget_show (page);
g_signal_connect_object (group,
"group-activated",
G_CALLBACK (on_group_activated_cb),
page,
0);
sysprof_display_add_page (present->display, SYSPROF_PAGE (page));
}
return counters != NULL;
}
static void
sysprof_counters_aid_class_init (SysprofCountersAidClass *klass)
{
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
aid_class->prepare = sysprof_counters_aid_prepare;
aid_class->present_async = sysprof_counters_aid_present_async;
aid_class->present_finish = sysprof_counters_aid_present_finish;
}
static void
sysprof_counters_aid_init (SysprofCountersAid *self)
{
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Battery"));
sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof3-symbolic");
}

View File

@ -0,0 +1,33 @@
/* sysprof-counters-aid.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "sysprof-aid.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_COUNTERS_AID (sysprof_counters_aid_get_type())
G_DECLARE_FINAL_TYPE (SysprofCountersAid, sysprof_counters_aid, SYSPROF, COUNTERS_AID, SysprofAid)
SysprofAid *sysprof_counters_aid_new (void);
G_END_DECLS

View File

@ -24,15 +24,33 @@
#include <glib/gi18n.h>
#include "sysprof-color-cycle.h"
#include "sysprof-cpu-aid.h"
#include "sysprof-line-visualizer.h"
struct _SysprofCpuAid
{
SysprofAid parent_instance;
};
typedef struct
{
SysprofCaptureCursor *cursor;
SysprofDisplay *display;
} Present;
G_DEFINE_TYPE (SysprofCpuAid, sysprof_cpu_aid, SYSPROF_TYPE_AID)
static void
present_free (gpointer data)
{
Present *p = data;
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
g_clear_object (&p->display);
g_slice_free (Present, p);
}
/**
* sysprof_cpu_aid_new:
*
@ -63,12 +81,243 @@ sysprof_cpu_aid_prepare (SysprofAid *self,
#endif
}
static gboolean
collect_cpu_counters (const SysprofCaptureFrame *frame,
gpointer user_data)
{
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
GArray *counters = user_data;
g_assert (frame != NULL);
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
g_assert (counters != NULL);
for (guint i = 0; i < def->n_counters; i++)
{
const SysprofCaptureCounter *counter = &def->counters[i];
if (g_strcmp0 (counter->category, "CPU Percent") == 0 ||
g_strcmp0 (counter->category, "CPU Frequency") == 0)
g_array_append_vals (counters, counter, 1);
}
return TRUE;
}
static void
sysprof_cpu_aid_present_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
Present *present = task_data;
g_autoptr(GArray) counters = NULL;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_CPU_AID (source_object));
g_assert (present != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
sysprof_capture_cursor_foreach (present->cursor, collect_cpu_counters, counters);
g_task_return_pointer (task,
g_steal_pointer (&counters),
(GDestroyNotify) g_array_unref);
}
static void
sysprof_cpu_aid_present_async (SysprofAid *aid,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
g_autoptr(SysprofCaptureCondition) condition = NULL;
g_autoptr(SysprofCaptureCursor) cursor = NULL;
g_autoptr(GTask) task = NULL;
Present present;
g_assert (SYSPROF_IS_CPU_AID (aid));
g_assert (reader != NULL);
g_assert (SYSPROF_IS_DISPLAY (display));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
condition = sysprof_capture_condition_new_where_type_in (1, types);
cursor = sysprof_capture_cursor_new (reader);
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
present.cursor = g_steal_pointer (&cursor);
present.display = g_object_ref (display);
task = g_task_new (aid, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_cpu_aid_present_async);
g_task_set_task_data (task,
g_slice_dup (Present, &present),
present_free);
g_task_run_in_thread (task, sysprof_cpu_aid_present_worker);
}
static gboolean
sysprof_cpu_aid_present_finish (SysprofAid *aid,
GAsyncResult *result,
GError **error)
{
g_autoptr(GArray) counters = NULL;
Present *present;
g_assert (SYSPROF_IS_AID (aid));
g_assert (G_IS_TASK (result));
present = g_task_get_task_data (G_TASK (result));
if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
{
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
g_autoptr(SysprofColorCycle) freq_cycle = sysprof_color_cycle_new ();
SysprofVisualizerGroup *usage;
SysprofVisualizerGroup *freq;
SysprofVisualizer *freq_row = NULL;
SysprofVisualizer *over_row = NULL;
gboolean found_combined = FALSE;
gboolean has_usage = FALSE;
gboolean has_freq = FALSE;
usage = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
"can-focus", TRUE,
"priority", -1000,
"title", _("CPU Usage"),
"visible", TRUE,
NULL);
freq = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
"can-focus", TRUE,
"priority", -999,
"title", _("CPU Frequency"),
"visible", TRUE,
NULL);
freq_row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
"title", _("CPU Frequency (All)"),
"height-request", 35,
"visible", TRUE,
"y-lower", 0.0,
"y-upper", 100.0,
NULL);
gtk_container_add (GTK_CONTAINER (freq), GTK_WIDGET (freq_row));
over_row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
"title", _("CPU Usage (All)"),
"height-request", 35,
"visible", TRUE,
"y-lower", 0.0,
"y-upper", 100.0,
NULL);
for (guint i = 0; i < counters->len; i++)
{
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
if (g_strcmp0 (ctr->category, "CPU Percent") == 0)
{
if (strstr (ctr->name, "Combined") != NULL)
{
GtkWidget *row;
GdkRGBA rgba;
found_combined = TRUE;
gdk_rgba_parse (&rgba, "#1a5fb4");
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
/* Translators: CPU is the processor. */
"title", _("CPU Usage (All)"),
"height-request", 35,
"visible", TRUE,
"y-lower", 0.0,
"y-upper", 100.0,
NULL);
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
rgba.alpha = 0.5;
sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), 0, FALSE);
has_usage = TRUE;
}
else if (g_str_has_prefix (ctr->name, "Total CPU "))
{
GtkWidget *row;
GdkRGBA rgba;
sysprof_color_cycle_next (cycle, &rgba);
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
"title", ctr->name,
"height-request", 35,
"visible", FALSE,
"y-lower", 0.0,
"y-upper", 100.0,
NULL);
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (over_row), ctr->id, &rgba);
rgba.alpha = 0.5;
sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), -1, TRUE);
has_usage = TRUE;
}
}
else if (g_strcmp0 (ctr->category, "CPU Frequency") == 0)
{
if (g_str_has_prefix (ctr->name, "CPU "))
{
g_autofree gchar *title = g_strdup_printf ("%s Frequency", ctr->name);
GtkWidget *row;
GdkRGBA rgba;
sysprof_color_cycle_next (freq_cycle, &rgba);
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (freq_row), ctr->id, &rgba);
sysprof_line_visualizer_set_dash (SYSPROF_LINE_VISUALIZER (freq_row), ctr->id, TRUE);
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
"title", title,
"height-request", 35,
"visible", FALSE,
"y-lower", 0.0,
"y-upper", 100.0,
NULL);
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
sysprof_line_visualizer_set_dash (SYSPROF_LINE_VISUALIZER (row), ctr->id, TRUE);
sysprof_visualizer_group_insert (freq, SYSPROF_VISUALIZER (row), -1, TRUE);
has_freq = TRUE;
}
}
}
if (has_usage && !found_combined)
sysprof_visualizer_group_insert (usage, over_row, 0, FALSE);
else
gtk_widget_destroy (GTK_WIDGET (over_row));
if (has_usage)
sysprof_display_add_group (present->display, usage);
else
gtk_widget_destroy (GTK_WIDGET (usage));
if (has_freq)
sysprof_display_add_group (present->display, freq);
else
gtk_widget_destroy (GTK_WIDGET (freq));
}
return counters != NULL;
}
static void
sysprof_cpu_aid_class_init (SysprofCpuAidClass *klass)
{
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
aid_class->prepare = sysprof_cpu_aid_prepare;
aid_class->present_async = sysprof_cpu_aid_present_async;
aid_class->present_finish = sysprof_cpu_aid_present_finish;
}
static void

View File

@ -26,10 +26,8 @@ G_BEGIN_DECLS
#define SYSPROF_TYPE_CPU_AID (sysprof_cpu_aid_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (SysprofCpuAid, sysprof_cpu_aid, SYSPROF, CPU_AID, SysprofAid)
SYSPROF_AVAILABLE_IN_ALL
SysprofAid *sysprof_cpu_aid_new (void);
G_END_DECLS

View File

@ -1,239 +0,0 @@
/* sysprof-cpu-visualizer-row.c
*
* Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-cpu-visualizer-row"
#include "config.h"
#include <sysprof.h>
#include "sysprof-color-cycle.h"
#include "sysprof-cpu-visualizer-row.h"
struct _SysprofCpuVisualizerRow
{
SysprofLineVisualizerRow parent_instance;
SysprofColorCycle *colors;
gchar *category;
guint use_dash : 1;
};
enum {
PROP_0,
PROP_CATEGORY,
PROP_USE_DASH,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
G_DEFINE_TYPE (SysprofCpuVisualizerRow, sysprof_cpu_visualizer_row, SYSPROF_TYPE_LINE_VISUALIZER_ROW)
static gboolean
sysprof_cpu_visualizer_counter_found (const SysprofCaptureFrame *frame,
gpointer user_data)
{
const SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
struct {
SysprofCpuVisualizerRow *self;
GArray *counters;
} *state = user_data;
gboolean found = FALSE;
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
g_assert (state != NULL);
/*
* In practice, all the CPU counters are defined at once, so we can avoid
* walking the rest of the capture by returning after we find our CTRDEF.
*/
for (guint i = 0; i < def->n_counters; i++)
{
if (strcmp (def->counters[i].category, state->self->category) == 0 &&
strstr (def->counters[i].name, "(Combined)") == NULL)
{
guint id = def->counters[i].id;
g_array_append_val (state->counters, id);
found = TRUE;
}
}
return !found;
}
static void
sysprof_cpu_visualizer_row_discover_counters (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *canellable)
{
const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
SysprofCaptureReader *reader = task_data;
g_autoptr(SysprofCaptureCursor) cursor = NULL;
g_autoptr(GArray) counters = NULL;
struct {
SysprofCpuVisualizerRow *self;
GArray *counters;
} state;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_CPU_VISUALIZER_ROW (source_object));
g_assert (reader != NULL);
counters = g_array_new (FALSE, FALSE, sizeof (guint));
state.self = source_object;
state.counters = counters;
cursor = sysprof_capture_cursor_new (reader);
sysprof_capture_cursor_add_condition (cursor, sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types));
sysprof_capture_cursor_foreach (cursor, sysprof_cpu_visualizer_counter_found, &state);
g_task_return_pointer (task, g_steal_pointer (&counters), (GDestroyNotify)g_array_unref);
}
static void
complete_counters (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofCpuVisualizerRow *self = (SysprofCpuVisualizerRow *)object;
g_autoptr(GArray) counters = NULL;
g_assert (SYSPROF_IS_CPU_VISUALIZER_ROW (self));
g_assert (G_IS_TASK (result));
counters = g_task_propagate_pointer (G_TASK (result), NULL);
if (counters != NULL)
{
for (guint i = 0; i < counters->len; i++)
{
guint counter_id = g_array_index (counters, guint, i);
GdkRGBA color;
sysprof_color_cycle_next (self->colors, &color);
sysprof_line_visualizer_row_add_counter (SYSPROF_LINE_VISUALIZER_ROW (self), counter_id, &color);
if (self->use_dash)
sysprof_line_visualizer_row_set_dash (SYSPROF_LINE_VISUALIZER_ROW (self), counter_id, TRUE);
}
}
/* Hide ourself if we failed to locate counters */
gtk_widget_set_visible (GTK_WIDGET (self), counters != NULL && counters->len > 0);
}
static void
sysprof_cpu_visualizer_row_set_reader (SysprofVisualizerRow *row,
SysprofCaptureReader *reader)
{
SysprofCpuVisualizerRow *self = (SysprofCpuVisualizerRow *)row;
g_autoptr(GTask) task = NULL;
g_assert (SYSPROF_IS_CPU_VISUALIZER_ROW (row));
sysprof_color_cycle_reset (self->colors);
sysprof_line_visualizer_row_clear (SYSPROF_LINE_VISUALIZER_ROW (row));
SYSPROF_VISUALIZER_ROW_CLASS (sysprof_cpu_visualizer_row_parent_class)->set_reader (row, reader);
if (reader != NULL)
{
task = g_task_new (self, NULL, complete_counters, NULL);
g_task_set_source_tag (task, sysprof_cpu_visualizer_row_set_reader);
g_task_set_task_data (task, sysprof_capture_reader_copy (reader),
(GDestroyNotify)sysprof_capture_reader_unref);
g_task_run_in_thread (task, sysprof_cpu_visualizer_row_discover_counters);
}
}
static void
sysprof_cpu_visualizer_row_finalize (GObject *object)
{
SysprofCpuVisualizerRow *self = (SysprofCpuVisualizerRow *)object;
g_clear_pointer (&self->colors, sysprof_color_cycle_unref);
g_clear_pointer (&self->category, g_free);
G_OBJECT_CLASS (sysprof_cpu_visualizer_row_parent_class)->finalize (object);
}
static void
sysprof_cpu_visualizer_row_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofCpuVisualizerRow *self = SYSPROF_CPU_VISUALIZER_ROW (object);
switch (prop_id)
{
case PROP_CATEGORY:
g_free (self->category);
self->category = g_value_dup_string (value);
break;
case PROP_USE_DASH:
self->use_dash = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_cpu_visualizer_row_class_init (SysprofCpuVisualizerRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
SysprofVisualizerRowClass *row_class = SYSPROF_VISUALIZER_ROW_CLASS (klass);
object_class->finalize = sysprof_cpu_visualizer_row_finalize;
object_class->set_property = sysprof_cpu_visualizer_row_set_property;
row_class->set_reader = sysprof_cpu_visualizer_row_set_reader;
properties [PROP_CATEGORY] =
g_param_spec_string ("category", NULL, NULL,
"CPU Percent",
(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
properties [PROP_USE_DASH] =
g_param_spec_boolean ("use-dash", NULL, NULL,
FALSE,
(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
sysprof_cpu_visualizer_row_init (SysprofCpuVisualizerRow *self)
{
self->category = g_strdup ("CPU Percent");
self->colors = sysprof_color_cycle_new ();
}
GtkWidget *
sysprof_cpu_visualizer_row_new (void)
{
return g_object_new (SYSPROF_TYPE_CPU_VISUALIZER_ROW, NULL);
}

View File

@ -1,357 +0,0 @@
/* sysprof-depth-visualizer-row.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-depth-visualizer-row"
#include "config.h"
#include <glib/gi18n.h>
#include "pointcache.h"
#include "sysprof-depth-visualizer-row.h"
struct _SysprofDepthVisualizerRow
{
SysprofVisualizerRow parent_instance;
SysprofCaptureReader *reader;
PointCache *points;
guint reload_source;
};
typedef struct
{
SysprofCaptureReader *reader;
PointCache *pc;
gint64 begin_time;
gint64 end_time;
gint64 duration;
guint max_n_addrs;
} State;
G_DEFINE_TYPE (SysprofDepthVisualizerRow, sysprof_depth_visualizer_row, SYSPROF_TYPE_VISUALIZER_ROW)
static void
state_free (State *st)
{
g_clear_pointer (&st->reader, sysprof_capture_reader_unref);
g_clear_pointer (&st->pc, point_cache_unref);
g_slice_free (State, st);
}
static gboolean
discover_max_n_addr (const SysprofCaptureFrame *frame,
gpointer user_data)
{
const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
State *st = user_data;
g_assert (frame != NULL);
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
g_assert (st != NULL);
st->max_n_addrs = MAX (st->max_n_addrs, sample->n_addrs);
return TRUE;
}
static gboolean
build_point_cache_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
State *st = user_data;
gdouble x, y;
g_assert (frame != NULL);
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
g_assert (st != NULL);
x = (frame->time - st->begin_time) / (gdouble)st->duration;
y = sample->n_addrs / (gdouble)st->max_n_addrs;
/* If this contains a context-switch (meaning we're going into the kernel
* to do some work, use a negative value for Y so that we know later on
* that we should draw it with a different color (after removing the negation
* on the value.
*
* We skip past the first index, which is always a context switch as it is
* our perf handler.
*/
for (guint i = 1; i < sample->n_addrs; i++)
{
SysprofAddressContext kind;
if (sysprof_address_is_context_switch (sample->addrs[i], &kind))
{
y = -y;
break;
}
}
point_cache_add_point_to_set (st->pc, 1, x, y);
return TRUE;
}
static void
sysprof_depth_visualizer_row_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_SAMPLE, };
g_autoptr(SysprofCaptureCursor) cursor = NULL;
SysprofCaptureCondition *condition;
State *st = task_data;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_DEPTH_VISUALIZER_ROW (source_object));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
if (st->duration != 0)
{
cursor = sysprof_capture_cursor_new (st->reader);
condition = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
sysprof_capture_cursor_foreach (cursor, discover_max_n_addr, st);
sysprof_capture_cursor_reset (cursor);
sysprof_capture_cursor_foreach (cursor, build_point_cache_cb, st);
}
g_task_return_pointer (task,
g_steal_pointer (&st->pc),
(GDestroyNotify) point_cache_unref);
}
static void
apply_point_cache_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofDepthVisualizerRow *self = (SysprofDepthVisualizerRow *)object;
PointCache *pc;
g_assert (SYSPROF_IS_DEPTH_VISUALIZER_ROW (self));
g_assert (G_IS_TASK (result));
if ((pc = g_task_propagate_pointer (G_TASK (result), NULL)))
{
g_clear_pointer (&self->points, point_cache_unref);
self->points = g_steal_pointer (&pc);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
static void
sysprof_depth_visualizer_row_reload (SysprofDepthVisualizerRow *self)
{
g_autoptr(GTask) task = NULL;
GtkAllocation alloc;
State *st;
g_assert (SYSPROF_IS_DEPTH_VISUALIZER_ROW (self));
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
st = g_slice_new0 (State);
st->reader = sysprof_capture_reader_ref (self->reader);
st->pc = point_cache_new ();
st->max_n_addrs = 0;
st->begin_time = sysprof_capture_reader_get_start_time (self->reader);
st->end_time = sysprof_capture_reader_get_end_time (self->reader);
st->duration = st->end_time - st->begin_time;
point_cache_add_set (st->pc, 1);
task = g_task_new (self, NULL, apply_point_cache_cb, NULL);
g_task_set_source_tag (task, sysprof_depth_visualizer_row_reload);
g_task_set_task_data (task, st, (GDestroyNotify) state_free);
g_task_run_in_thread (task, sysprof_depth_visualizer_row_worker);
}
static void
sysprof_depth_visualizer_row_set_reader (SysprofVisualizerRow *row,
SysprofCaptureReader *reader)
{
SysprofDepthVisualizerRow *self = (SysprofDepthVisualizerRow *)row;
g_assert (SYSPROF_IS_DEPTH_VISUALIZER_ROW (self));
if (self->reader != reader)
{
if (self->reader != NULL)
{
sysprof_capture_reader_unref (self->reader);
self->reader = NULL;
}
if (reader != NULL)
{
self->reader = sysprof_capture_reader_ref (reader);
sysprof_depth_visualizer_row_reload (self);
}
}
}
static gboolean
sysprof_depth_visualizer_row_draw (GtkWidget *widget,
cairo_t *cr)
{
SysprofDepthVisualizerRow *self = (SysprofDepthVisualizerRow *)widget;
GtkStyleContext *style_context;
GtkAllocation alloc;
const Point *points;
guint n_points = 0;
GdkRGBA user;
GdkRGBA system;
g_assert (SYSPROF_IS_DEPTH_VISUALIZER_ROW (self));
g_assert (cr != NULL);
GTK_WIDGET_CLASS (sysprof_depth_visualizer_row_parent_class)->draw (widget, cr);
if (self->points == NULL)
return GDK_EVENT_PROPAGATE;
style_context = gtk_widget_get_style_context (widget);
gtk_style_context_get_color (style_context,
gtk_style_context_get_state (style_context),
&user);
gdk_rgba_parse (&system, "#ef2929");
gtk_widget_get_allocation (widget, &alloc);
if ((points = point_cache_get_points (self->points, 1, &n_points)))
{
g_autofree SysprofVisualizerRowAbsolutePoint *out_points = NULL;
gint last = 1;
out_points = g_new (SysprofVisualizerRowAbsolutePoint, n_points);
sysprof_visualizer_row_translate_points (SYSPROF_VISUALIZER_ROW (widget),
(const SysprofVisualizerRowRelativePoint *)points,
n_points, out_points, n_points);
cairo_set_line_width (cr, 1.0);
gdk_cairo_set_source_rgba (cr, &user);
if (n_points > 0 && points[0].y < 0)
gdk_cairo_set_source_rgba (cr, &system);
for (guint i = 0; i < n_points; i++)
{
if ((points[i].y < 0 && last > 0) ||
(points[i].y > 0 && last < 0))
cairo_stroke (cr);
last = points[i].y > 0 ? 1 : -1;
cairo_move_to (cr, .5 + alloc.x + (guint)out_points[i].x, alloc.height);
cairo_line_to (cr, .5 + alloc.x + out_points[i].x, out_points[i].y);
if (last > 0)
gdk_cairo_set_source_rgba (cr, &user);
else
gdk_cairo_set_source_rgba (cr, &system);
}
cairo_stroke (cr);
}
return GDK_EVENT_PROPAGATE;
}
static gboolean
sysprof_depth_visualizer_row_do_reload (gpointer data)
{
SysprofDepthVisualizerRow *self = data;
self->reload_source = 0;
sysprof_depth_visualizer_row_reload (self);
return G_SOURCE_REMOVE;
}
static void
sysprof_depth_visualizer_row_queue_reload (SysprofDepthVisualizerRow *self)
{
g_assert (SYSPROF_IS_DEPTH_VISUALIZER_ROW (self));
if (self->reload_source)
g_source_remove (self->reload_source);
self->reload_source = gdk_threads_add_idle (sysprof_depth_visualizer_row_do_reload, self);
}
static void
sysprof_depth_visualizer_row_size_allocate (GtkWidget *widget,
GtkAllocation *alloc)
{
GTK_WIDGET_CLASS (sysprof_depth_visualizer_row_parent_class)->size_allocate (widget, alloc);
sysprof_depth_visualizer_row_queue_reload (SYSPROF_DEPTH_VISUALIZER_ROW (widget));
}
static void
sysprof_depth_visualizer_row_finalize (GObject *object)
{
SysprofDepthVisualizerRow *self = (SysprofDepthVisualizerRow *)object;
g_clear_pointer (&self->reader, sysprof_capture_reader_unref);
if (self->reload_source)
{
g_source_remove (self->reload_source);
self->reload_source = 0;
}
G_OBJECT_CLASS (sysprof_depth_visualizer_row_parent_class)->finalize (object);
}
static void
sysprof_depth_visualizer_row_class_init (SysprofDepthVisualizerRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
SysprofVisualizerRowClass *row_class = SYSPROF_VISUALIZER_ROW_CLASS (klass);
object_class->finalize = sysprof_depth_visualizer_row_finalize;
widget_class->draw = sysprof_depth_visualizer_row_draw;
widget_class->size_allocate = sysprof_depth_visualizer_row_size_allocate;
row_class->set_reader = sysprof_depth_visualizer_row_set_reader;
}
static void
sysprof_depth_visualizer_row_init (SysprofDepthVisualizerRow *self)
{
PangoAttrList *attrs = pango_attr_list_new ();
GtkWidget *label;
pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL * PANGO_SCALE_SMALL));
label = g_object_new (GTK_TYPE_LABEL,
"label", _("Stack Depth"),
"attributes", attrs,
"visible", TRUE,
"xalign", 0.0f,
"yalign", 0.0f,
NULL);
gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (label));
pango_attr_list_unref (attrs);
}

View File

@ -0,0 +1,430 @@
/* sysprof-depth-visualizer.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-depth-visualizer"
#include "config.h"
#include <glib/gi18n.h>
#include "pointcache.h"
#include "sysprof-depth-visualizer.h"
struct _SysprofDepthVisualizer
{
SysprofVisualizer parent_instance;
SysprofCaptureReader *reader;
PointCache *points;
guint reload_source;
guint mode;
GtkAllocation last_alloc;
};
typedef struct
{
SysprofCaptureReader *reader;
PointCache *pc;
gint64 begin_time;
gint64 end_time;
gint64 duration;
guint max_n_addrs;
guint mode;
} State;
G_DEFINE_TYPE (SysprofDepthVisualizer, sysprof_depth_visualizer, SYSPROF_TYPE_VISUALIZER)
static void
state_free (State *st)
{
g_clear_pointer (&st->reader, sysprof_capture_reader_unref);
g_clear_pointer (&st->pc, point_cache_unref);
g_slice_free (State, st);
}
static gboolean
discover_max_n_addr (const SysprofCaptureFrame *frame,
gpointer user_data)
{
const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
State *st = user_data;
g_assert (frame != NULL);
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
g_assert (st != NULL);
st->max_n_addrs = MAX (st->max_n_addrs, sample->n_addrs);
return TRUE;
}
static gboolean
build_point_cache_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
State *st = user_data;
gdouble x, y;
gboolean has_kernel = FALSE;
g_assert (frame != NULL);
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
g_assert (st != NULL);
x = (frame->time - st->begin_time) / (gdouble)st->duration;
y = sample->n_addrs / (gdouble)st->max_n_addrs;
/* If this contains a context-switch (meaning we're going into the kernel
* to do some work, use a negative value for Y so that we know later on
* that we should draw it with a different color (after removing the negation
* on the value.
*
* We skip past the first index, which is always a context switch as it is
* our perf handler.
*/
for (guint i = 1; i < sample->n_addrs; i++)
{
SysprofAddressContext kind;
if (sysprof_address_is_context_switch (sample->addrs[i], &kind))
{
has_kernel = TRUE;
y = -y;
break;
}
}
if (!has_kernel)
point_cache_add_point_to_set (st->pc, 1, x, y);
else
point_cache_add_point_to_set (st->pc, 2, x, y);
return TRUE;
}
static void
sysprof_depth_visualizer_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_SAMPLE, };
g_autoptr(SysprofCaptureCursor) cursor = NULL;
SysprofCaptureCondition *condition;
State *st = task_data;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (source_object));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
if (st->duration != 0)
{
cursor = sysprof_capture_cursor_new (st->reader);
condition = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
sysprof_capture_cursor_foreach (cursor, discover_max_n_addr, st);
sysprof_capture_cursor_reset (cursor);
sysprof_capture_cursor_foreach (cursor, build_point_cache_cb, st);
}
g_task_return_pointer (task,
g_steal_pointer (&st->pc),
(GDestroyNotify) point_cache_unref);
}
static void
apply_point_cache_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)object;
PointCache *pc;
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
g_assert (G_IS_TASK (result));
if ((pc = g_task_propagate_pointer (G_TASK (result), NULL)))
{
g_clear_pointer (&self->points, point_cache_unref);
self->points = g_steal_pointer (&pc);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
static void
sysprof_depth_visualizer_reload (SysprofDepthVisualizer *self)
{
g_autoptr(GTask) task = NULL;
GtkAllocation alloc;
State *st;
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
st = g_slice_new0 (State);
st->reader = sysprof_capture_reader_ref (self->reader);
st->pc = point_cache_new ();
st->max_n_addrs = 0;
st->begin_time = sysprof_capture_reader_get_start_time (self->reader);
st->end_time = sysprof_capture_reader_get_end_time (self->reader);
st->duration = st->end_time - st->begin_time;
st->mode = self->mode;
point_cache_add_set (st->pc, 1);
point_cache_add_set (st->pc, 2);
task = g_task_new (self, NULL, apply_point_cache_cb, NULL);
g_task_set_source_tag (task, sysprof_depth_visualizer_reload);
g_task_set_task_data (task, st, (GDestroyNotify) state_free);
g_task_run_in_thread (task, sysprof_depth_visualizer_worker);
}
static void
sysprof_depth_visualizer_set_reader (SysprofVisualizer *row,
SysprofCaptureReader *reader)
{
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)row;
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
if (self->reader != reader)
{
if (self->reader != NULL)
{
sysprof_capture_reader_unref (self->reader);
self->reader = NULL;
}
if (reader != NULL)
{
self->reader = sysprof_capture_reader_ref (reader);
sysprof_depth_visualizer_reload (self);
}
}
}
static gboolean
sysprof_depth_visualizer_draw (GtkWidget *widget,
cairo_t *cr)
{
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)widget;
GtkAllocation alloc;
GdkRectangle clip;
const Point *points;
gboolean ret;
guint n_points = 0;
GdkRGBA user;
GdkRGBA system;
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
g_assert (cr != NULL);
ret = GTK_WIDGET_CLASS (sysprof_depth_visualizer_parent_class)->draw (widget, cr);
if (self->points == NULL)
return ret;
gdk_rgba_parse (&user, "#1a5fb4");
gdk_rgba_parse (&system, "#3584e4");
gtk_widget_get_allocation (widget, &alloc);
if (!gdk_cairo_get_clip_rectangle (cr, &clip))
return ret;
/* Draw user-space stacks */
if (self->mode != SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY &&
(points = point_cache_get_points (self->points, 1, &n_points)))
{
g_autofree SysprofVisualizerAbsolutePoint *out_points = NULL;
out_points = g_new (SysprofVisualizerAbsolutePoint, n_points);
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (widget),
(const SysprofVisualizerRelativePoint *)points,
n_points, out_points, n_points);
cairo_set_line_width (cr, 1.0);
gdk_cairo_set_source_rgba (cr, &user);
for (guint i = 0; i < n_points; i++)
{
gdouble x, y;
x = out_points[i].x;
y = out_points[i].y;
if (x < clip.x)
continue;
if (x > clip.x + clip.width)
break;
for (guint j = i + 1; j < n_points; j++)
{
if (out_points[j].x != x)
break;
y = MIN (y, out_points[j].y);
}
x += alloc.x;
cairo_move_to (cr, (guint)x + .5, alloc.height);
cairo_line_to (cr, (guint)x + .5, y);
}
cairo_stroke (cr);
}
/* Draw kernel-space stacks */
if (self->mode != SYSPROF_DEPTH_VISUALIZER_USER_ONLY &&
(points = point_cache_get_points (self->points, 2, &n_points)))
{
g_autofree SysprofVisualizerAbsolutePoint *out_points = NULL;
out_points = g_new (SysprofVisualizerAbsolutePoint, n_points);
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (widget),
(const SysprofVisualizerRelativePoint *)points,
n_points, out_points, n_points);
cairo_set_line_width (cr, 1.0);
gdk_cairo_set_source_rgba (cr, &system);
for (guint i = 0; i < n_points; i++)
{
gdouble x, y;
x = out_points[i].x;
y = out_points[i].y;
if (x < clip.x)
continue;
if (x > clip.x + clip.width)
break;
for (guint j = i + 1; j < n_points; j++)
{
if (out_points[j].x != x)
break;
y = MIN (y, out_points[j].y);
}
x += alloc.x;
cairo_move_to (cr, (guint)x + .5, alloc.height);
cairo_line_to (cr, (guint)x + .5, y);
}
cairo_stroke (cr);
}
return ret;
}
static gboolean
sysprof_depth_visualizer_do_reload (gpointer data)
{
SysprofDepthVisualizer *self = data;
self->reload_source = 0;
sysprof_depth_visualizer_reload (self);
return G_SOURCE_REMOVE;
}
static void
sysprof_depth_visualizer_queue_reload (SysprofDepthVisualizer *self)
{
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
if (self->reload_source)
g_source_remove (self->reload_source);
self->reload_source = gdk_threads_add_idle (sysprof_depth_visualizer_do_reload, self);
}
static void
sysprof_depth_visualizer_size_allocate (GtkWidget *widget,
GtkAllocation *alloc)
{
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)widget;
GTK_WIDGET_CLASS (sysprof_depth_visualizer_parent_class)->size_allocate (widget, alloc);
if (alloc->width != self->last_alloc.x ||
alloc->height != self->last_alloc.height)
{
sysprof_depth_visualizer_queue_reload (SYSPROF_DEPTH_VISUALIZER (widget));
self->last_alloc = *alloc;
}
}
static void
sysprof_depth_visualizer_finalize (GObject *object)
{
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)object;
g_clear_pointer (&self->reader, sysprof_capture_reader_unref);
if (self->reload_source)
{
g_source_remove (self->reload_source);
self->reload_source = 0;
}
G_OBJECT_CLASS (sysprof_depth_visualizer_parent_class)->finalize (object);
}
static void
sysprof_depth_visualizer_class_init (SysprofDepthVisualizerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
SysprofVisualizerClass *row_class = SYSPROF_VISUALIZER_CLASS (klass);
object_class->finalize = sysprof_depth_visualizer_finalize;
widget_class->draw = sysprof_depth_visualizer_draw;
widget_class->size_allocate = sysprof_depth_visualizer_size_allocate;
row_class->set_reader = sysprof_depth_visualizer_set_reader;
}
static void
sysprof_depth_visualizer_init (SysprofDepthVisualizer *self)
{
}
SysprofVisualizer *
sysprof_depth_visualizer_new (SysprofDepthVisualizerMode mode)
{
SysprofDepthVisualizer *self;
g_return_val_if_fail (mode == SYSPROF_DEPTH_VISUALIZER_COMBINED ||
mode == SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY ||
mode == SYSPROF_DEPTH_VISUALIZER_USER_ONLY,
NULL);
self = g_object_new (SYSPROF_TYPE_DEPTH_VISUALIZER, NULL);
self->mode = mode;
return SYSPROF_VISUALIZER (g_steal_pointer (&self));
}

View File

@ -0,0 +1,40 @@
/* sysprof-depth-visualizer.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "sysprof-visualizer.h"
G_BEGIN_DECLS
typedef enum
{
SYSPROF_DEPTH_VISUALIZER_COMBINED,
SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY,
SYSPROF_DEPTH_VISUALIZER_USER_ONLY,
} SysprofDepthVisualizerMode;
#define SYSPROF_TYPE_DEPTH_VISUALIZER (sysprof_depth_visualizer_get_type())
G_DECLARE_FINAL_TYPE (SysprofDepthVisualizer, sysprof_depth_visualizer, SYSPROF, DEPTH_VISUALIZER, SysprofVisualizer)
SysprofVisualizer *sysprof_depth_visualizer_new (SysprofDepthVisualizerMode mode);
G_END_DECLS

View File

@ -0,0 +1,324 @@
/* sysprof-details-page.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#define G_LOG_DOMAIN "sysprof-details-page"
#include "config.h"
#include <dazzle.h>
#include <glib/gi18n.h>
#include <string.h>
#include "sysprof-details-page.h"
#include "sysprof-ui-private.h"
#define NSEC_PER_SEC (G_USEC_PER_SEC * 1000L)
struct _SysprofDetailsPage
{
SysprofPage parent_instance;
/* Template Objects */
DzlThreeGrid *three_grid;
GtkListStore *marks_store;
GtkTreeView *marks_view;
GtkLabel *counters;
GtkLabel *duration;
GtkLabel *filename;
GtkLabel *forks;
GtkLabel *marks;
GtkLabel *processes;
GtkLabel *samples;
GtkLabel *start_time;
GtkLabel *cpu_label;
guint next_row;
};
G_DEFINE_TYPE (SysprofDetailsPage, sysprof_details_page, GTK_TYPE_BIN)
#if GLIB_CHECK_VERSION(2, 56, 0)
# define _g_date_time_new_from_iso8601 g_date_time_new_from_iso8601
#else
static GDateTime *
_g_date_time_new_from_iso8601 (const gchar *str,
GTimeZone *default_tz)
{
GTimeVal tv;
if (g_time_val_from_iso8601 (str, &tv))
{
g_autoptr(GDateTime) dt = g_date_time_new_from_timeval_utc (&tv);
if (default_tz)
return g_date_time_to_timezone (dt, default_tz);
else
return g_steal_pointer (&dt);
}
return NULL;
}
#endif
static void
sysprof_details_page_class_init (SysprofDetailsPageClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-details-page.ui");
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, counters);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, cpu_label);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, duration);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, filename);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, forks);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, marks);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, marks_store);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, marks_view);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, processes);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, samples);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, start_time);
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, three_grid);
g_type_ensure (DZL_TYPE_THREE_GRID);
}
static void
sysprof_details_page_init (SysprofDetailsPage *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (self->marks_view),
GTK_SELECTION_MULTIPLE);
self->next_row = 8;
}
GtkWidget *
sysprof_details_page_new (void)
{
return g_object_new (SYSPROF_TYPE_DETAILS_PAGE, NULL);
}
static void
update_cpu_info_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(SysprofDetailsPage) self = user_data;
g_autofree gchar *str = NULL;
g_assert (SYSPROF_IS_DETAILS_PAGE (self));
g_assert (G_IS_TASK (result));
if ((str = g_task_propagate_pointer (G_TASK (result), NULL)))
gtk_label_set_label (self->cpu_label, str);
}
static gboolean
cpu_info_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
const SysprofCaptureFileChunk *fc = (gpointer)frame;
const gchar *endptr;
const gchar *line;
gchar **str = user_data;
endptr = (gchar *)fc->data + fc->len;
line = memmem ((gchar *)fc->data, fc->len, "model name", 10);
endptr = memchr (line, '\n', endptr - line);
if (endptr)
{
gchar *tmp = *str = g_strndup (line, endptr - line);
for (; *tmp && *tmp != ':'; tmp++)
*tmp = ' ';
if (*tmp == ':')
*tmp = ' ';
g_strstrip (*str);
return FALSE;
}
return TRUE;
}
static void
sysprof_details_page_update_cpu_info_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
SysprofCaptureCursor *cursor = task_data;
gchar *str = NULL;
g_assert (G_IS_TASK (task));
g_assert (cursor != NULL);
sysprof_capture_cursor_foreach (cursor, cpu_info_cb, &str);
g_task_return_pointer (task, g_steal_pointer (&str), g_free);
}
static void
sysprof_details_page_update_cpu_info (SysprofDetailsPage *self,
SysprofCaptureReader *reader)
{
g_autoptr(SysprofCaptureCursor) cursor = NULL;
g_autoptr(GTask) task = NULL;
g_assert (SYSPROF_IS_DETAILS_PAGE (self));
g_assert (reader != NULL);
cursor = sysprof_capture_cursor_new (reader);
sysprof_capture_cursor_add_condition (cursor,
sysprof_capture_condition_new_where_file ("/proc/cpuinfo"));
task = g_task_new (NULL, NULL, update_cpu_info_cb, g_object_ref (self));
g_task_set_task_data (task,
g_steal_pointer (&cursor),
(GDestroyNotify) sysprof_capture_cursor_unref);
g_task_run_in_thread (task, sysprof_details_page_update_cpu_info_worker);
}
void
sysprof_details_page_set_reader (SysprofDetailsPage *self,
SysprofCaptureReader *reader)
{
g_autoptr(GDateTime) dt = NULL;
g_autoptr(GDateTime) local = NULL;
g_autofree gchar *duration_str = NULL;
const gchar *filename;
const gchar *capture_at;
SysprofCaptureStat st_buf;
gint64 duration;
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
g_return_if_fail (reader != NULL);
sysprof_details_page_update_cpu_info (self, reader);
if (!(filename = sysprof_capture_reader_get_filename (reader)))
filename = _("Memory Capture");
gtk_label_set_label (self->filename, filename);
if ((capture_at = sysprof_capture_reader_get_time (reader)) &&
(dt = _g_date_time_new_from_iso8601 (capture_at, NULL)) &&
(local = g_date_time_to_local (dt)))
{
g_autofree gchar *str = g_date_time_format (local, "%x %X");
gtk_label_set_label (self->start_time, str);
}
duration = sysprof_capture_reader_get_end_time (reader) -
sysprof_capture_reader_get_start_time (reader);
duration_str = g_strdup_printf (_("%0.4lf seconds"), duration / (gdouble)NSEC_PER_SEC);
gtk_label_set_label (self->duration, duration_str);
if (sysprof_capture_reader_get_stat (reader, &st_buf))
{
#define SET_FRAME_COUNT(field, TYPE) \
G_STMT_START { \
g_autofree gchar *str = NULL; \
str = g_strdup_printf ("%"G_GSIZE_FORMAT, st_buf.frame_count[TYPE]); \
gtk_label_set_label (self->field, str); \
} G_STMT_END
SET_FRAME_COUNT (samples, SYSPROF_CAPTURE_FRAME_SAMPLE);
SET_FRAME_COUNT (marks, SYSPROF_CAPTURE_FRAME_MARK);
SET_FRAME_COUNT (processes, SYSPROF_CAPTURE_FRAME_PROCESS);
SET_FRAME_COUNT (forks, SYSPROF_CAPTURE_FRAME_FORK);
SET_FRAME_COUNT (counters, SYSPROF_CAPTURE_FRAME_CTRSET);
#undef SET_FRAME_COUNT
}
}
void
sysprof_details_page_add_item (SysprofDetailsPage *self,
GtkWidget *left,
GtkWidget *center)
{
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
g_return_if_fail (!left || GTK_IS_WIDGET (left));
g_return_if_fail (!center || GTK_IS_WIDGET (center));
if (left)
gtk_container_add_with_properties (GTK_CONTAINER (self->three_grid), left,
"row", self->next_row,
"column", DZL_THREE_GRID_COLUMN_LEFT,
NULL);
if (center)
gtk_container_add_with_properties (GTK_CONTAINER (self->three_grid), center,
"row", self->next_row,
"column", DZL_THREE_GRID_COLUMN_CENTER,
NULL);
self->next_row++;
}
void
sysprof_details_page_add_mark (SysprofDetailsPage *self,
const gchar *mark,
gint64 min,
gint64 max,
gint64 avg,
gint64 hits)
{
GtkTreeIter iter;
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
gtk_list_store_append (self->marks_store, &iter);
gtk_list_store_set (self->marks_store, &iter,
0, mark,
1, min ? _sysprof_format_duration (min) : "",
2, max ? _sysprof_format_duration (max) : "",
3, avg ? _sysprof_format_duration (avg) : "",
4, hits,
-1);
}
void
sysprof_details_page_add_marks (SysprofDetailsPage *self,
const SysprofMarkStat *marks,
guint n_marks)
{
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
g_return_if_fail (marks != NULL || n_marks == 0);
if (marks == NULL || n_marks == 0)
return;
/* Be reasonable */
if (n_marks > 100)
n_marks = 100;
for (guint i = 0; i < n_marks; i++)
sysprof_details_page_add_mark (self,
marks[i].name,
marks[i].min,
marks[i].max,
marks[i].avg,
marks[i].count);
}

View File

@ -0,0 +1,60 @@
/* sysprof-details-page.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
#include <sysprof-capture.h>
G_BEGIN_DECLS
SYSPROF_ALIGNED_BEGIN (8)
typedef struct
{
gchar name[152];
guint64 count;
gint64 max;
gint64 min;
gint64 avg;
guint64 avg_count;
} SysprofMarkStat
SYSPROF_ALIGNED_END (8);
#define SYSPROF_TYPE_DETAILS_PAGE (sysprof_details_page_get_type())
G_DECLARE_FINAL_TYPE (SysprofDetailsPage, sysprof_details_page, SYSPROF, DETAILS_PAGE, GtkBin)
GtkWidget *sysprof_details_page_new (void);
void sysprof_details_page_set_reader (SysprofDetailsPage *self,
SysprofCaptureReader *reader);
void sysprof_details_page_add_marks (SysprofDetailsPage *self,
const SysprofMarkStat *marks,
guint n_marks);
void sysprof_details_page_add_mark (SysprofDetailsPage *self,
const gchar *mark,
gint64 min,
gint64 max,
gint64 avg,
gint64 hits);
void sysprof_details_page_add_item (SysprofDetailsPage *self,
GtkWidget *left,
GtkWidget *center);
G_END_DECLS

View File

@ -0,0 +1,372 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<template class="SysprofDetailsPage" parent="GtkBin">
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="propagate-natural-height">true</property>
<property name="visible">true</property>
<child>
<object class="DzlThreeGrid" id="three_grid">
<property name="margin">36</property>
<property name="column-spacing">12</property>
<property name="row-spacing">6</property>
<property name="visible">true</property>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="label" translatable="yes">Filename</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="column">left</property>
<property name="row">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="label" translatable="yes">Captured at</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="column">left</property>
<property name="row">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Duration</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="column">left</property>
<property name="row">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">CPU Model</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="column">left</property>
<property name="row">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="margin-top">12</property>
<property name="visible">True</property>
<property name="label" translatable="yes">Samples Captured</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="column">left</property>
<property name="row">4</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Marks Captured</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="column">left</property>
<property name="row">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Processes Captured</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="column">left</property>
<property name="row">6</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Forks Captured</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="column">left</property>
<property name="row">7</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="margin-bottom">12</property>
<property name="label" translatable="yes">Counters Captured</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="column">left</property>
<property name="row">8</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="filename">
<property name="width-chars">35</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ellipsize">start</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="column">1</property>
<property name="row">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="start_time">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ellipsize">start</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="column">center</property>
<property name="row">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="duration">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="column">center</property>
<property name="row">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cpu_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="column">center</property>
<property name="row">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="samples">
<property name="margin-top">12</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ellipsize">start</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="column">center</property>
<property name="row">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="marks">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ellipsize">start</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="column">center</property>
<property name="row">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="processes">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ellipsize">start</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="column">center</property>
<property name="row">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="forks">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ellipsize">start</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="column">center</property>
<property name="row">7</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="counters">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ellipsize">start</property>
<property name="margin-bottom">12</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="column">center</property>
<property name="row">8</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="shadow-type">in</property>
<property name="margin-bottom">12</property>
<child>
<object class="GtkTreeView" id="marks_view">
<property name="model">marks_store</property>
<property name="width-request">500</property>
<property name="height-request">100</property>
<property name="enable-grid-lines">both</property>
<property name="visible">true</property>
<child>
<object class="GtkTreeViewColumn">
<property name="expand">true</property>
<property name="title" translatable="yes">Mark</property>
<child>
<object class="GtkCellRendererText">
<property name="xalign">0.0</property>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Hits</property>
<child>
<object class="GtkCellRendererText">
<property name="xalign">0.0</property>
</object>
<attributes>
<attribute name="text">4</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Min</property>
<child>
<object class="GtkCellRendererText">
<property name="xalign">0.0</property>
</object>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Max</property>
<child>
<object class="GtkCellRendererText">
<property name="xalign">0.0</property>
</object>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Avg</property>
<child>
<object class="GtkCellRendererText">
<property name="xalign">0.0</property>
</object>
<attributes>
<attribute name="text">3</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="column">center</property>
<property name="row">9</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</template>
<object class="GtkListStore" id="marks_store">
<columns>
<!-- column-name Mark -->
<column type="gchararray"/>
<!-- column-name Min -->
<column type="gchararray"/>
<!-- column-name Max -->
<column type="gchararray"/>
<!-- column-name Avg -->
<column type="gchararray"/>
<!-- column-name Hits -->
<column type="gint64"/>
</columns>
</object>
</interface>

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,9 @@
#include <gtk/gtk.h>
#include <sysprof.h>
#include "sysprof-version-macros.h"
#include "sysprof-page.h"
#include "sysprof-visualizer-group.h"
#include "sysprof-zoom-manager.h"
G_BEGIN_DECLS
@ -32,38 +34,59 @@ G_BEGIN_DECLS
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofDisplay, sysprof_display, SYSPROF, DISPLAY, GtkBin)
SYSPROF_ALIGNED_BEGIN(8)
struct _SysprofDisplayClass
{
GtkBinClass parent_class;
/*< private >*/
gpointer _reserved[16];
}
SYSPROF_ALIGNED_END(8);
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_display_new (void);
GtkWidget *sysprof_display_new (void);
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_display_new_for_profiler (SysprofProfiler *profiler);
GtkWidget *sysprof_display_new_for_profiler (SysprofProfiler *profiler);
SYSPROF_AVAILABLE_IN_ALL
gchar *sysprof_display_dup_title (SysprofDisplay *self);
char *sysprof_display_dup_title (SysprofDisplay *self);
SYSPROF_AVAILABLE_IN_ALL
SysprofProfiler *sysprof_display_get_profiler (SysprofDisplay *self);
SysprofProfiler *sysprof_display_get_profiler (SysprofDisplay *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_display_is_empty (SysprofDisplay *self);
void sysprof_display_add_group (SysprofDisplay *self,
SysprofVisualizerGroup *group);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_display_open (SysprofDisplay *self,
GFile *file);
void sysprof_display_add_page (SysprofDisplay *self,
SysprofPage *page);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_display_save (SysprofDisplay *self);
SysprofPage *sysprof_display_get_visible_page (SysprofDisplay *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_display_get_can_save (SysprofDisplay *self);
void sysprof_display_set_visible_page (SysprofDisplay *self,
SysprofPage *page);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_display_stop_recording (SysprofDisplay *self);
SysprofZoomManager *sysprof_display_get_zoom_manager (SysprofDisplay *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_display_get_can_replay (SysprofDisplay *self);
void sysprof_display_load_async (SysprofDisplay *self,
SysprofCaptureReader *reader,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
SYSPROF_AVAILABLE_IN_ALL
SysprofDisplay *sysprof_display_replay (SysprofDisplay *self);
gboolean sysprof_display_load_finish (SysprofDisplay *self,
GAsyncResult *result,
GError **error);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_display_is_empty (SysprofDisplay *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_display_open (SysprofDisplay *self,
GFile *file);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_display_save (SysprofDisplay *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_display_get_can_save (SysprofDisplay *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_display_stop_recording (SysprofDisplay *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_display_get_can_replay (SysprofDisplay *self);
SYSPROF_AVAILABLE_IN_ALL
SysprofDisplay *sysprof_display_replay (SysprofDisplay *self);
G_END_DECLS

View File

@ -14,11 +14,40 @@
</packing>
</child>
<child>
<object class="SysprofCaptureView" id="capture_view">
<object class="DzlMultiPaned">
<property name="orientation">vertical</property>
<property name="visible">true</property>
<child>
<object class="SysprofVisualizersFrame" id="visualizers">
<property name="vexpand">false</property>
<property name="visible">true</property>
</object>
</child>
<child>
<object class="GtkSeparator">
<property name="orientation">horizontal</property>
<property name="visible">true</property>
</object>
</child>
<child>
<object class="GtkStack" id="pages">
<property name="homogeneous">false</property>
<property name="vexpand">true</property>
<property name="visible">true</property>
<child>
<object class="SysprofDetailsPage" id="details">
<property name="visible">true</property>
</object>
<packing>
<property name="title" translatable="yes">Details</property>
<property name="name">details</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="name">capture</property>
<property name="name">view</property>
</packing>
</child>
<child>
@ -26,14 +55,11 @@
<property name="visible">true</property>
</object>
<packing>
<property name="name">recording</property>
<property name="name">record</property>
</packing>
</child>
<child>
<object class="SysprofEmptyStateView" id="failed_view">
<property name="icon-name">computer-fail-symbolic</property>
<property name="title" translatable="yes">Something went wrong</property>
<property name="subtitle" translatable="yes">Sysprof failed to access the requested performance data.</property>
<object class="SysprofFailedStateView" id="failed_view">
<property name="visible">true</property>
</object>
<packing>

View File

@ -20,10 +20,6 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include <sysprof.h>
@ -31,7 +27,6 @@ G_BEGIN_DECLS
#define SYSPROF_TYPE_EMPTY_STATE_VIEW (sysprof_empty_state_view_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofEmptyStateView, sysprof_empty_state_view, SYSPROF, EMPTY_STATE_VIEW, GtkBin)
struct _SysprofEmptyStateViewClass
@ -41,7 +36,6 @@ struct _SysprofEmptyStateViewClass
gpointer padding[4];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_empty_state_view_new (void);
G_END_DECLS

View File

@ -20,10 +20,6 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include <sysprof.h>
@ -31,7 +27,6 @@ G_BEGIN_DECLS
#define SYSPROF_TYPE_FAILED_STATE_VIEW (sysprof_failed_state_view_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofFailedStateView, sysprof_failed_state_view, SYSPROF, FAILED_STATE_VIEW, GtkBin)
struct _SysprofFailedStateViewClass
@ -41,9 +36,7 @@ struct _SysprofFailedStateViewClass
gpointer padding[4];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_failed_state_view_new (void);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_failed_state_view_set_profiler (SysprofFailedStateView *self,
SysprofProfiler *profiler);

View File

@ -1,70 +0,0 @@
/* sysprof-line-visualizer-row.h
*
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <sysprof.h>
#include "sysprof-visualizer-row.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_LINE_VISUALIZER_ROW (sysprof_line_visualizer_row_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofLineVisualizerRow, sysprof_line_visualizer_row, SYSPROF, LINE_VISUALIZER_ROW, SysprofVisualizerRow)
struct _SysprofLineVisualizerRowClass
{
SysprofVisualizerRowClass parent_class;
void (*counter_added) (SysprofLineVisualizerRow *self,
guint counter_id);
/*< private >*/
gpointer _reserved[16];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_line_visualizer_row_new (void);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_line_visualizer_row_clear (SysprofLineVisualizerRow *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_line_visualizer_row_add_counter (SysprofLineVisualizerRow *self,
guint counter_id,
const GdkRGBA *color);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_line_visualizer_row_set_line_width (SysprofLineVisualizerRow *self,
guint counter_id,
gdouble width);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_line_visualizer_row_set_fill (SysprofLineVisualizerRow *self,
guint counter_id,
const GdkRGBA *color);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_line_visualizer_row_set_dash (SysprofLineVisualizerRow *self,
guint counter_id,
gboolean use_dash);
G_END_DECLS

View File

@ -1,4 +1,4 @@
/* sysprof-line-visualizer-row.c
/* sysprof-line-visualizer.c
*
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
*
@ -18,7 +18,7 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-line-visualizer-row"
#define G_LOG_DOMAIN "sysprof-line-visualizer"
#include "config.h"
@ -27,7 +27,7 @@
#include <sysprof.h>
#include "pointcache.h"
#include "sysprof-line-visualizer-row.h"
#include "sysprof-line-visualizer.h"
typedef struct
{
@ -49,11 +49,6 @@ typedef struct
*/
PointCache *cache;
/*
* Child widget to display the label in the upper corner.
*/
GtkLabel *label;
/*
* Range of the scale for lower and upper.
*/
@ -69,7 +64,7 @@ typedef struct
guint y_lower_set : 1;
guint y_upper_set : 1;
} SysprofLineVisualizerRowPrivate;
} SysprofLineVisualizerPrivate;
typedef struct
{
@ -96,19 +91,18 @@ typedef struct
guint y_upper_set : 1;
} LoadData;
G_DEFINE_TYPE_WITH_PRIVATE (SysprofLineVisualizerRow, sysprof_line_visualizer_row, SYSPROF_TYPE_VISUALIZER_ROW)
G_DEFINE_TYPE_WITH_PRIVATE (SysprofLineVisualizer, sysprof_line_visualizer, SYSPROF_TYPE_VISUALIZER)
static void sysprof_line_visualizer_row_load_data_async (SysprofLineVisualizerRow *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
static PointCache *sysprof_line_visualizer_row_load_data_finish (SysprofLineVisualizerRow *self,
GAsyncResult *result,
GError **error);
static void sysprof_line_visualizer_load_data_async (SysprofLineVisualizer *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
static PointCache *sysprof_line_visualizer_load_data_finish (SysprofLineVisualizer *self,
GAsyncResult *result,
GError **error);
enum {
PROP_0,
PROP_TITLE,
PROP_Y_LOWER,
PROP_Y_UPPER,
N_PROPS
@ -144,34 +138,38 @@ copy_array (GArray *ar)
}
static gboolean
sysprof_line_visualizer_row_draw (GtkWidget *widget,
cairo_t *cr)
sysprof_line_visualizer_draw (GtkWidget *widget,
cairo_t *cr)
{
SysprofLineVisualizerRow *self = (SysprofLineVisualizerRow *)widget;
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizer *self = (SysprofLineVisualizer *)widget;
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
GtkStyleContext *style_context;
GtkStateFlags flags;
GtkAllocation alloc;
GdkRectangle clip;
GdkRGBA foreground;
gboolean ret;
g_assert (SYSPROF_IS_LINE_VISUALIZER_ROW (widget));
g_assert (SYSPROF_IS_LINE_VISUALIZER (widget));
g_assert (cr != NULL);
gtk_widget_get_allocation (widget, &alloc);
ret = GTK_WIDGET_CLASS (sysprof_line_visualizer_row_parent_class)->draw (widget, cr);
ret = GTK_WIDGET_CLASS (sysprof_line_visualizer_parent_class)->draw (widget, cr);
if (priv->cache == NULL)
return ret;
if (!gdk_cairo_get_clip_rectangle (cr, &clip))
return ret;
style_context = gtk_widget_get_style_context (widget);
flags = gtk_widget_get_state_flags (widget);
gtk_style_context_get_color (style_context, flags, &foreground);
for (guint line = 0; line < priv->lines->len; line++)
{
g_autofree SysprofVisualizerRowAbsolutePoint *points = NULL;
g_autofree SysprofVisualizerAbsolutePoint *points = NULL;
const LineInfo *line_info = &g_array_index (priv->lines, LineInfo, line);
const Point *fpoints;
guint n_fpoints = 0;
@ -181,19 +179,32 @@ sysprof_line_visualizer_row_draw (GtkWidget *widget,
if (n_fpoints > 0)
{
gdouble last_x;
gdouble last_y;
gdouble last_x = 0;
gdouble last_y = 0;
guint p;
points = g_new0 (SysprofVisualizerRowAbsolutePoint, n_fpoints);
points = g_new0 (SysprofVisualizerAbsolutePoint, n_fpoints);
sysprof_visualizer_row_translate_points (SYSPROF_VISUALIZER_ROW (self),
(const SysprofVisualizerRowRelativePoint *)fpoints,
n_fpoints,
points,
n_fpoints);
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
(const SysprofVisualizerRelativePoint *)fpoints,
n_fpoints,
points,
n_fpoints);
last_x = points[0].x;
last_y = points[0].y;
for (p = 0; p < n_fpoints; p++)
{
if (points[p].x >= clip.x)
break;
}
if (p >= n_fpoints)
return ret;
if (p > 0)
p--;
last_x = points[p].x;
last_y = points[p].y;
if (line_info->fill)
{
@ -205,7 +216,7 @@ sysprof_line_visualizer_row_draw (GtkWidget *widget,
cairo_move_to (cr, last_x, last_y);
}
for (guint i = 1; i < n_fpoints; i++)
for (guint i = p + 1; i < n_fpoints; i++)
{
cairo_curve_to (cr,
last_x + ((points[i].x - last_x) / 2),
@ -214,8 +225,12 @@ sysprof_line_visualizer_row_draw (GtkWidget *widget,
points[i].y,
points[i].x,
points[i].y);
last_x = points[i].x;
last_y = points[i].y;
if (points[i].x > clip.x + clip.width)
break;
}
if (line_info->fill)
@ -249,18 +264,18 @@ sysprof_line_visualizer_row_draw (GtkWidget *widget,
}
static void
sysprof_line_visualizer_row_load_data_cb (GObject *object,
sysprof_line_visualizer_load_data_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofLineVisualizerRow *self = (SysprofLineVisualizerRow *)object;
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizer *self = (SysprofLineVisualizer *)object;
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_autoptr(GError) error = NULL;
g_autoptr(PointCache) cache = NULL;
g_assert (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
cache = sysprof_line_visualizer_row_load_data_finish (self, result, &error);
cache = sysprof_line_visualizer_load_data_finish (self, result, &error);
if (cache == NULL)
{
@ -275,20 +290,20 @@ sysprof_line_visualizer_row_load_data_cb (GObject *object,
}
static gboolean
sysprof_line_visualizer_row_do_reload (gpointer data)
sysprof_line_visualizer_do_reload (gpointer data)
{
SysprofLineVisualizerRow *self = data;
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizer *self = data;
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_assert (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
priv->queued_load = 0;
if (priv->reader != NULL)
{
sysprof_line_visualizer_row_load_data_async (self,
sysprof_line_visualizer_load_data_async (self,
NULL,
sysprof_line_visualizer_row_load_data_cb,
sysprof_line_visualizer_load_data_cb,
NULL);
}
@ -296,29 +311,29 @@ sysprof_line_visualizer_row_do_reload (gpointer data)
}
static void
sysprof_line_visualizer_row_queue_reload (SysprofLineVisualizerRow *self)
sysprof_line_visualizer_queue_reload (SysprofLineVisualizer *self)
{
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_assert (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
if (priv->queued_load == 0)
{
priv->queued_load = gdk_threads_add_idle_full (G_PRIORITY_LOW,
sysprof_line_visualizer_row_do_reload,
sysprof_line_visualizer_do_reload,
self,
NULL);
}
}
static void
sysprof_line_visualizer_row_set_reader (SysprofVisualizerRow *row,
SysprofCaptureReader *reader)
sysprof_line_visualizer_set_reader (SysprofVisualizer *row,
SysprofCaptureReader *reader)
{
SysprofLineVisualizerRow *self = (SysprofLineVisualizerRow *)row;
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizer *self = (SysprofLineVisualizer *)row;
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_assert (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
if (priv->reader != reader)
{
@ -331,15 +346,15 @@ sysprof_line_visualizer_row_set_reader (SysprofVisualizerRow *row,
if (reader != NULL)
priv->reader = sysprof_capture_reader_ref (reader);
sysprof_line_visualizer_row_queue_reload (self);
sysprof_line_visualizer_queue_reload (self);
}
}
static void
sysprof_line_visualizer_row_finalize (GObject *object)
sysprof_line_visualizer_finalize (GObject *object)
{
SysprofLineVisualizerRow *self = (SysprofLineVisualizerRow *)object;
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizer *self = (SysprofLineVisualizer *)object;
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_clear_pointer (&priv->lines, g_array_unref);
g_clear_pointer (&priv->cache, point_cache_unref);
@ -351,24 +366,20 @@ sysprof_line_visualizer_row_finalize (GObject *object)
priv->queued_load = 0;
}
G_OBJECT_CLASS (sysprof_line_visualizer_row_parent_class)->finalize (object);
G_OBJECT_CLASS (sysprof_line_visualizer_parent_class)->finalize (object);
}
static void
sysprof_line_visualizer_row_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
sysprof_line_visualizer_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofLineVisualizerRow *self = SYSPROF_LINE_VISUALIZER_ROW (object);
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizer *self = SYSPROF_LINE_VISUALIZER (object);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
switch (prop_id)
{
case PROP_TITLE:
g_object_get_property (G_OBJECT (priv->label), "label", value);
break;
case PROP_Y_LOWER:
g_value_set_double (value, priv->y_lower);
break;
@ -383,20 +394,16 @@ sysprof_line_visualizer_row_get_property (GObject *object,
}
static void
sysprof_line_visualizer_row_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
sysprof_line_visualizer_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofLineVisualizerRow *self = SYSPROF_LINE_VISUALIZER_ROW (object);
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizer *self = SYSPROF_LINE_VISUALIZER (object);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
switch (prop_id)
{
case PROP_TITLE:
g_object_set_property (G_OBJECT (priv->label), "label", value);
break;
case PROP_Y_LOWER:
priv->y_lower = g_value_get_double (value);
priv->y_lower_set = TRUE;
@ -415,26 +422,19 @@ sysprof_line_visualizer_row_set_property (GObject *object,
}
static void
sysprof_line_visualizer_row_class_init (SysprofLineVisualizerRowClass *klass)
sysprof_line_visualizer_class_init (SysprofLineVisualizerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
SysprofVisualizerRowClass *visualizer_class = SYSPROF_VISUALIZER_ROW_CLASS (klass);
SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
object_class->finalize = sysprof_line_visualizer_row_finalize;
object_class->get_property = sysprof_line_visualizer_row_get_property;
object_class->set_property = sysprof_line_visualizer_row_set_property;
object_class->finalize = sysprof_line_visualizer_finalize;
object_class->get_property = sysprof_line_visualizer_get_property;
object_class->set_property = sysprof_line_visualizer_set_property;
widget_class->draw = sysprof_line_visualizer_row_draw;
widget_class->draw = sysprof_line_visualizer_draw;
visualizer_class->set_reader = sysprof_line_visualizer_row_set_reader;
properties [PROP_TITLE] =
g_param_spec_string ("title",
"Title",
"The title of the row",
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
visualizer_class->set_reader = sysprof_line_visualizer_set_reader;
properties [PROP_Y_LOWER] =
g_param_spec_double ("y-lower",
@ -458,35 +458,22 @@ sysprof_line_visualizer_row_class_init (SysprofLineVisualizerRowClass *klass)
}
static void
sysprof_line_visualizer_row_init (SysprofLineVisualizerRow *self)
sysprof_line_visualizer_init (SysprofLineVisualizer *self)
{
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
PangoAttrList *attrs = pango_attr_list_new ();
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
priv->lines = g_array_new (FALSE, FALSE, sizeof (LineInfo));
pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL * PANGO_SCALE_SMALL));
priv->label = g_object_new (GTK_TYPE_LABEL,
"attributes", attrs,
"visible", TRUE,
"xalign", 0.0f,
"yalign", 0.0f,
NULL);
gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (priv->label));
pango_attr_list_unref (attrs);
}
void
sysprof_line_visualizer_row_add_counter (SysprofLineVisualizerRow *self,
guint counter_id,
const GdkRGBA *color)
sysprof_line_visualizer_add_counter (SysprofLineVisualizer *self,
guint counter_id,
const GdkRGBA *color)
{
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
LineInfo line_info = { 0 };
g_assert (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
g_assert (priv->lines != NULL);
line_info.id = counter_id;
@ -506,18 +493,18 @@ sysprof_line_visualizer_row_add_counter (SysprofLineVisualizerRow *self,
g_array_append_val (priv->lines, line_info);
if (SYSPROF_LINE_VISUALIZER_ROW_GET_CLASS (self)->counter_added)
SYSPROF_LINE_VISUALIZER_ROW_GET_CLASS (self)->counter_added (self, counter_id);
if (SYSPROF_LINE_VISUALIZER_GET_CLASS (self)->counter_added)
SYSPROF_LINE_VISUALIZER_GET_CLASS (self)->counter_added (self, counter_id);
sysprof_line_visualizer_row_queue_reload (self);
sysprof_line_visualizer_queue_reload (self);
}
void
sysprof_line_visualizer_row_clear (SysprofLineVisualizerRow *self)
sysprof_line_visualizer_clear (SysprofLineVisualizer *self)
{
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
if (priv->lines->len > 0)
g_array_remove_range (priv->lines, 0, priv->lines->len);
@ -580,8 +567,8 @@ calc_y_int64 (gint64 lower,
}
static gboolean
sysprof_line_visualizer_row_load_data_frame_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
sysprof_line_visualizer_load_data_frame_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
LoadData *load = user_data;
@ -622,8 +609,8 @@ sysprof_line_visualizer_row_load_data_frame_cb (const SysprofCaptureFrame *frame
}
static gboolean
sysprof_line_visualizer_row_load_data_range_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
sysprof_line_visualizer_load_data_range_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
LoadData *load = user_data;
@ -689,16 +676,16 @@ sysprof_line_visualizer_row_load_data_range_cb (const SysprofCaptureFrame *frame
}
static void
sysprof_line_visualizer_row_load_data_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
sysprof_line_visualizer_load_data_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
LoadData *load = task_data;
g_autoptr(GArray) counter_ids = NULL;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_LINE_VISUALIZER_ROW (source_object));
g_assert (SYSPROF_IS_LINE_VISUALIZER (source_object));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
counter_ids = g_array_new (FALSE, FALSE, sizeof (guint));
@ -716,7 +703,7 @@ sysprof_line_visualizer_row_load_data_worker (GTask *task,
/* If y boundaries are not set, we need to discover them by scaning the data. */
if (!load->y_lower_set || !load->y_upper_set)
{
sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_row_load_data_range_cb, load);
sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_load_data_range_cb, load);
sysprof_capture_cursor_reset (load->cursor);
/* Add extra boundary for some space above the graph line */
@ -724,26 +711,26 @@ sysprof_line_visualizer_row_load_data_worker (GTask *task,
load->y_upper = load->y_upper + ((load->y_upper - load->y_lower) * .25);
}
sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_row_load_data_frame_cb, load);
sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_load_data_frame_cb, load);
g_task_return_pointer (task, g_steal_pointer (&load->cache), (GDestroyNotify)point_cache_unref);
}
static void
sysprof_line_visualizer_row_load_data_async (SysprofLineVisualizerRow *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
sysprof_line_visualizer_load_data_async (SysprofLineVisualizer *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_autoptr(GTask) task = NULL;
LoadData *load;
g_assert (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_priority (task, G_PRIORITY_LOW);
g_task_set_source_tag (task, sysprof_line_visualizer_row_load_data_async);
g_task_set_source_tag (task, sysprof_line_visualizer_load_data_async);
if (priv->reader == NULL)
{
@ -773,18 +760,18 @@ sysprof_line_visualizer_row_load_data_async (SysprofLineVisualizerRow *self,
}
g_task_set_task_data (task, load, load_data_free);
g_task_run_in_thread (task, sysprof_line_visualizer_row_load_data_worker);
g_task_run_in_thread (task, sysprof_line_visualizer_load_data_worker);
}
static PointCache *
sysprof_line_visualizer_row_load_data_finish (SysprofLineVisualizerRow *self,
GAsyncResult *result,
GError **error)
sysprof_line_visualizer_load_data_finish (SysprofLineVisualizer *self,
GAsyncResult *result,
GError **error)
{
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
LoadData *state;
g_assert (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
g_assert (G_IS_TASK (result));
state = g_task_get_task_data (G_TASK (result));
@ -805,13 +792,13 @@ sysprof_line_visualizer_row_load_data_finish (SysprofLineVisualizerRow *self,
}
void
sysprof_line_visualizer_row_set_line_width (SysprofLineVisualizerRow *self,
guint counter_id,
gdouble width)
sysprof_line_visualizer_set_line_width (SysprofLineVisualizer *self,
guint counter_id,
gdouble width)
{
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
for (guint i = 0; i < priv->lines->len; i++)
{
@ -820,20 +807,20 @@ sysprof_line_visualizer_row_set_line_width (SysprofLineVisualizerRow *self,
if (info->id == counter_id)
{
info->line_width = width;
sysprof_line_visualizer_row_queue_reload (self);
sysprof_line_visualizer_queue_reload (self);
break;
}
}
}
void
sysprof_line_visualizer_row_set_fill (SysprofLineVisualizerRow *self,
guint counter_id,
const GdkRGBA *color)
sysprof_line_visualizer_set_fill (SysprofLineVisualizer *self,
guint counter_id,
const GdkRGBA *color)
{
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
for (guint i = 0; i < priv->lines->len; i++)
{
@ -844,20 +831,20 @@ sysprof_line_visualizer_row_set_fill (SysprofLineVisualizerRow *self,
info->fill = !!color;
if (color != NULL)
info->background = *color;
sysprof_line_visualizer_row_queue_reload (self);
sysprof_line_visualizer_queue_reload (self);
break;
}
}
}
void
sysprof_line_visualizer_row_set_dash (SysprofLineVisualizerRow *self,
guint counter_id,
gboolean use_dash)
sysprof_line_visualizer_set_dash (SysprofLineVisualizer *self,
guint counter_id,
gboolean use_dash)
{
SysprofLineVisualizerRowPrivate *priv = sysprof_line_visualizer_row_get_instance_private (self);
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER_ROW (self));
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
for (guint i = 0; i < priv->lines->len; i++)
{
@ -866,7 +853,7 @@ sysprof_line_visualizer_row_set_dash (SysprofLineVisualizerRow *self,
if (info->id == counter_id)
{
info->use_dash = !!use_dash;
sysprof_line_visualizer_row_queue_reload (self);
sysprof_line_visualizer_queue_reload (self);
break;
}
}

View File

@ -0,0 +1,57 @@
/* sysprof-line-visualizer.h
*
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "sysprof-visualizer.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_LINE_VISUALIZER (sysprof_line_visualizer_get_type())
G_DECLARE_DERIVABLE_TYPE (SysprofLineVisualizer, sysprof_line_visualizer, SYSPROF, LINE_VISUALIZER, SysprofVisualizer)
struct _SysprofLineVisualizerClass
{
SysprofVisualizerClass parent_class;
void (*counter_added) (SysprofLineVisualizer *self,
guint counter_id);
/*< private >*/
gpointer _reserved[16];
};
GtkWidget *sysprof_line_visualizer_new (void);
void sysprof_line_visualizer_clear (SysprofLineVisualizer *self);
void sysprof_line_visualizer_add_counter (SysprofLineVisualizer *self,
guint counter_id,
const GdkRGBA *color);
void sysprof_line_visualizer_set_line_width (SysprofLineVisualizer *self,
guint counter_id,
gdouble width);
void sysprof_line_visualizer_set_fill (SysprofLineVisualizer *self,
guint counter_id,
const GdkRGBA *color);
void sysprof_line_visualizer_set_dash (SysprofLineVisualizer *self,
guint counter_id,
gboolean use_dash);
G_END_DECLS

View File

@ -0,0 +1,237 @@
/* sysprof-logs-aid.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-logs-aid"
#include "config.h"
#include <glib/gi18n.h>
#include "sysprof-color-cycle.h"
#include "sysprof-logs-aid.h"
#include "sysprof-logs-page.h"
#include "sysprof-mark-visualizer.h"
struct _SysprofLogsAid
{
SysprofAid parent_instance;
};
typedef struct
{
SysprofDisplay *display;
SysprofCaptureCursor *cursor;
GArray *log_marks;
} Present;
G_DEFINE_TYPE (SysprofLogsAid, sysprof_logs_aid, SYSPROF_TYPE_AID)
static void
present_free (gpointer data)
{
Present *p = data;
g_clear_pointer (&p->log_marks, g_array_unref);
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
g_clear_object (&p->display);
g_slice_free (Present, p);
}
static void
on_group_activated_cb (SysprofVisualizerGroup *group,
SysprofPage *page)
{
SysprofDisplay *display;
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
g_assert (SYSPROF_IS_PAGE (page));
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
sysprof_display_set_visible_page (display, page);
}
/**
* sysprof_logs_aid_new:
*
* Create a new #SysprofLogsAid.
*
* Returns: (transfer full): a newly created #SysprofLogsAid
*/
SysprofAid *
sysprof_logs_aid_new (void)
{
return g_object_new (SYSPROF_TYPE_LOGS_AID, NULL);
}
static gboolean
find_marks_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
Present *p = user_data;
g_assert (frame != NULL);
g_assert (p != NULL);
if (frame->type == SYSPROF_CAPTURE_FRAME_LOG)
{
SysprofMarkTimeSpan span = { frame->time, frame->time };
g_array_append_val (p->log_marks, span);
}
return TRUE;
}
static gint
compare_span (const SysprofMarkTimeSpan *a,
const SysprofMarkTimeSpan *b)
{
if (a->kind < b->kind)
return -1;
if (b->kind < a->kind)
return 1;
if (a->begin < b->begin)
return -1;
if (b->begin < a->begin)
return 1;
if (b->end > a->end)
return -1;
return 0;
}
static void
sysprof_logs_aid_present_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
Present *p = task_data;
g_assert (G_IS_TASK (task));
g_assert (p != NULL);
g_assert (SYSPROF_IS_DISPLAY (p->display));
g_assert (p->cursor != NULL);
g_assert (SYSPROF_IS_LOGS_AID (source_object));
sysprof_capture_cursor_foreach (p->cursor, find_marks_cb, p);
g_array_sort (p->log_marks, (GCompareFunc)compare_span);
g_task_return_boolean (task, TRUE);
}
static void
sysprof_logs_aid_present_async (SysprofAid *aid,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
static const SysprofCaptureFrameType logs[] = {
SYSPROF_CAPTURE_FRAME_LOG,
};
SysprofLogsAid *self = (SysprofLogsAid *)aid;
g_autoptr(GTask) task = NULL;
Present p = {0};
g_assert (SYSPROF_IS_LOGS_AID (self));
p.display = g_object_ref (display);
p.log_marks = g_array_new (FALSE, FALSE, sizeof (SysprofMarkTimeSpan));
p.cursor = sysprof_capture_cursor_new (reader);
sysprof_capture_cursor_add_condition (p.cursor,
sysprof_capture_condition_new_where_type_in (1, logs));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_logs_aid_present_async);
g_task_set_task_data (task,
g_slice_dup (Present, &p),
present_free);
g_task_run_in_thread (task, sysprof_logs_aid_present_worker);
}
static gboolean
sysprof_logs_aid_present_finish (SysprofAid *aid,
GAsyncResult *result,
GError **error)
{
Present *p;
g_assert (SYSPROF_IS_LOGS_AID (aid));
g_assert (G_IS_TASK (result));
p = g_task_get_task_data (G_TASK (result));
if (p->log_marks->len > 0)
{
g_autoptr(GHashTable) items = NULL;
SysprofVisualizerGroup *group;
SysprofVisualizer *marks;
SysprofPage *page;
items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_array_unref);
g_hash_table_insert (items, g_strdup (_("Logs")), g_array_ref (p->log_marks));
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
"can-focus", TRUE,
"title", _("Logs"),
"visible", TRUE,
NULL);
marks = sysprof_mark_visualizer_new (items);
sysprof_visualizer_set_title (marks, _("Logs"));
gtk_widget_show (GTK_WIDGET (marks));
sysprof_visualizer_group_insert (group, marks, 0, FALSE);
sysprof_display_add_group (p->display, group);
page = g_object_new (SYSPROF_TYPE_LOGS_PAGE,
"title", _("Logs"),
"visible", TRUE,
NULL);
sysprof_display_add_page (p->display, page);
g_signal_connect_object (group,
"group-activated",
G_CALLBACK (on_group_activated_cb),
page,
0);
}
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
sysprof_logs_aid_class_init (SysprofLogsAidClass *klass)
{
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
aid_class->present_async = sysprof_logs_aid_present_async;
aid_class->present_finish = sysprof_logs_aid_present_finish;
}
static void
sysprof_logs_aid_init (SysprofLogsAid *self)
{
}

View File

@ -0,0 +1,33 @@
/* sysprof-logs-aid.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "sysprof-aid.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_LOGS_AID (sysprof_logs_aid_get_type())
G_DECLARE_FINAL_TYPE (SysprofLogsAid, sysprof_logs_aid, SYSPROF, LOGS_AID, SysprofAid)
SysprofAid *sysprof_logs_aid_new (void);
G_END_DECLS

View File

@ -0,0 +1,116 @@
/* sysprof-logs-page.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-logs-page"
#include "config.h"
#include "sysprof-log-model.h"
#include "sysprof-logs-page.h"
struct _SysprofLogsPage
{
SysprofPage parent_instance;
/* Template Widgets */
GtkTreeView *tree_view;
};
G_DEFINE_TYPE (SysprofLogsPage, sysprof_logs_page, SYSPROF_TYPE_PAGE)
static void
sysprof_logs_page_load_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofLogsPage *self;
g_autoptr(SysprofLogModel) model = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GTask) task = user_data;
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task));
if (!(model = sysprof_log_model_new_finish (result, &error)))
g_task_return_error (task, g_steal_pointer (&error));
else
g_task_return_boolean (task, TRUE);
self = g_task_get_source_object (task);
gtk_tree_view_set_model (self->tree_view, GTK_TREE_MODEL (model));
}
static void
sysprof_logs_page_load_async (SysprofPage *page,
SysprofCaptureReader *reader,
SysprofSelection *selection,
SysprofCaptureCondition *filter,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
SysprofLogsPage *self = (SysprofLogsPage *)page;
g_autoptr(GTask) task = NULL;
g_assert (SYSPROF_IS_LOGS_PAGE (self));
g_assert (reader != NULL);
g_assert (!selection || SYSPROF_IS_SELECTION (selection));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_logs_page_load_async);
sysprof_log_model_new_async (reader,
selection,
cancellable,
sysprof_logs_page_load_cb,
g_steal_pointer (&task));
}
static gboolean
sysprof_logs_page_load_finish (SysprofPage *page,
GAsyncResult *result,
GError **error)
{
g_assert (SYSPROF_IS_LOGS_PAGE (page));
g_assert (G_IS_TASK (result));
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
sysprof_logs_page_class_init (SysprofLogsPageClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
SysprofPageClass *page_class = SYSPROF_PAGE_CLASS (klass);
page_class->load_async = sysprof_logs_page_load_async;
page_class->load_finish = sysprof_logs_page_load_finish;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-logs-page.ui");
gtk_widget_class_bind_template_child (widget_class, SysprofLogsPage, tree_view);
}
static void
sysprof_logs_page_init (SysprofLogsPage *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}

View File

@ -1,6 +1,6 @@
/* sysprof-visualizer-row-private.h
/* sysprof-logs-page.h
*
* Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -20,10 +20,12 @@
#pragma once
#include "sysprof-visualizer-row.h"
#include "sysprof-page.h"
G_BEGIN_DECLS
gint _sysprof_visualizer_row_get_graph_width (SysprofVisualizerRow *self);
#define SYSPROF_TYPE_LOGS_PAGE (sysprof_logs_page_get_type())
G_DECLARE_FINAL_TYPE (SysprofLogsPage, sysprof_logs_page, SYSPROF, LOGS_PAGE, SysprofPage)
G_END_DECLS

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SysprofLogsPage" parent="SysprofPage">
<child>
<object class="GtkScrolledWindow">
<property name="visible">true</property>
<child>
<object class="GtkTreeView" id="tree_view">
<property name="tooltip-column">3</property>
<property name="headers-visible">true</property>
<property name="visible">true</property>
<child>
<object class="GtkTreeViewColumn">
<property name="expand">false</property>
<property name="title" translatable="yes">Time</property>
<child>
<object class="GtkCellRendererText">
<property name="xalign">0.0</property>
</object>
<attributes>
<attribute name="text">4</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="expand">false</property>
<property name="title" translatable="yes">Severity</property>
<child>
<object class="GtkCellRendererText">
<property name="xalign">0.0</property>
</object>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="expand">false</property>
<property name="resizable">true</property>
<property name="title" translatable="yes">Domain</property>
<child>
<object class="GtkCellRendererText">
<property name="xalign">0.0</property>
</object>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="expand">true</property>
<property name="title" translatable="yes">Message</property>
<child>
<object class="GtkCellRendererText">
<property name="ellipsize">end</property>
<property name="xalign">0.0</property>
</object>
<attributes>
<attribute name="text">3</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@ -1,492 +0,0 @@
/* sysprof-mark-visualizer-row.c
*
* Copyright 2018-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-mark-visualizer-row"
#include "config.h"
#include <string.h>
#include "sysprof-capture-condition.h"
#include "sysprof-capture-cursor.h"
#include "rectangles.h"
#include "sysprof-mark-visualizer-row.h"
typedef struct
{
/*
* Our reader as assigned by the visualizer system.
*/
SysprofCaptureReader *reader;
/*
* The group we care about for displaying marks. The idea is that we only
* show one group per-row, so tooling from separate systems can either be
* displayed together or not, based on usefulness.
*/
gchar *group;
/*
* Rectangle information we have built from the marks that belong to this
* row of information.
*/
Rectangles *rectangles;
/*
* Child widget to display the label in the upper corner.
*/
GtkLabel *label;
} SysprofMarkVisualizerRowPrivate;
typedef struct
{
gchar *group;
SysprofCaptureCursor *cursor;
Rectangles *rects;
GHashTable *inferred_rects;
} BuildState;
typedef struct {
gint64 time;
gchar *name;
gchar *message;
} InferredRect;
enum {
PROP_0,
PROP_GROUP,
PROP_TITLE,
N_PROPS
};
G_DEFINE_TYPE_WITH_PRIVATE (SysprofMarkVisualizerRow, sysprof_mark_visualizer_row, SYSPROF_TYPE_VISUALIZER_ROW)
static GParamSpec *properties [N_PROPS];
static void
free_inferred_rect (InferredRect *rect)
{
g_free (rect->name);
g_free (rect->message);
g_slice_free (InferredRect, rect);
}
static void
add_inferred_rect_point (BuildState *state,
InferredRect *rect)
{
rectangles_add (state->rects,
rect->time,
rect->time,
rect->name,
rect->message);
}
static void
build_state_free (BuildState *state)
{
g_hash_table_remove_all (state->inferred_rects);
g_clear_pointer (&state->inferred_rects, g_hash_table_unref);
g_free (state->group);
g_clear_pointer (&state->cursor, sysprof_capture_cursor_unref);
g_slice_free (BuildState, state);
}
/* Creates rectangles for GPU marks.
*
* GPU marks come in as a begin and an end, but since those things are
* processessed on potentially different CPUs, perf doesn't record
* them in sequence order in the mmap ringbuffer. Thus, we have to
* shuffle things back around at visualization time.
*/
static gboolean
process_gpu_mark (BuildState *state,
const SysprofCaptureMark *mark)
{
InferredRect *rect = g_hash_table_lookup (state->inferred_rects,
mark->message);
if (rect)
{
gboolean ours_begins = strstr (mark->name, "begin") != NULL;
gboolean theirs_begins = strstr (rect->name, "begin") != NULL;
if (ours_begins != theirs_begins)
{
rectangles_add (state->rects,
ours_begins ? mark->frame.time : rect->time,
ours_begins ? rect->time : mark->frame.time,
ours_begins ? mark->name : rect->name,
rect->message);
}
else
{
/* Something went weird with the tracking (GPU hang caused
* two starts?), so just put up both time points as vertical
* bars for now.
*/
rectangles_add (state->rects,
mark->frame.time,
mark->frame.time,
mark->name,
mark->message);
add_inferred_rect_point (state, rect);
}
g_hash_table_remove (state->inferred_rects,
rect->message);
}
else
{
rect = g_slice_new0 (InferredRect);
rect->name = g_strdup (mark->name);
rect->message = g_strdup (mark->message);
rect->time = mark->frame.time;
g_hash_table_insert (state->inferred_rects, rect->message, rect);
}
return TRUE;
}
static gboolean
sysprof_mark_visualizer_row_add_rect (const SysprofCaptureFrame *frame,
gpointer user_data)
{
BuildState *state = user_data;
const SysprofCaptureMark *mark = (const SysprofCaptureMark *)frame;
g_assert (frame != NULL);
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_MARK);
g_assert (state != NULL);
g_assert (state->rects != NULL);
if (g_strcmp0 (mark->group, state->group) == 0)
{
if (strstr (mark->name, "gpu begin") != NULL ||
strstr (mark->name, "gpu end") != NULL)
process_gpu_mark (state, mark);
else
rectangles_add (state->rects,
frame->time,
frame->time + mark->duration,
mark->name,
mark->message);
}
return TRUE;
}
static void
sysprof_mark_visualizer_row_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
BuildState *state = task_data;
GHashTableIter iter;
gpointer key, value;
gint64 end_time;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_MARK_VISUALIZER_ROW (source_object));
g_assert (state != NULL);
g_assert (state->cursor != NULL);
sysprof_capture_cursor_foreach (state->cursor, sysprof_mark_visualizer_row_add_rect, state);
/* If any inferred rects are left incomplete, just drop them in as
* point events for now.
*/
g_hash_table_iter_init (&iter, state->inferred_rects);
while (g_hash_table_iter_next (&iter, &key, &value))
{
InferredRect *rect = value;
add_inferred_rect_point (state, rect);
}
g_hash_table_remove_all (state->inferred_rects);
end_time = sysprof_capture_reader_get_end_time (sysprof_capture_cursor_get_reader (state->cursor));
rectangles_set_end_time (state->rects, end_time);
g_task_return_pointer (task, g_steal_pointer (&state->rects), (GDestroyNotify)rectangles_free);
}
static gboolean
sysprof_mark_visualizer_row_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_mode,
GtkTooltip *tooltip)
{
SysprofMarkVisualizerRow *self = (SysprofMarkVisualizerRow *)widget;
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
g_assert (SYSPROF_IS_MARK_VISUALIZER_ROW (self));
if (priv->rectangles == NULL)
return FALSE;
return rectangles_query_tooltip (priv->rectangles, tooltip, priv->group, x, y);
}
static gboolean
sysprof_mark_visualizer_row_draw (GtkWidget *widget,
cairo_t *cr)
{
SysprofMarkVisualizerRow *self = (SysprofMarkVisualizerRow *)widget;
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
GtkStyleContext *style_context;
GtkStateFlags flags;
GdkRGBA foreground;
GtkAllocation alloc;
gboolean ret;
g_assert (SYSPROF_IS_MARK_VISUALIZER_ROW (widget));
g_assert (cr != NULL);
gtk_widget_get_allocation (widget, &alloc);
ret = GTK_WIDGET_CLASS (sysprof_mark_visualizer_row_parent_class)->draw (widget, cr);
if (priv->rectangles == NULL)
return ret;
style_context = gtk_widget_get_style_context (widget);
flags = gtk_widget_get_state_flags (widget);
gtk_style_context_get_color (style_context, flags, &foreground);
rectangles_draw (priv->rectangles, GTK_WIDGET (self), cr);
return ret;
}
static void
data_load_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofMarkVisualizerRow *self = (SysprofMarkVisualizerRow *)object;
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
g_assert (SYSPROF_IS_MARK_VISUALIZER_ROW (self));
g_assert (G_IS_TASK (result));
g_clear_pointer (&priv->rectangles, rectangles_free);
priv->rectangles = g_task_propagate_pointer (G_TASK (result), NULL);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
sysprof_mark_visualizer_row_reload (SysprofMarkVisualizerRow *self)
{
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
g_autoptr(SysprofCaptureCursor) cursor = NULL;
g_autoptr(GTask) task = NULL;
SysprofCaptureCondition *condition;
BuildState *state;
g_assert (SYSPROF_IS_MARK_VISUALIZER_ROW (self));
g_clear_pointer (&priv->rectangles, rectangles_free);
condition = sysprof_capture_condition_new_where_type_in (1, (SysprofCaptureFrameType[]) { SYSPROF_CAPTURE_FRAME_MARK });
cursor = sysprof_capture_cursor_new (priv->reader);
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
state = g_slice_new0 (BuildState);
state->inferred_rects = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
(GDestroyNotify)free_inferred_rect);
state->group = g_strdup (priv->group);
state->cursor = g_steal_pointer (&cursor);
state->rects = rectangles_new (sysprof_capture_reader_get_start_time (priv->reader),
sysprof_capture_reader_get_end_time (priv->reader));
task = g_task_new (self, NULL, data_load_cb, NULL);
g_task_set_task_data (task, state, (GDestroyNotify)build_state_free);
g_task_run_in_thread (task, sysprof_mark_visualizer_row_worker);
}
static void
sysprof_mark_visualizer_row_set_reader (SysprofVisualizerRow *row,
SysprofCaptureReader *reader)
{
SysprofMarkVisualizerRow *self = (SysprofMarkVisualizerRow *)row;
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
g_assert (SYSPROF_IS_MARK_VISUALIZER_ROW (self));
if (reader != priv->reader)
{
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
if (reader != NULL)
priv->reader = sysprof_capture_reader_ref (reader);
sysprof_mark_visualizer_row_reload (self);
}
}
static void
sysprof_mark_visualizer_row_finalize (GObject *object)
{
SysprofMarkVisualizerRow *self = (SysprofMarkVisualizerRow *)object;
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
g_clear_pointer (&priv->group, g_free);
g_clear_pointer (&priv->rectangles, rectangles_free);
G_OBJECT_CLASS (sysprof_mark_visualizer_row_parent_class)->finalize (object);
}
static void
sysprof_mark_visualizer_row_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofMarkVisualizerRow *self = SYSPROF_MARK_VISUALIZER_ROW (object);
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
switch (prop_id)
{
case PROP_GROUP:
g_value_set_string (value, sysprof_mark_visualizer_row_get_group (self));
break;
case PROP_TITLE:
g_value_set_string (value, gtk_label_get_label (priv->label));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_mark_visualizer_row_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofMarkVisualizerRow *self = SYSPROF_MARK_VISUALIZER_ROW (object);
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
switch (prop_id)
{
case PROP_GROUP:
sysprof_mark_visualizer_row_set_group (self, g_value_get_string (value));
break;
case PROP_TITLE:
gtk_label_set_label (priv->label, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_mark_visualizer_row_class_init (SysprofMarkVisualizerRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
SysprofVisualizerRowClass *visualizer_class = SYSPROF_VISUALIZER_ROW_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = sysprof_mark_visualizer_row_finalize;
object_class->get_property = sysprof_mark_visualizer_row_get_property;
object_class->set_property = sysprof_mark_visualizer_row_set_property;
widget_class->draw = sysprof_mark_visualizer_row_draw;
widget_class->query_tooltip = sysprof_mark_visualizer_row_query_tooltip;
visualizer_class->set_reader = sysprof_mark_visualizer_row_set_reader;
properties [PROP_GROUP] =
g_param_spec_string ("group",
"Group",
"The group of the row",
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties [PROP_TITLE] =
g_param_spec_string ("title",
"Title",
"The title of the row",
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
sysprof_mark_visualizer_row_init (SysprofMarkVisualizerRow *self)
{
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
PangoAttrList *attrs = pango_attr_list_new ();
gtk_widget_set_has_tooltip (GTK_WIDGET (self), TRUE);
pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL * PANGO_SCALE_SMALL));
priv->label = g_object_new (GTK_TYPE_LABEL,
"attributes", attrs,
"visible", TRUE,
"xalign", 0.0f,
"yalign", 0.0f,
NULL);
gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (priv->label));
pango_attr_list_unref (attrs);
}
GtkWidget *
sysprof_mark_visualizer_row_new (void)
{
return g_object_new (SYSPROF_TYPE_MARK_VISUALIZER_ROW, NULL);
}
const gchar *
sysprof_mark_visualizer_row_get_group (SysprofMarkVisualizerRow *self)
{
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_MARK_VISUALIZER_ROW (self), NULL);
return priv->group;
}
void
sysprof_mark_visualizer_row_set_group (SysprofMarkVisualizerRow *self,
const gchar *group)
{
SysprofMarkVisualizerRowPrivate *priv = sysprof_mark_visualizer_row_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_MARK_VISUALIZER_ROW (self));
if (g_strcmp0 (priv->group, group) != 0)
{
g_free (priv->group);
priv->group = g_strdup (group);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_GROUP]);
}
}

View File

@ -1,53 +0,0 @@
/* sysprof-mark-visualizer-row.h
*
* Copyright 2018-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include "sysprof-visualizer-row.h"
#include "sysprof-version-macros.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_MARK_VISUALIZER_ROW (sysprof_mark_visualizer_row_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofMarkVisualizerRow, sysprof_mark_visualizer_row, SYSPROF, MARK_VISUALIZER_ROW, SysprofVisualizerRow)
struct _SysprofMarkVisualizerRowClass
{
SysprofVisualizerRowClass parent_class;
/*< private >*/
gpointer _reserved[16];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_mark_visualizer_row_new (void);
SYSPROF_AVAILABLE_IN_ALL
const gchar *sysprof_mark_visualizer_row_get_group (SysprofMarkVisualizerRow *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_mark_visualizer_row_set_group (SysprofMarkVisualizerRow *self,
const gchar *group);
G_END_DECLS

View File

@ -0,0 +1,287 @@
/* sysprof-mark-visualizer.c
*
* Copyright 2018-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-mark-visualizer"
#include "config.h"
#include "sysprof-mark-visualizer.h"
#define RECT_HEIGHT (4)
#define RECT_MIN_WIDTH (3)
#define RECT_OVERLAP (-1)
struct _SysprofMarkVisualizer
{
SysprofVisualizer parent_instance;
GHashTable *spans_by_group;
GHashTable *rgba_by_group;
GHashTable *rgba_by_kind;
GHashTable *row_by_kind;
guint x_is_dirty : 1;
};
G_DEFINE_TYPE (SysprofMarkVisualizer, sysprof_mark_visualizer, SYSPROF_TYPE_VISUALIZER)
static void
reset_positions (SysprofMarkVisualizer *self)
{
g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
self->x_is_dirty = TRUE;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
SysprofVisualizer *
sysprof_mark_visualizer_new (GHashTable *groups)
{
SysprofMarkVisualizer *self;
guint n_items;
gint height;
g_return_val_if_fail (groups != NULL, NULL);
self = g_object_new (SYSPROF_TYPE_MARK_VISUALIZER, NULL);
self->spans_by_group = g_hash_table_ref (groups);
reset_positions (self);
n_items = g_hash_table_size (groups);
height = MAX (35, n_items * (RECT_HEIGHT - RECT_OVERLAP));
gtk_widget_set_size_request (GTK_WIDGET (self), -1, height);
return SYSPROF_VISUALIZER (g_steal_pointer (&self));
}
static gboolean
sysprof_mark_visualizer_draw (GtkWidget *widget,
cairo_t *cr)
{
SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)widget;
SysprofVisualizer *vis = (SysprofVisualizer *)widget;
GHashTableIter iter;
GtkAllocation alloc;
gpointer k, v;
gboolean ret;
gint n_groups = 0;
gint y = 0;
g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
g_assert (cr != NULL);
ret = GTK_WIDGET_CLASS (sysprof_mark_visualizer_parent_class)->draw (widget, cr);
if (self->spans_by_group == NULL)
return ret;
gtk_widget_get_allocation (widget, &alloc);
/* Pre-calculate all time slots so we can join later */
if (self->x_is_dirty)
{
g_hash_table_iter_init (&iter, self->spans_by_group);
while (g_hash_table_iter_next (&iter, &k, &v))
{
const GArray *spans = v;
for (guint i = 0; i < spans->len; i++)
{
SysprofMarkTimeSpan *span = &g_array_index (spans, SysprofMarkTimeSpan, i);
span->x = sysprof_visualizer_get_x_for_time (vis, span->begin);
span->x2 = sysprof_visualizer_get_x_for_time (vis, span->end);
}
}
self->x_is_dirty = FALSE;
}
n_groups = g_hash_table_size (self->spans_by_group);
g_hash_table_iter_init (&iter, self->spans_by_group);
while (g_hash_table_iter_next (&iter, &k, &v))
{
static const GdkRGBA black = {0, 0, 0, 1};
SysprofMarkTimeSpan *span;
const gchar *group = k;
const GArray *spans = v;
const GdkRGBA *rgba;
const GdkRGBA *kindrgba;
const GdkRGBA *grouprgba;
if ((grouprgba = g_hash_table_lookup (self->rgba_by_group, group)))
{
rgba = grouprgba;
gdk_cairo_set_source_rgba (cr, rgba);
}
for (guint i = 0; i < spans->len; i++)
{
gint x1, x2;
span = &g_array_index (spans, SysprofMarkTimeSpan, i);
if (n_groups == 1)
{
rgba = &black;
if ((kindrgba = g_hash_table_lookup (self->rgba_by_kind, GUINT_TO_POINTER (span->kind))))
rgba = kindrgba;
else if ((grouprgba = g_hash_table_lookup (self->rgba_by_group, group)))
rgba = grouprgba;
gdk_cairo_set_source_rgba (cr, rgba);
}
x1 = span->x;
x2 = x1 + RECT_MIN_WIDTH;
if (span->x2 > x2)
x2 = span->x2;
/* If we are limited to one group, we might need to get the row
* height for the kind of span this is.
*/
if (n_groups == 1)
{
gint row = GPOINTER_TO_INT (g_hash_table_lookup (self->row_by_kind, GUINT_TO_POINTER (span->kind)));
y = row * (RECT_HEIGHT - RECT_OVERLAP);
}
for (guint j = i + 1; j < spans->len; j++)
{
const SysprofMarkTimeSpan *next = &g_array_index (spans, SysprofMarkTimeSpan, j);
/* Don't join this if we are about to draw a different kind */
if (n_groups == 1 && next->kind != span->kind)
break;
if (next->x <= x2)
{
x2 = MAX (x2, next->x2);
i++;
continue;
}
break;
}
cairo_rectangle (cr, x1, y, x2 - x1, RECT_HEIGHT);
if (n_groups == 1)
cairo_fill (cr);
}
if (n_groups > 1)
cairo_fill (cr);
y += RECT_HEIGHT + RECT_OVERLAP;
}
return ret;
}
static void
sysprof_mark_visualizer_size_allocate (GtkWidget *widget,
GtkAllocation *alloc)
{
SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)widget;
g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
g_assert (alloc != NULL);
GTK_WIDGET_CLASS (sysprof_mark_visualizer_parent_class)->size_allocate (widget, alloc);
reset_positions (self);
}
static void
sysprof_mark_visualizer_finalize (GObject *object)
{
SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)object;
g_clear_pointer (&self->spans_by_group, g_hash_table_unref);
g_clear_pointer (&self->rgba_by_group, g_hash_table_unref);
g_clear_pointer (&self->rgba_by_kind, g_hash_table_unref);
g_clear_pointer (&self->row_by_kind, g_hash_table_unref);
G_OBJECT_CLASS (sysprof_mark_visualizer_parent_class)->finalize (object);
}
static void
sysprof_mark_visualizer_class_init (SysprofMarkVisualizerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = sysprof_mark_visualizer_finalize;
widget_class->draw = sysprof_mark_visualizer_draw;
widget_class->size_allocate = sysprof_mark_visualizer_size_allocate;
}
static void
sysprof_mark_visualizer_init (SysprofMarkVisualizer *self)
{
self->rgba_by_kind = g_hash_table_new_full (NULL, NULL, NULL, g_free);
self->row_by_kind = g_hash_table_new (NULL, NULL);
self->rgba_by_group = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
}
void
sysprof_mark_visualizer_set_group_rgba (SysprofMarkVisualizer *self,
const gchar *group,
const GdkRGBA *rgba)
{
g_return_if_fail (SYSPROF_IS_MARK_VISUALIZER (self));
g_return_if_fail (group != NULL);
g_hash_table_insert (self->rgba_by_group,
g_strdup (group),
g_memdup (rgba, sizeof *rgba));
}
void
sysprof_mark_visualizer_set_kind_rgba (SysprofMarkVisualizer *self,
GHashTable *rgba_by_kind)
{
g_return_if_fail (SYSPROF_IS_MARK_VISUALIZER (self));
if (rgba_by_kind != self->rgba_by_kind)
{
g_hash_table_remove_all (self->row_by_kind);
g_clear_pointer (&self->rgba_by_kind, g_hash_table_unref);
if (rgba_by_kind)
{
GHashTableIter iter;
guint row = 0;
gpointer k;
self->rgba_by_kind = g_hash_table_ref (rgba_by_kind);
g_hash_table_iter_init (&iter, rgba_by_kind);
while (g_hash_table_iter_next (&iter, &k, NULL))
g_hash_table_insert (self->row_by_kind, k, GUINT_TO_POINTER (row++));
gtk_widget_set_size_request (GTK_WIDGET (self),
-1,
MAX (35, row * (RECT_HEIGHT - RECT_OVERLAP)));
}
}
}

View File

@ -0,0 +1,47 @@
/* sysprof-mark-visualizer.h
*
* Copyright 2018-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "sysprof-visualizer.h"
G_BEGIN_DECLS
typedef struct
{
gint64 begin;
gint64 end;
guint kind;
gint x;
gint x2;
} SysprofMarkTimeSpan;
#define SYSPROF_TYPE_MARK_VISUALIZER (sysprof_mark_visualizer_get_type())
G_DECLARE_FINAL_TYPE (SysprofMarkVisualizer, sysprof_mark_visualizer, SYSPROF, MARK_VISUALIZER, SysprofVisualizer)
SysprofVisualizer *sysprof_mark_visualizer_new (GHashTable *groups);
void sysprof_mark_visualizer_set_group_rgba (SysprofMarkVisualizer *self,
const gchar *group,
const GdkRGBA *rgba);
void sysprof_mark_visualizer_set_kind_rgba (SysprofMarkVisualizer *self,
GHashTable *rgba_by_kind);
G_END_DECLS

View File

@ -0,0 +1,319 @@
/* sysprof-marks-aid.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-marks-aid"
#include "config.h"
#include <glib/gi18n.h>
#include "sysprof-color-cycle.h"
#include "sysprof-marks-aid.h"
#include "sysprof-marks-page.h"
#include "sysprof-mark-visualizer.h"
struct _SysprofMarksAid
{
SysprofAid parent_instance;
};
typedef struct
{
SysprofDisplay *display;
SysprofCaptureCursor *cursor;
GHashTable *categories;
GHashTable *kinds;
guint last_kind;
guint has_marks : 1;
} Present;
G_DEFINE_TYPE (SysprofMarksAid, sysprof_marks_aid, SYSPROF_TYPE_AID)
static void
present_free (gpointer data)
{
Present *p = data;
g_clear_pointer (&p->categories, g_hash_table_unref);
g_clear_pointer (&p->kinds, g_hash_table_unref);
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
g_clear_object (&p->display);
g_slice_free (Present, p);
}
static void
on_group_activated_cb (SysprofVisualizerGroup *group,
SysprofPage *page)
{
SysprofDisplay *display;
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
g_assert (SYSPROF_IS_PAGE (page));
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
sysprof_display_set_visible_page (display, page);
}
/**
* sysprof_marks_aid_new:
*
* Create a new #SysprofMarksAid.
*
* Returns: (transfer full): a newly created #SysprofMarksAid
*/
SysprofAid *
sysprof_marks_aid_new (void)
{
return g_object_new (SYSPROF_TYPE_MARKS_AID, NULL);
}
static gboolean
find_marks_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
Present *p = user_data;
g_assert (frame != NULL);
g_assert (p != NULL);
if (frame->type == SYSPROF_CAPTURE_FRAME_MARK)
{
const SysprofCaptureMark *mark = (const SysprofCaptureMark *)frame;
SysprofMarkTimeSpan span = { frame->time, frame->time + mark->duration };
gchar joined[64];
gpointer kptr;
GArray *items;
p->has_marks = TRUE;
if G_UNLIKELY (!(items = g_hash_table_lookup (p->categories, mark->group)))
{
items = g_array_new (FALSE, FALSE, sizeof (SysprofMarkTimeSpan));
g_hash_table_insert (p->categories, g_strdup (mark->group), items);
}
g_snprintf (joined, sizeof joined, "%s:%s", mark->group, mark->name);
if G_UNLIKELY (!(kptr = g_hash_table_lookup (p->kinds, joined)))
{
p->last_kind++;
kptr = GINT_TO_POINTER (p->last_kind);
g_hash_table_insert (p->kinds, g_strdup (joined), kptr);
}
span.kind = GPOINTER_TO_INT (kptr);
g_array_append_val (items, span);
}
return TRUE;
}
static gint
compare_span (const SysprofMarkTimeSpan *a,
const SysprofMarkTimeSpan *b)
{
if (a->kind < b->kind)
return -1;
if (b->kind < a->kind)
return 1;
if (a->begin < b->begin)
return -1;
if (b->begin < a->begin)
return 1;
if (b->end > a->end)
return -1;
return 0;
}
static void
sysprof_marks_aid_present_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
Present *p = task_data;
GHashTableIter iter;
gpointer k, v;
g_assert (G_IS_TASK (task));
g_assert (p != NULL);
g_assert (SYSPROF_IS_DISPLAY (p->display));
g_assert (p->cursor != NULL);
g_assert (SYSPROF_IS_MARKS_AID (source_object));
sysprof_capture_cursor_foreach (p->cursor, find_marks_cb, p);
g_hash_table_iter_init (&iter, p->categories);
while (g_hash_table_iter_next (&iter, &k, &v))
{
GArray *spans = v;
g_array_sort (spans, (GCompareFunc)compare_span);
}
g_task_return_boolean (task, TRUE);
}
static void
sysprof_marks_aid_present_async (SysprofAid *aid,
SysprofCaptureReader *reader,
SysprofDisplay *display,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
static const SysprofCaptureFrameType marks[] = {
SYSPROF_CAPTURE_FRAME_MARK,
};
SysprofMarksAid *self = (SysprofMarksAid *)aid;
g_autoptr(GTask) task = NULL;
Present p = {0};
g_assert (SYSPROF_IS_MARKS_AID (self));
p.display = g_object_ref (display);
p.categories = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_array_unref);
p.kinds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
p.cursor = sysprof_capture_cursor_new (reader);
sysprof_capture_cursor_add_condition (p.cursor,
sysprof_capture_condition_new_where_type_in (1, marks));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_marks_aid_present_async);
g_task_set_task_data (task,
g_slice_dup (Present, &p),
present_free);
g_task_run_in_thread (task, sysprof_marks_aid_present_worker);
}
static gboolean
sysprof_marks_aid_present_finish (SysprofAid *aid,
GAsyncResult *result,
GError **error)
{
Present *p;
g_assert (SYSPROF_IS_MARKS_AID (aid));
g_assert (G_IS_TASK (result));
p = g_task_get_task_data (G_TASK (result));
if (p->has_marks)
{
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
SysprofVisualizerGroup *group;
SysprofVisualizer *marks;
SysprofPage *page;
GHashTableIter iter;
gpointer k, v;
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
"can-focus", TRUE,
"has-page", TRUE,
"title", _("Timings"),
"visible", TRUE,
NULL);
marks = sysprof_mark_visualizer_new (p->categories);
sysprof_visualizer_set_title (marks, _("Timings"));
gtk_widget_show (GTK_WIDGET (marks));
g_hash_table_iter_init (&iter, p->categories);
while (g_hash_table_iter_next (&iter, &k, &v))
{
g_autoptr(GHashTable) seen = g_hash_table_new_full (NULL, NULL, NULL, g_free);
g_autoptr(GHashTable) scoped = NULL;
SysprofVisualizer *scoped_vis;
GArray *spans = v;
const gchar *name = k;
GdkRGBA rgba;
GdkRGBA kind_rgba;
gdouble ratio;
sysprof_color_cycle_next (cycle, &rgba);
sysprof_mark_visualizer_set_group_rgba (SYSPROF_MARK_VISUALIZER (marks), name, &rgba);
/* Now make a scoped row just for this group */
scoped = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify)g_array_unref);
g_hash_table_insert (scoped, g_strdup (name), g_array_ref (spans));
scoped_vis = sysprof_mark_visualizer_new (scoped);
sysprof_visualizer_set_title (scoped_vis, name);
sysprof_mark_visualizer_set_group_rgba (SYSPROF_MARK_VISUALIZER (scoped_vis), name, &rgba);
sysprof_visualizer_group_insert (group, scoped_vis, -1, TRUE);
ratio = .4 / p->last_kind;
for (guint i = 0; i < spans->len; i++)
{
const SysprofMarkTimeSpan *span = &g_array_index (spans, SysprofMarkTimeSpan, i);
if (!g_hash_table_contains (seen, GUINT_TO_POINTER (span->kind)))
{
dzl_rgba_shade (&rgba, &kind_rgba, 1 + (ratio * span->kind));
g_hash_table_insert (seen,
GUINT_TO_POINTER (span->kind),
g_memdup (&kind_rgba, sizeof kind_rgba));
}
}
sysprof_mark_visualizer_set_kind_rgba (SYSPROF_MARK_VISUALIZER (scoped_vis), seen);
}
page = g_object_new (SYSPROF_TYPE_MARKS_PAGE,
"zoom-manager", sysprof_display_get_zoom_manager (p->display),
"visible", TRUE,
NULL);
g_signal_connect_object (group,
"group-activated",
G_CALLBACK (on_group_activated_cb),
page,
0);
sysprof_visualizer_group_insert (group, marks, 0, FALSE);
sysprof_display_add_group (p->display, group);
sysprof_display_add_page (p->display, page);
}
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
sysprof_marks_aid_class_init (SysprofMarksAidClass *klass)
{
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
aid_class->present_async = sysprof_marks_aid_present_async;
aid_class->present_finish = sysprof_marks_aid_present_finish;
}
static void
sysprof_marks_aid_init (SysprofMarksAid *self)
{
}

View File

@ -0,0 +1,33 @@
/* sysprof-marks-aid.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "sysprof-aid.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_MARKS_AID (sysprof_marks_aid_get_type())
G_DECLARE_FINAL_TYPE (SysprofMarksAid, sysprof_marks_aid, SYSPROF, MARKS_AID, SysprofAid)
SysprofAid *sysprof_marks_aid_new (void);
G_END_DECLS

View File

@ -1,4 +1,4 @@
/* sysprof-marks-view.c
/* sysprof-marks-page.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
@ -18,13 +18,13 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-marks-view"
#define G_LOG_DOMAIN "sysprof-marks-page"
#include "config.h"
#include "sysprof-cell-renderer-duration.h"
#include "sysprof-marks-model.h"
#include "sysprof-marks-view.h"
#include "sysprof-marks-page.h"
#include "sysprof-ui-private.h"
#include "sysprof-zoom-manager.h"
@ -42,10 +42,16 @@ typedef struct
/* Template objects */
GtkScrolledWindow *scroller;
GtkTreeView *tree_view;
GtkBox *details_box;
GtkTreeViewColumn *duration_column;
SysprofCellRendererDuration *duration_cell;
GtkStack *stack;
} SysprofMarksViewPrivate;
GtkLabel *group;
GtkLabel *mark;
GtkLabel *time;
GtkLabel *duration;
GtkTextView *message;
} SysprofMarksPagePrivate;
enum {
PROP_0,
@ -56,17 +62,17 @@ enum {
static GParamSpec *properties [N_PROPS];
G_DEFINE_TYPE_WITH_PRIVATE (SysprofMarksView, sysprof_marks_view, GTK_TYPE_BIN)
G_DEFINE_TYPE_WITH_PRIVATE (SysprofMarksPage, sysprof_marks_page, SYSPROF_TYPE_PAGE)
static gboolean
sysprof_marks_view_tree_view_key_press_event_cb (SysprofMarksView *self,
sysprof_marks_page_tree_view_key_press_event_cb (SysprofMarksPage *self,
const GdkEventKey *key,
GtkTreeView *tree_view)
{
SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self);
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
gint dir = 0;
g_assert (SYSPROF_MARKS_VIEW (self));
g_assert (SYSPROF_MARKS_PAGE (self));
g_assert (key != NULL);
if (key->state == 0)
@ -127,21 +133,29 @@ get_first_selected (GtkTreeSelection *selection,
}
static void
sysprof_marks_view_selection_changed_cb (SysprofMarksView *self,
sysprof_marks_page_selection_changed_cb (SysprofMarksPage *self,
GtkTreeSelection *selection)
{
SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self);
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
GtkTreeModel *model;
GtkTreeIter iter;
g_assert (SYSPROF_IS_MARKS_VIEW (self));
g_assert (SYSPROF_IS_MARKS_PAGE (self));
g_assert (GTK_IS_TREE_SELECTION (selection));
if (get_first_selected (selection, &model, &iter))
{
g_autofree gchar *group = NULL;
g_autofree gchar *name = NULL;
g_autofree gchar *duration_str = NULL;
g_autofree gchar *time_str = NULL;
g_autofree gchar *text = NULL;
GtkAdjustment *adj;
gdouble x;
gint64 begin_time;
gint64 end_time;
gint64 duration;
gint64 otime;
gdouble lower;
gdouble upper;
gdouble value;
@ -149,9 +163,26 @@ sysprof_marks_view_selection_changed_cb (SysprofMarksView *self,
gint width;
gtk_tree_model_get (model, &iter,
SYSPROF_MARKS_MODEL_COLUMN_GROUP, &group,
SYSPROF_MARKS_MODEL_COLUMN_NAME, &name,
SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME, &begin_time,
SYSPROF_MARKS_MODEL_COLUMN_END_TIME, &end_time,
SYSPROF_MARKS_MODEL_COLUMN_TEXT, &text,
-1);
duration = end_time - begin_time;
duration_str = _sysprof_format_duration (duration);
otime = begin_time - priv->capture_begin_time;
time_str = _sysprof_format_duration (otime);
gtk_label_set_label (priv->group, group);
gtk_label_set_label (priv->mark, name);
gtk_label_set_label (priv->duration, duration_str);
gtk_label_set_label (priv->time, time_str);
gtk_text_buffer_set_text (gtk_text_view_get_buffer (priv->message), text, -1);
adj = gtk_scrolled_window_get_hadjustment (priv->scroller);
width = gtk_tree_view_column_get_width (priv->duration_column);
x = sysprof_zoom_manager_get_offset_at_time (priv->zoom_manager,
@ -173,19 +204,19 @@ sysprof_marks_view_selection_changed_cb (SysprofMarksView *self,
}
static gboolean
sysprof_marks_view_tree_view_query_tooltip_cb (SysprofMarksView *self,
sysprof_marks_page_tree_view_query_tooltip_cb (SysprofMarksPage *self,
gint x,
gint y,
gboolean keyboard_mode,
GtkTooltip *tooltip,
GtkTreeView *tree_view)
{
SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self);
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
g_autoptr(GtkTreePath) path = NULL;
GtkTreeViewColumn *column;
gint cell_x, cell_y;
g_assert (SYSPROF_IS_MARKS_VIEW (self));
g_assert (SYSPROF_IS_MARKS_PAGE (self));
g_assert (GTK_IS_TOOLTIP (tooltip));
g_assert (GTK_IS_TREE_VIEW (tree_view));
@ -229,162 +260,22 @@ sysprof_marks_view_tree_view_query_tooltip_cb (SysprofMarksView *self,
}
static void
sysprof_marks_view_finalize (GObject *object)
{
SysprofMarksView *self = (SysprofMarksView *)object;
SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self);
g_clear_object (&priv->zoom_manager);
G_OBJECT_CLASS (sysprof_marks_view_parent_class)->finalize (object);
}
static void
sysprof_marks_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofMarksView *self = SYSPROF_MARKS_VIEW (object);
SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self);
switch (prop_id)
{
case PROP_KIND:
g_value_set_enum (value, priv->kind);
break;
case PROP_ZOOM_MANAGER:
g_value_set_object (value, priv->zoom_manager);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_marks_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofMarksView *self = SYSPROF_MARKS_VIEW (object);
SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self);
switch (prop_id)
{
case PROP_KIND:
priv->kind = g_value_get_enum (value);
break;
case PROP_ZOOM_MANAGER:
if (g_set_object (&priv->zoom_manager, g_value_get_object (value)))
{
g_object_set (priv->duration_cell,
"zoom-manager", priv->zoom_manager,
NULL);
if (priv->zoom_manager)
g_signal_connect_object (priv->zoom_manager,
"notify::zoom",
G_CALLBACK (gtk_tree_view_column_queue_resize),
priv->duration_column,
G_CONNECT_SWAPPED);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_marks_view_class_init (SysprofMarksViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = sysprof_marks_view_finalize;
object_class->get_property = sysprof_marks_view_get_property;
object_class->set_property = sysprof_marks_view_set_property;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-marks-view.ui");
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksView, scroller);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksView, tree_view);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksView, duration_cell);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksView, duration_column);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksView, stack);
properties [PROP_KIND] =
g_param_spec_enum ("kind", NULL, NULL,
SYSPROF_TYPE_MARKS_MODEL_KIND,
SYSPROF_MARKS_MODEL_MARKS,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
properties [PROP_ZOOM_MANAGER] =
g_param_spec_object ("zoom-manager", NULL, NULL,
SYSPROF_TYPE_ZOOM_MANAGER,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
g_type_ensure (SYSPROF_TYPE_CELL_RENDERER_DURATION);
}
static void
sysprof_marks_view_init (SysprofMarksView *self)
{
SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self);
priv->kind = SYSPROF_MARKS_MODEL_MARKS;
gtk_widget_init_template (GTK_WIDGET (self));
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (priv->tree_view),
GTK_SELECTION_MULTIPLE);
g_signal_connect_object (priv->tree_view,
"key-press-event",
G_CALLBACK (sysprof_marks_view_tree_view_key_press_event_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->tree_view,
"query-tooltip",
G_CALLBACK (sysprof_marks_view_tree_view_query_tooltip_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (gtk_tree_view_get_selection (priv->tree_view),
"changed",
G_CALLBACK (sysprof_marks_view_selection_changed_cb),
self,
G_CONNECT_SWAPPED);
}
GtkWidget *
sysprof_marks_view_new (void)
{
return g_object_new (SYSPROF_TYPE_MARKS_VIEW, NULL);
}
static void
sysprof_marks_view_load_cb (GObject *object,
sysprof_marks_page_load_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(SysprofMarksModel) model = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GTask) task = user_data;
SysprofMarksViewPrivate *priv;
SysprofMarksPagePrivate *priv;
SysprofCaptureReader *reader;
SysprofMarksView *self;
SysprofMarksPage *self;
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task));
self = g_task_get_source_object (task);
priv = sysprof_marks_view_get_instance_private (self);
priv = sysprof_marks_page_get_instance_private (self);
if (!(model = sysprof_marks_model_new_finish (result, &error)))
{
@ -414,24 +305,26 @@ sysprof_marks_view_load_cb (GObject *object,
g_task_return_boolean (task, TRUE);
}
void
sysprof_marks_view_load_async (SysprofMarksView *self,
SysprofCaptureReader *reader,
SysprofSelection *selection,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
static void
sysprof_marks_page_load_async (SysprofPage *page,
SysprofCaptureReader *reader,
SysprofSelection *selection,
SysprofCaptureCondition *filter,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self);
SysprofMarksPage *self = (SysprofMarksPage *)page;
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
g_autoptr(GTask) task = NULL;
g_return_if_fail (SYSPROF_IS_MARKS_VIEW (self));
g_return_if_fail (SYSPROF_IS_MARKS_PAGE (self));
g_return_if_fail (reader != NULL);
g_return_if_fail (!selection || SYSPROF_IS_SELECTION (selection));
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_marks_view_load_async);
g_task_set_source_tag (task, sysprof_marks_page_load_async);
g_task_set_task_data (task,
sysprof_capture_reader_ref (reader),
(GDestroyNotify) sysprof_capture_reader_unref);
@ -440,28 +333,218 @@ sysprof_marks_view_load_async (SysprofMarksView *self,
priv->kind,
selection,
cancellable,
sysprof_marks_view_load_cb,
sysprof_marks_page_load_cb,
g_steal_pointer (&task));
}
gboolean
sysprof_marks_view_load_finish (SysprofMarksView *self,
GAsyncResult *result,
GError **error)
static gboolean
sysprof_marks_page_load_finish (SysprofPage *page,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (SYSPROF_IS_MARKS_VIEW (self), FALSE);
g_return_val_if_fail (SYSPROF_IS_MARKS_PAGE (page), FALSE);
g_return_val_if_fail (G_IS_TASK (result), FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
sysprof_marks_page_set_hadjustment (SysprofPage *page,
GtkAdjustment *hadjustment)
{
SysprofMarksPage *self = (SysprofMarksPage *)page;
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
g_assert (SYSPROF_IS_MARKS_PAGE (self));
g_assert (!hadjustment || GTK_IS_ADJUSTMENT (hadjustment));
gtk_scrolled_window_set_hadjustment (priv->scroller, hadjustment);
}
static void
sysprof_marks_page_set_size_group (SysprofPage *page,
GtkSizeGroup *size_group)
{
SysprofMarksPage *self = (SysprofMarksPage *)page;
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
g_assert (SYSPROF_IS_MARKS_PAGE (self));
g_assert (GTK_IS_SIZE_GROUP (size_group));
gtk_size_group_add_widget (size_group, GTK_WIDGET (priv->details_box));
}
static void
sysprof_marks_page_finalize (GObject *object)
{
SysprofMarksPage *self = (SysprofMarksPage *)object;
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
g_clear_object (&priv->zoom_manager);
G_OBJECT_CLASS (sysprof_marks_page_parent_class)->finalize (object);
}
static void
sysprof_marks_page_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofMarksPage *self = SYSPROF_MARKS_PAGE (object);
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
switch (prop_id)
{
case PROP_KIND:
g_value_set_enum (value, priv->kind);
break;
case PROP_ZOOM_MANAGER:
g_value_set_object (value, priv->zoom_manager);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_marks_page_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofMarksPage *self = SYSPROF_MARKS_PAGE (object);
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
switch (prop_id)
{
case PROP_KIND:
priv->kind = g_value_get_enum (value);
break;
case PROP_ZOOM_MANAGER:
if (g_set_object (&priv->zoom_manager, g_value_get_object (value)))
{
g_object_set (priv->duration_cell,
"zoom-manager", priv->zoom_manager,
NULL);
if (priv->zoom_manager)
g_signal_connect_object (priv->zoom_manager,
"notify::zoom",
G_CALLBACK (gtk_tree_view_column_queue_resize),
priv->duration_column,
G_CONNECT_SWAPPED);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_marks_page_class_init (SysprofMarksPageClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
SysprofPageClass *page_class = SYSPROF_PAGE_CLASS (klass);
object_class->finalize = sysprof_marks_page_finalize;
object_class->get_property = sysprof_marks_page_get_property;
object_class->set_property = sysprof_marks_page_set_property;
page_class->load_async = sysprof_marks_page_load_async;
page_class->load_finish = sysprof_marks_page_load_finish;
page_class->set_hadjustment = sysprof_marks_page_set_hadjustment;
page_class->set_size_group = sysprof_marks_page_set_size_group;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-marks-page.ui");
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, details_box);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, duration_cell);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, duration_column);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, scroller);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, stack);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, tree_view);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, group);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, mark);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, duration);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, time);
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, message);
properties [PROP_KIND] =
g_param_spec_enum ("kind", NULL, NULL,
SYSPROF_TYPE_MARKS_MODEL_KIND,
SYSPROF_MARKS_MODEL_MARKS,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
properties [PROP_ZOOM_MANAGER] =
g_param_spec_object ("zoom-manager", NULL, NULL,
SYSPROF_TYPE_ZOOM_MANAGER,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
g_type_ensure (SYSPROF_TYPE_CELL_RENDERER_DURATION);
}
static void
sysprof_marks_page_init (SysprofMarksPage *self)
{
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
priv->kind = SYSPROF_MARKS_MODEL_MARKS;
gtk_widget_init_template (GTK_WIDGET (self));
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (priv->tree_view),
GTK_SELECTION_MULTIPLE);
g_signal_connect_object (priv->tree_view,
"key-press-event",
G_CALLBACK (sysprof_marks_page_tree_view_key_press_event_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->tree_view,
"query-tooltip",
G_CALLBACK (sysprof_marks_page_tree_view_query_tooltip_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (gtk_tree_view_get_selection (priv->tree_view),
"changed",
G_CALLBACK (sysprof_marks_page_selection_changed_cb),
self,
G_CONNECT_SWAPPED);
}
GtkWidget *
sysprof_marks_page_new (SysprofZoomManager *zoom_manager,
SysprofMarksModelKind kind)
{
SysprofMarksPage *self;
SysprofMarksPagePrivate *priv;
g_return_val_if_fail (SYSPROF_IS_ZOOM_MANAGER (zoom_manager), NULL);
self = g_object_new (SYSPROF_TYPE_MARKS_PAGE,
"zoom-manager", zoom_manager,
NULL);
priv = sysprof_marks_page_get_instance_private (self);
priv->kind = kind;
return GTK_WIDGET (self);
}
void
_sysprof_marks_view_set_hadjustment (SysprofMarksView *self,
_sysprof_marks_page_set_hadjustment (SysprofMarksPage *self,
GtkAdjustment *hadjustment)
{
SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self);
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_MARKS_VIEW (self));
g_return_if_fail (SYSPROF_IS_MARKS_PAGE (self));
g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
gtk_scrolled_window_set_hadjustment (priv->scroller, hadjustment);

View File

@ -1,6 +1,6 @@
/* sysprof-cpu-visualizer-row.h
/* sysprof-marks-page.h
*
* Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -20,22 +20,25 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include "sysprof-line-visualizer-row.h"
#include "sysprof-version-macros.h"
#include "sysprof-marks-model.h"
#include "sysprof-page.h"
#include "sysprof-zoom-manager.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_CPU_VISUALIZER_ROW (sysprof_cpu_visualizer_row_get_type())
#define SYSPROF_TYPE_MARKS_PAGE (sysprof_marks_page_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (SysprofCpuVisualizerRow, sysprof_cpu_visualizer_row, SYSPROF, CPU_VISUALIZER_ROW, SysprofLineVisualizerRow)
G_DECLARE_DERIVABLE_TYPE (SysprofMarksPage, sysprof_marks_page, SYSPROF, MARKS_PAGE, SysprofPage)
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_cpu_visualizer_row_new (void);
struct _SysprofMarksPageClass
{
SysprofPageClass parent_class;
/*< private >*/
gpointer _reserved[16];
};
GtkWidget *sysprof_marks_page_new (SysprofZoomManager *zoom_manager,
SysprofMarksModelKind kind);
G_END_DECLS

View File

@ -0,0 +1,231 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SysprofMarksPage" parent="SysprofPage">
<child>
<object class="GtkStack" id="stack">
<property name="homogeneous">false</property>
<property name="visible">true</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="visible">true</property>
<child>
<object class="GtkBox" id="details_box">
<property name="orientation">vertical</property>
<property name="margin">6</property>
<property name="visible">true</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Details</property>
<property name="xalign">0</property>
<property name="visible">true</property>
<property name="margin-bottom">6</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkGrid">
<property name="hexpand">false</property>
<property name="vexpand">true</property>
<property name="margin-start">6</property>
<property name="visible">true</property>
<property name="column-spacing">6</property>
<property name="row-spacing">3</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Group</property>
<property name="visible">true</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="top-attach">0</property>
<property name="left-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Mark</property>
<property name="visible">true</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="top-attach">1</property>
<property name="left-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Time</property>
<property name="visible">true</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="top-attach">2</property>
<property name="left-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Duration</property>
<property name="visible">true</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="top-attach">3</property>
<property name="left-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Message</property>
<property name="visible">true</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="top-attach">4</property>
<property name="left-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="group">
<property name="visible">true</property>
<property name="xalign">0</property>
<property name="wrap">true</property>
</object>
<packing>
<property name="top-attach">0</property>
<property name="left-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="mark">
<property name="visible">true</property>
<property name="xalign">0</property>
<property name="wrap">true</property>
</object>
<packing>
<property name="top-attach">1</property>
<property name="left-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="time">
<property name="visible">true</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">2</property>
<property name="left-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="duration">
<property name="visible">true</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="top-attach">3</property>
<property name="left-attach">1</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hexpand">true</property>
<property name="shadow-type">in</property>
<property name="visible">true</property>
<child>
<object class="GtkTextView" id="message">
<property name="editable">false</property>
<property name="visible">true</property>
</object>
</child>
</object>
<packing>
<property name="top-attach">4</property>
<property name="left-attach">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator">
<property name="orientation">vertical</property>
<property name="visible">true</property>
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="scroller">
<property name="hscrollbar-policy">external</property>
<property name="hexpand">true</property>
<property name="visible">true</property>
<child>
<object class="GtkTreeView" id="tree_view">
<property name="headers-visible">false</property>
<property name="enable-grid-lines">horizontal</property>
<property name="has-tooltip">true</property>
<property name="visible">true</property>
<child>
<object class="GtkTreeViewColumn" id="duration_column">
<property name="title" translatable="yes">Duration</property>
<property name="expand">true</property>
<child>
<object class="SysprofCellRendererDuration" id="duration_cell">
<property name="xalign">0</property>
<property name="ypad">1</property>
</object>
<attributes>
<attribute name="text">5</attribute>
<attribute name="begin-time">2</attribute>
<attribute name="end-time">3</attribute>
</attributes>
<cell-packing>
<property name="expand">true</property>
</cell-packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">marks</property>
</packing>
</child>
<child>
<object class="DzlEmptyState">
<property name="icon-name">computer-fail-symbolic</property>
<property name="title" translatable="yes">No Timings Available</property>
<property name="subtitle" translatable="yes">No timing data was found for the current selection</property>
<property name="visible">true</property>
</object>
<packing>
<property name="name">empty-state</property>
</packing>
</child>
</object>
</child>
</template>
</interface>

View File

@ -1,55 +0,0 @@
/* sysprof-marks-view.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <sysprof.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define SYSPROF_TYPE_MARKS_VIEW (sysprof_marks_view_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofMarksView, sysprof_marks_view, SYSPROF, MARKS_VIEW, GtkBin)
struct _SysprofMarksViewClass
{
GtkBinClass parent_class;
/*< private >*/
gpointer _reserved[16];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_marks_view_new (void);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_marks_view_load_async (SysprofMarksView *self,
SysprofCaptureReader *reader,
SysprofSelection *selection,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_marks_view_load_finish (SysprofMarksView *self,
GAsyncResult *result,
GError **error);
G_END_DECLS

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SysprofMarksView" parent="GtkBin">
<child>
<object class="GtkStack" id="stack">
<property name="visible">true</property>
<child>
<object class="GtkScrolledWindow" id="scroller">
<property name="visible">true</property>
<child>
<object class="GtkTreeView" id="tree_view">
<property name="headers-visible">false</property>
<property name="enable-grid-lines">horizontal</property>
<property name="has-tooltip">true</property>
<property name="visible">true</property>
<child>
<object class="GtkTreeViewColumn" id="duration_column">
<property name="title" translatable="yes">Duration</property>
<property name="expand">true</property>
<child>
<object class="SysprofCellRendererDuration" id="duration_cell">
<property name="xalign">0</property>
<property name="ypad">1</property>
</object>
<attributes>
<attribute name="text">5</attribute>
<attribute name="begin-time">2</attribute>
<attribute name="end-time">3</attribute>
</attributes>
<cell-packing>
<property name="expand">true</property>
</cell-packing>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">marks</property>
</packing>
</child>
<child>
<object class="SysprofEmptyStateView">
<property name="icon-name">computer-fail-symbolic</property>
<property name="title" translatable="yes">No Timings Available</property>
<property name="subtitle" translatable="yes">No timing data was collected.</property>
<property name="visible">true</property>
</object>
<packing>
<property name="name">empty-state</property>
</packing>
</child>
</object>
</child>
</template>
</interface>

View File

@ -26,10 +26,8 @@ G_BEGIN_DECLS
#define SYSPROF_TYPE_MEMORY_AID (sysprof_memory_aid_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (SysprofMemoryAid, sysprof_memory_aid, SYSPROF, MEMORY_AID, SysprofAid)
SYSPROF_AVAILABLE_IN_ALL
SysprofAid *sysprof_memory_aid_new (void);
G_END_DECLS

View File

@ -33,7 +33,7 @@ G_BEGIN_DECLS
#define SYSPROF_TYPE_MODEL_FILTER (sysprof_model_filter_get_type())
typedef gboolean (*SysprofModelFilterFunc) (GObject *object,
gpointer user_data);
gpointer user_data);
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofModelFilter, sysprof_model_filter, SYSPROF, MODEL_FILTER, GObject)

View File

@ -20,6 +20,10 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include <sysprof.h>

View File

@ -0,0 +1,235 @@
/* sysprof-page.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-page"
#include "config.h"
#include "sysprof-page.h"
typedef struct
{
gchar *title;
} SysprofPagePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (SysprofPage, sysprof_page, GTK_TYPE_BIN)
enum {
PROP_0,
PROP_TITLE,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
/**
* sysprof_page_new:
*
* Create a new #SysprofPage.
*
* Returns: (transfer full) (type SysprofPage): a newly created #SysprofPage
*/
GtkWidget *
sysprof_page_new (void)
{
return g_object_new (SYSPROF_TYPE_PAGE, NULL);
}
const gchar *
sysprof_page_get_title (SysprofPage *self)
{
SysprofPagePrivate *priv = sysprof_page_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_PAGE (self), NULL);
return priv->title;
}
void
sysprof_page_set_title (SysprofPage *self,
const gchar *title)
{
SysprofPagePrivate *priv = sysprof_page_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_PAGE (self));
if (g_strcmp0 (priv->title, title) != 0)
{
g_free (priv->title);
priv->title = g_strdup (title);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
}
}
static void
sysprof_page_real_load_async (SysprofPage *self,
SysprofCaptureReader *reader,
SysprofSelection *selection,
SysprofCaptureCondition *condition,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_task_report_new_error (self, callback, user_data,
sysprof_page_load_async,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Operation not supported");
}
static gboolean
sysprof_page_real_load_finish (SysprofPage *self,
GAsyncResult *result,
GError **error)
{
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
sysprof_page_finalize (GObject *object)
{
SysprofPage *self = (SysprofPage *)object;
SysprofPagePrivate *priv = sysprof_page_get_instance_private (self);
g_clear_pointer (&priv->title, g_free);
G_OBJECT_CLASS (sysprof_page_parent_class)->finalize (object);
}
static void
sysprof_page_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofPage *self = SYSPROF_PAGE (object);
switch (prop_id)
{
case PROP_TITLE:
g_value_set_string (value, sysprof_page_get_title (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_page_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofPage *self = SYSPROF_PAGE (object);
switch (prop_id)
{
case PROP_TITLE:
sysprof_page_set_title (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_page_class_init (SysprofPageClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = sysprof_page_finalize;
object_class->get_property = sysprof_page_get_property;
object_class->set_property = sysprof_page_set_property;
klass->load_async = sysprof_page_real_load_async;
klass->load_finish = sysprof_page_real_load_finish;
properties [PROP_TITLE] =
g_param_spec_string ("title",
"Title",
"The title for the page",
NULL,
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
sysprof_page_init (SysprofPage *self)
{
}
/**
* sysprof_page_load_async:
* @condition: (nullable): a #sysprofCaptureCondition or %NULL
* @cancellable: (nullable): a #GCancellable or %NULL
*
* Since: 3.34
*/
void
sysprof_page_load_async (SysprofPage *self,
SysprofCaptureReader *reader,
SysprofSelection *selection,
SysprofCaptureCondition *condition,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (SYSPROF_IS_PAGE (self));
g_return_if_fail (reader != NULL);
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
SYSPROF_PAGE_GET_CLASS (self)->load_async (self, reader, selection, condition, cancellable, callback, user_data);
}
gboolean
sysprof_page_load_finish (SysprofPage *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (SYSPROF_IS_PAGE (self), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
return SYSPROF_PAGE_GET_CLASS (self)->load_finish (self, result, error);
}
void
sysprof_page_set_size_group (SysprofPage *self,
GtkSizeGroup *size_group)
{
g_return_if_fail (SYSPROF_IS_PAGE (self));
g_return_if_fail (!size_group || GTK_IS_SIZE_GROUP (size_group));
if (SYSPROF_PAGE_GET_CLASS (self)->set_size_group)
SYSPROF_PAGE_GET_CLASS (self)->set_size_group (self, size_group);
}
void
sysprof_page_set_hadjustment (SysprofPage *self,
GtkAdjustment *hadjustment)
{
g_return_if_fail (SYSPROF_IS_PAGE (self));
g_return_if_fail (!hadjustment || GTK_IS_ADJUSTMENT (hadjustment));
if (SYSPROF_PAGE_GET_CLASS (self)->set_hadjustment)
SYSPROF_PAGE_GET_CLASS (self)->set_hadjustment (self, hadjustment);
}

View File

@ -0,0 +1,86 @@
/* sysprof-page.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include <sysprof.h>
G_BEGIN_DECLS
#define SYSPROF_TYPE_PAGE (sysprof_page_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofPage, sysprof_page, SYSPROF, PAGE, GtkBin)
struct _SysprofPageClass
{
GtkBinClass parent_class;
void (*load_async) (SysprofPage *self,
SysprofCaptureReader *reader,
SysprofSelection *selection,
SysprofCaptureCondition *condition,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (*load_finish) (SysprofPage *self,
GAsyncResult *result,
GError **error);
void (*set_hadjustment) (SysprofPage *self,
GtkAdjustment *hadjustment);
void (*set_size_group) (SysprofPage *self,
GtkSizeGroup *size_group);
/*< private >*/
gpointer _reserved[16];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_page_new (void);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_page_load_async (SysprofPage *self,
SysprofCaptureReader *reader,
SysprofSelection *selection,
SysprofCaptureCondition *condition,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_page_load_finish (SysprofPage *self,
GAsyncResult *result,
GError **error);
SYSPROF_AVAILABLE_IN_ALL
const gchar *sysprof_page_get_title (SysprofPage *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_page_set_title (SysprofPage *self,
const gchar *title);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_page_set_hadjustment (SysprofPage *self,
GtkAdjustment *hadjustment);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_page_set_size_group (SysprofPage *self,
GtkSizeGroup *size_group);
G_END_DECLS

View File

@ -27,13 +27,17 @@
#include "sysprof-platform.h"
#include "sysprof-aid-icon.h"
#include "sysprof-cpu-aid.h"
#include "sysprof-environ-editor.h"
#include "sysprof-profiler-assistant.h"
#include "sysprof-proxy-aid.h"
#include "sysprof-process-model-row.h"
#include "sysprof-ui-private.h"
#include "sysprof-battery-aid.h"
#include "sysprof-callgraph-aid.h"
#include "sysprof-cpu-aid.h"
#include "sysprof-memory-aid.h"
#include "sysprof-proxy-aid.h"
struct _SysprofProfilerAssistant
{
GtkBin parent_instance;
@ -298,9 +302,12 @@ sysprof_profiler_assistant_class_init (SysprofProfilerAssistantClass *klass)
gtk_widget_class_bind_template_child (widget_class, SysprofProfilerAssistant, inherit_switch);
g_type_ensure (SYSPROF_TYPE_AID_ICON);
g_type_ensure (SYSPROF_TYPE_BATTERY_AID);
g_type_ensure (SYSPROF_TYPE_CPU_AID);
g_type_ensure (SYSPROF_TYPE_MEMORY_AID);
g_type_ensure (SYSPROF_TYPE_PROXY_AID);
g_type_ensure (SYSPROF_TYPE_ENVIRON_EDITOR);
g_type_ensure (SYSPROF_TYPE_CALLGRAPH_AID);
}
static void

View File

@ -28,10 +28,8 @@ G_BEGIN_DECLS
#define SYSPROF_TYPE_PROFILER_ASSISTANT (sysprof_profiler_assistant_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (SysprofProfilerAssistant, sysprof_profiler_assistant, SYSPROF, PROFILER_ASSISTANT, GtkBin)
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_profiler_assistant_new (void);
G_END_DECLS

View File

@ -43,13 +43,7 @@
</object>
</child>
</object>
<object class="SysprofAid" id="battery_aid">
<property name="display-name">Battery</property>
<property name="icon-name">battery-low-charging-symbolic</property>
<child>
<object class="SysprofBatterySource"/>
</child>
</object>
<object class="SysprofBatteryAid" id="battery_aid"/>
<template class="SysprofProfilerAssistant" parent="GtkBin">
<child>
<object class="GtkScrolledWindow">

View File

@ -36,13 +36,10 @@ struct _SysprofProxyAidClass
gpointer _reserved[8];
};
SYSPROF_AVAILABLE_IN_ALL
void sysprof_proxy_aid_set_bus_type (SysprofProxyAid *self,
GBusType bus_type);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_proxy_aid_set_bus_name (SysprofProxyAid *self,
const gchar *bus_name);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_proxy_aid_set_object_path (SysprofProxyAid *self,
const gchar *obj_path);

View File

@ -20,10 +20,6 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include <sysprof.h>
@ -31,7 +27,6 @@ G_BEGIN_DECLS
#define SYSPROF_TYPE_RECORDING_STATE_VIEW (sysprof_recording_state_view_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofRecordingStateView, sysprof_recording_state_view, SYSPROF, RECORDING_STATE_VIEW, GtkBin)
struct _SysprofRecordingStateViewClass
@ -41,9 +36,7 @@ struct _SysprofRecordingStateViewClass
gpointer padding[4];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_recording_state_view_new (void);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_recording_state_view_set_profiler (SysprofRecordingStateView *self,
SysprofProfiler *profiler);

View File

@ -0,0 +1,306 @@
/* sysprof-scrollmap.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-scrollmap"
#include "config.h"
#include "sysprof-scrollmap.h"
#define BOX_SIZE 4
struct _SysprofScrollmap
{
GtkScrollbar parent_instance;
gint64 begin_time;
gint64 end_time;
GArray *timings;
GArray *buckets;
GCancellable *cancellable;
gint most;
};
typedef struct
{
gint64 begin_time;
gint64 end_time;
GArray *timings;
gint width;
gint height;
} Recalculate;
G_DEFINE_TYPE (SysprofScrollmap, sysprof_scrollmap, GTK_TYPE_SCROLLBAR)
static void
recalculate_free (gpointer data)
{
Recalculate *state = data;
g_clear_pointer (&state->timings, g_array_unref);
g_slice_free (Recalculate, state);
}
static void
sysprof_scrollmap_recalculate_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
Recalculate *state = task_data;
g_autoptr(GArray) buckets = NULL;
gint64 duration;
gint n_buckets;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_SCROLLMAP (source_object));
g_assert (state != NULL);
g_assert (state->timings != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
duration = state->end_time - state->begin_time;
n_buckets = MAX (1, state->width / (BOX_SIZE + 1));
buckets = g_array_sized_new (FALSE, TRUE, sizeof (gint), n_buckets);
g_array_set_size (buckets, n_buckets);
for (guint i = 0; i < state->timings->len; i++)
{
gint64 t = g_array_index (state->timings, gint64, i);
gint n;
if (t < state->begin_time || t > state->end_time)
continue;
n = ((t - state->begin_time) / (gdouble)duration) * n_buckets;
g_assert (n < n_buckets);
g_array_index (buckets, gint, n)++;
}
g_task_return_pointer (task,
g_steal_pointer (&buckets),
(GDestroyNotify) g_array_unref);
}
static void
sysprof_scrollmap_recalculate_async (SysprofScrollmap *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
GtkAllocation alloc;
Recalculate state;
g_assert (SYSPROF_IS_SCROLLMAP (self));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_scrollmap_recalculate_async);
if (self->timings == NULL)
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_CANCELLED,
"The operation was cancelled");
return;
}
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
state.begin_time = self->begin_time;
state.end_time = self->end_time;
state.width = alloc.width;
state.height = alloc.height;
state.timings = g_array_ref (self->timings);
g_task_set_task_data (task,
g_slice_dup (Recalculate, &state),
recalculate_free);
g_task_run_in_thread (task, sysprof_scrollmap_recalculate_worker);
}
static GArray *
sysprof_scrollmap_recalculate_finish (SysprofScrollmap *self,
GAsyncResult *result,
GError **error)
{
g_assert (SYSPROF_IS_SCROLLMAP (self));
g_assert (G_IS_TASK (result));
return g_task_propagate_pointer (G_TASK (result), error);
}
static void
draw_boxes (const GtkAllocation *alloc,
cairo_t *cr,
gint x,
gint n_boxes)
{
gint y;
g_assert (cr != NULL);
y = alloc->height - BOX_SIZE;
for (gint i = 0; i < n_boxes; i++)
{
cairo_rectangle (cr, x, y, BOX_SIZE, -BOX_SIZE);
y -= (BOX_SIZE + 1);
}
cairo_fill (cr);
}
static gboolean
sysprof_scrollmap_draw (GtkWidget *widget,
cairo_t *cr)
{
SysprofScrollmap *self = (SysprofScrollmap *)widget;
GtkStyleContext *style_context;
GtkAllocation alloc;
GdkRGBA color;
gint max_boxes;
g_assert (SYSPROF_IS_SCROLLMAP (self));
g_assert (cr != NULL);
if (self->buckets == NULL)
goto chainup;
gtk_widget_get_allocation (widget, &alloc);
max_boxes = alloc.height / (BOX_SIZE + 1) - 1;
style_context = gtk_widget_get_style_context (widget);
gtk_style_context_get_color (style_context,
gtk_style_context_get_state (style_context),
&color);
gdk_cairo_set_source_rgba (cr, &color);
for (guint i = 0; i < self->buckets->len; i++)
{
gint n = g_array_index (self->buckets, gint, i);
gint x = 1 + i * (BOX_SIZE + 1);
gint b = max_boxes * (n / (gdouble)self->most);
#if 1
if (n > 0)
b = MAX (b, 1);
#endif
draw_boxes (&alloc, cr, x, b);
}
chainup:
return GTK_WIDGET_CLASS (sysprof_scrollmap_parent_class)->draw (widget, cr);
}
static void
sysprof_scrollmap_recalculate_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofScrollmap *self = (SysprofScrollmap *)object;
g_autoptr(GArray) buckets = NULL;
g_assert (SYSPROF_IS_SCROLLMAP (self));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (user_data == NULL);
if ((buckets = sysprof_scrollmap_recalculate_finish (self, result, NULL)))
{
self->most = 0;
for (guint i = 0; i < buckets->len; i++)
{
gint n = g_array_index (buckets, gint, i);
self->most = MAX (self->most, n);
}
g_clear_pointer (&self->buckets, g_array_unref);
self->buckets = g_steal_pointer (&buckets);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
static void
sysprof_scrollmap_finalize (GObject *object)
{
SysprofScrollmap *self = (SysprofScrollmap *)object;
g_clear_pointer (&self->buckets, g_array_unref);
g_clear_pointer (&self->timings, g_array_unref);
G_OBJECT_CLASS (sysprof_scrollmap_parent_class)->finalize (object);
}
static void
sysprof_scrollmap_class_init (SysprofScrollmapClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = sysprof_scrollmap_finalize;
widget_class->draw = sysprof_scrollmap_draw;
}
static void
sysprof_scrollmap_init (SysprofScrollmap *self)
{
}
void
sysprof_scrollmap_set_timings (SysprofScrollmap *self,
GArray *timings)
{
g_return_if_fail (SYSPROF_IS_SCROLLMAP (self));
if (timings != self->timings)
{
g_clear_pointer (&self->timings, g_array_unref);
self->timings = timings ? g_array_ref (timings) : NULL;
}
}
void
sysprof_scrollmap_set_time_range (SysprofScrollmap *self,
gint64 begin_time,
gint64 end_time)
{
g_return_if_fail (SYSPROF_IS_SCROLLMAP (self));
self->begin_time = begin_time;
self->end_time = end_time;
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
self->cancellable = g_cancellable_new ();
sysprof_scrollmap_recalculate_async (self,
self->cancellable,
sysprof_scrollmap_recalculate_cb,
NULL);
}

View File

@ -0,0 +1,37 @@
/* sysprof-scrollmap.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define SYSPROF_TYPE_SCROLLMAP (sysprof_scrollmap_get_type())
G_DECLARE_FINAL_TYPE (SysprofScrollmap, sysprof_scrollmap, SYSPROF, SCROLLMAP, GtkScrollbar)
void sysprof_scrollmap_set_timings (SysprofScrollmap *self,
GArray *timings);
void sysprof_scrollmap_set_time_range (SysprofScrollmap *self,
gint64 begin_time,
gint64 end_time);
G_END_DECLS

View File

@ -202,9 +202,9 @@ sysprof_theme_manager_get_default (void)
guint
sysprof_theme_manager_register_resource (SysprofThemeManager *self,
const gchar *theme_name,
const gchar *variant,
const gchar *resource)
const gchar *theme_name,
const gchar *variant,
const gchar *resource)
{
ThemeResource *theme_resource;
static guint counter;

View File

@ -0,0 +1,543 @@
/* sysprof-time-visualizer.c
*
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-time-visualizer"
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <sysprof.h>
#include "pointcache.h"
#include "sysprof-time-visualizer.h"
typedef struct
{
/*
* Our reader as assigned by the visualizer system.
*/
SysprofCaptureReader *reader;
/*
* An array of LineInfo which contains information about the counters
* we need to render.
*/
GArray *lines;
/*
* This is our set of cached points to render. Once it is assigned here,
* it is immutable (and therefore may be shared with worker processes
* that are rendering the points).
*/
PointCache *cache;
/*
* If we have a new counter discovered or the reader is set, we might
* want to delay loading until we return to the main loop. This can
* help us avoid doing duplicate work.
*/
guint queued_load;
} SysprofTimeVisualizerPrivate;
typedef struct
{
guint id;
gdouble line_width;
GdkRGBA rgba;
guint use_default_style : 1;
guint use_dash : 1;
} LineInfo;
typedef struct
{
SysprofCaptureCursor *cursor;
GArray *lines;
PointCache *cache;
gint64 begin_time;
gint64 end_time;
} LoadData;
G_DEFINE_TYPE_WITH_PRIVATE (SysprofTimeVisualizer, sysprof_time_visualizer, SYSPROF_TYPE_VISUALIZER)
static void sysprof_time_visualizer_load_data_async (SysprofTimeVisualizer *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
static PointCache *sysprof_time_visualizer_load_data_finish (SysprofTimeVisualizer *self,
GAsyncResult *result,
GError **error);
static gdouble dashes[] = { 1.0, 2.0 };
static void
load_data_free (gpointer data)
{
LoadData *load = data;
if (load != NULL)
{
g_clear_pointer (&load->lines, g_array_unref);
g_clear_pointer (&load->cursor, sysprof_capture_cursor_unref);
g_clear_pointer (&load->cache, point_cache_unref);
g_slice_free (LoadData, load);
}
}
static GArray *
copy_array (GArray *ar)
{
GArray *ret;
ret = g_array_sized_new (FALSE, FALSE, g_array_get_element_size (ar), ar->len);
g_array_set_size (ret, ar->len);
memcpy (ret->data, ar->data, ar->len * g_array_get_element_size (ret));
return ret;
}
static gboolean
sysprof_time_visualizer_draw (GtkWidget *widget,
cairo_t *cr)
{
SysprofTimeVisualizer *self = (SysprofTimeVisualizer *)widget;
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
GtkStyleContext *style_context;
GtkStateFlags flags;
GtkAllocation alloc;
GdkRectangle clip;
GdkRGBA foreground;
gboolean ret;
g_assert (SYSPROF_IS_TIME_VISUALIZER (widget));
g_assert (cr != NULL);
gtk_widget_get_allocation (widget, &alloc);
ret = GTK_WIDGET_CLASS (sysprof_time_visualizer_parent_class)->draw (widget, cr);
if (priv->cache == NULL)
return ret;
if (!gdk_cairo_get_clip_rectangle (cr, &clip))
return ret;
style_context = gtk_widget_get_style_context (widget);
flags = gtk_widget_get_state_flags (widget);
gtk_style_context_get_color (style_context, flags, &foreground);
gdk_cairo_set_source_rgba (cr, &foreground);
for (guint line = 0; line < priv->lines->len; line++)
{
g_autofree SysprofVisualizerAbsolutePoint *points = NULL;
const LineInfo *line_info = &g_array_index (priv->lines, LineInfo, line);
const Point *fpoints;
guint n_fpoints = 0;
fpoints = point_cache_get_points (priv->cache, line_info->id, &n_fpoints);
if (n_fpoints > 0)
{
guint last_x = G_MAXUINT;
points = g_new0 (SysprofVisualizerAbsolutePoint, n_fpoints);
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
(const SysprofVisualizerRelativePoint *)fpoints,
n_fpoints,
points,
n_fpoints);
cairo_set_line_width (cr, 1.0);
for (guint i = 0; i < n_fpoints; i++)
{
if ((guint)points[i].x != last_x)
last_x = (guint)points[i].x;
else
continue;
cairo_move_to (cr, (guint)points[i].x + .5, alloc.height / 3);
cairo_line_to (cr, (guint)points[i].x + .5, alloc.height / 3 * 2);
}
if (line_info->use_dash)
cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
cairo_stroke (cr);
}
}
return ret;
}
static void
sysprof_time_visualizer_load_data_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofTimeVisualizer *self = (SysprofTimeVisualizer *)object;
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
g_autoptr(GError) error = NULL;
g_autoptr(PointCache) cache = NULL;
g_assert (SYSPROF_IS_TIME_VISUALIZER (self));
cache = sysprof_time_visualizer_load_data_finish (self, result, &error);
if (cache == NULL)
{
g_warning ("%s", error->message);
return;
}
g_clear_pointer (&priv->cache, point_cache_unref);
priv->cache = g_steal_pointer (&cache);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static gboolean
sysprof_time_visualizer_do_reload (gpointer data)
{
SysprofTimeVisualizer *self = data;
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
g_assert (SYSPROF_IS_TIME_VISUALIZER (self));
priv->queued_load = 0;
if (priv->reader != NULL)
sysprof_time_visualizer_load_data_async (self,
NULL,
sysprof_time_visualizer_load_data_cb,
NULL);
return G_SOURCE_REMOVE;
}
static void
sysprof_time_visualizer_queue_reload (SysprofTimeVisualizer *self)
{
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
g_assert (SYSPROF_IS_TIME_VISUALIZER (self));
if (priv->queued_load == 0)
priv->queued_load =
gdk_threads_add_idle_full (G_PRIORITY_LOW,
sysprof_time_visualizer_do_reload,
self,
NULL);
}
static void
sysprof_time_visualizer_set_reader (SysprofVisualizer *row,
SysprofCaptureReader *reader)
{
SysprofTimeVisualizer *self = (SysprofTimeVisualizer *)row;
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
g_assert (SYSPROF_IS_TIME_VISUALIZER (self));
if (priv->reader != reader)
{
if (priv->reader != NULL)
{
sysprof_capture_reader_unref (priv->reader);
priv->reader = NULL;
}
if (reader != NULL)
priv->reader = sysprof_capture_reader_ref (reader);
sysprof_time_visualizer_queue_reload (self);
}
}
static void
sysprof_time_visualizer_finalize (GObject *object)
{
SysprofTimeVisualizer *self = (SysprofTimeVisualizer *)object;
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
g_clear_pointer (&priv->lines, g_array_unref);
g_clear_pointer (&priv->cache, point_cache_unref);
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
if (priv->queued_load != 0)
{
g_source_remove (priv->queued_load);
priv->queued_load = 0;
}
G_OBJECT_CLASS (sysprof_time_visualizer_parent_class)->finalize (object);
}
static void
sysprof_time_visualizer_class_init (SysprofTimeVisualizerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
object_class->finalize = sysprof_time_visualizer_finalize;
widget_class->draw = sysprof_time_visualizer_draw;
visualizer_class->set_reader = sysprof_time_visualizer_set_reader;
}
static void
sysprof_time_visualizer_init (SysprofTimeVisualizer *self)
{
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
priv->lines = g_array_new (FALSE, FALSE, sizeof (LineInfo));
}
void
sysprof_time_visualizer_add_counter (SysprofTimeVisualizer *self,
guint counter_id,
const GdkRGBA *color)
{
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
LineInfo line_info = {0};
g_assert (SYSPROF_IS_TIME_VISUALIZER (self));
g_assert (priv->lines != NULL);
line_info.id = counter_id;
line_info.line_width = 1.0;
if (color != NULL)
{
line_info.rgba = *color;
line_info.use_default_style = FALSE;
}
else
{
line_info.use_default_style = TRUE;
}
g_array_append_val (priv->lines, line_info);
if (SYSPROF_TIME_VISUALIZER_GET_CLASS (self)->counter_added)
SYSPROF_TIME_VISUALIZER_GET_CLASS (self)->counter_added (self, counter_id);
sysprof_time_visualizer_queue_reload (self);
}
void
sysprof_time_visualizer_clear (SysprofTimeVisualizer *self)
{
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_TIME_VISUALIZER (self));
if (priv->lines->len > 0)
g_array_remove_range (priv->lines, 0, priv->lines->len);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static inline gboolean
contains_id (GArray *ar,
guint id)
{
for (guint i = 0; i < ar->len; i++)
{
const LineInfo *info = &g_array_index (ar, LineInfo, i);
if (info->id == id)
return TRUE;
}
return FALSE;
}
static inline gdouble
calc_x (gint64 lower,
gint64 upper,
gint64 value)
{
return (gdouble)(value - lower) / (gdouble)(upper - lower);
}
static gboolean
sysprof_time_visualizer_load_data_frame_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
LoadData *load = user_data;
g_assert (frame != NULL);
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET ||
frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
g_assert (load != NULL);
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
{
const SysprofCaptureCounterSet *set = (SysprofCaptureCounterSet *)frame;
gdouble x = calc_x (load->begin_time, load->end_time, frame->time);
for (guint i = 0; i < set->n_values; i++)
{
const SysprofCaptureCounterValues *group = &set->values[i];
for (guint j = 0; j < G_N_ELEMENTS (group->ids); j++)
{
guint counter_id = group->ids[j];
if (counter_id != 0 && contains_id (load->lines, counter_id))
point_cache_add_point_to_set (load->cache, counter_id, x, 0);
}
}
}
return TRUE;
}
static void
sysprof_time_visualizer_load_data_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
LoadData *load = task_data;
g_autoptr(GArray) counter_ids = NULL;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_TIME_VISUALIZER (source_object));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
counter_ids = g_array_new (FALSE, FALSE, sizeof (guint));
for (guint i = 0; i < load->lines->len; i++)
{
const LineInfo *line_info = &g_array_index (load->lines, LineInfo, i);
g_array_append_val (counter_ids, line_info->id);
}
sysprof_capture_cursor_add_condition (load->cursor,
sysprof_capture_condition_new_where_counter_in (counter_ids->len,
(guint *)(gpointer)counter_ids->data));
sysprof_capture_cursor_foreach (load->cursor, sysprof_time_visualizer_load_data_frame_cb, load);
g_task_return_pointer (task, g_steal_pointer (&load->cache), (GDestroyNotify)point_cache_unref);
}
static void
sysprof_time_visualizer_load_data_async (SysprofTimeVisualizer *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
g_autoptr(GTask) task = NULL;
LoadData *load;
g_assert (SYSPROF_IS_TIME_VISUALIZER (self));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_priority (task, G_PRIORITY_LOW);
g_task_set_source_tag (task, sysprof_time_visualizer_load_data_async);
if (priv->reader == NULL)
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"No data loaded");
return;
}
load = g_slice_new0 (LoadData);
load->cache = point_cache_new ();
load->begin_time = sysprof_capture_reader_get_start_time (priv->reader);
load->end_time = sysprof_capture_reader_get_end_time (priv->reader);
load->cursor = sysprof_capture_cursor_new (priv->reader);
load->lines = copy_array (priv->lines);
for (guint i = 0; i < load->lines->len; i++)
{
const LineInfo *line_info = &g_array_index (load->lines, LineInfo, i);
point_cache_add_set (load->cache, line_info->id);
}
g_task_set_task_data (task, load, load_data_free);
g_task_run_in_thread (task, sysprof_time_visualizer_load_data_worker);
}
static PointCache *
sysprof_time_visualizer_load_data_finish (SysprofTimeVisualizer *self,
GAsyncResult *result,
GError **error)
{
g_assert (SYSPROF_IS_TIME_VISUALIZER (self));
g_assert (G_IS_TASK (result));
return g_task_propagate_pointer (G_TASK (result), error);
}
void
sysprof_time_visualizer_set_line_width (SysprofTimeVisualizer *self,
guint counter_id,
gdouble width)
{
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_TIME_VISUALIZER (self));
for (guint i = 0; i < priv->lines->len; i++)
{
LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
if (info->id == counter_id)
{
info->line_width = width;
sysprof_time_visualizer_queue_reload (self);
break;
}
}
}
void
sysprof_time_visualizer_set_dash (SysprofTimeVisualizer *self,
guint counter_id,
gboolean use_dash)
{
SysprofTimeVisualizerPrivate *priv = sysprof_time_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_TIME_VISUALIZER (self));
for (guint i = 0; i < priv->lines->len; i++)
{
LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
if (info->id == counter_id)
{
info->use_dash = !!use_dash;
sysprof_time_visualizer_queue_reload (self);
break;
}
}
}

View File

@ -0,0 +1,54 @@
/* sysprof-time-visualizer.h
*
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include "sysprof-visualizer.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_TIME_VISUALIZER (sysprof_time_visualizer_get_type())
G_DECLARE_DERIVABLE_TYPE (SysprofTimeVisualizer, sysprof_time_visualizer, SYSPROF, TIME_VISUALIZER, SysprofVisualizer)
struct _SysprofTimeVisualizerClass
{
SysprofVisualizerClass parent_class;
void (*counter_added) (SysprofTimeVisualizer *self,
guint counter_id);
/*< private >*/
gpointer _reserved[16];
};
GtkWidget *sysprof_time_visualizer_new (void);
void sysprof_time_visualizer_clear (SysprofTimeVisualizer *self);
void sysprof_time_visualizer_add_counter (SysprofTimeVisualizer *self,
guint counter_id,
const GdkRGBA *color);
void sysprof_time_visualizer_set_line_width (SysprofTimeVisualizer *self,
guint counter_id,
gdouble width);
void sysprof_time_visualizer_set_dash (SysprofTimeVisualizer *self,
guint counter_id,
gboolean use_dash);
G_END_DECLS

View File

@ -20,42 +20,18 @@
#pragma once
#include "sysprof-callgraph-view.h"
#include "sysprof-callgraph-page.h"
#include "sysprof-display.h"
#include "sysprof-marks-view.h"
#include "sysprof-profiler-assistant.h"
#include "sysprof-visualizer-view.h"
G_BEGIN_DECLS
typedef struct
{
gchar *name;
guint64 count;
gint64 max;
gint64 min;
gint64 avg;
guint64 avg_count;
} SysprofMarkStat;
SysprofMarkStat *_sysprof_mark_stat_new (const gchar *name);
void _sysprof_mark_stat_free (SysprofMarkStat *self);
void _sysprof_marks_view_set_hadjustment (SysprofMarksView *self,
GtkAdjustment *hadjustment);
void _sysprof_visualizer_view_set_hadjustment (SysprofVisualizerView *self,
GtkAdjustment *hadjustment);
void _sysprof_rounded_rectangle (cairo_t *cr,
const GdkRectangle *rect,
gint x_radius,
gint y_radius);
gchar *_sysprof_format_duration (gint64 duration);
void _sysprof_callgraph_view_set_failed (SysprofCallgraphView *self);
void _sysprof_callgraph_view_set_loading (SysprofCallgraphView *self,
gboolean loading);
void _sysprof_display_focus_record (SysprofDisplay *self);
void _sysprof_profiler_assistant_focus_record (SysprofProfilerAssistant *self);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofMarkStat, _sysprof_mark_stat_free)
void _sysprof_callgraph_page_set_failed (SysprofCallgraphPage *self);
void _sysprof_callgraph_page_set_loading (SysprofCallgraphPage *self,
gboolean loading);
void _sysprof_display_focus_record (SysprofDisplay *self);
void _sysprof_profiler_assistant_focus_record (SysprofProfilerAssistant *self);
gchar *_sysprof_format_duration (gint64 duration);
#if !GLIB_CHECK_VERSION(2, 56, 0)
# define g_clear_weak_pointer(ptr) \

View File

@ -27,31 +27,14 @@ G_BEGIN_DECLS
#define SYSPROF_UI_INSIDE
# include "sysprof-aid.h"
# include "sysprof-callgraph-view.h"
# include "sysprof-capture-view.h"
# include "sysprof-callgraph-aid.h"
# include "sysprof-cell-renderer-percent.h"
# include "sysprof-check.h"
# include "sysprof-cpu-aid.h"
# include "sysprof-cpu-visualizer-row.h"
# include "sysprof-display.h"
# include "sysprof-empty-state-view.h"
# include "sysprof-failed-state-view.h"
# include "sysprof-line-visualizer-row.h"
# include "sysprof-marks-model.h"
# include "sysprof-marks-view.h"
# include "sysprof-mark-visualizer-row.h"
# include "sysprof-memory-aid.h"
# include "sysprof-model-filter.h"
# include "sysprof-notebook.h"
# include "sysprof-page.h"
# include "sysprof-process-model-row.h"
# include "sysprof-profiler-assistant.h"
# include "sysprof-proxy-aid.h"
# include "sysprof-recording-state-view.h"
# include "sysprof-visualizer-row.h"
# include "sysprof-visualizer-view.h"
# include "sysprof-zoom-manager.h"
# include "sysprof-visualizer-group.h"
# include "sysprof-visualizer.h"
#undef SYSPROF_UI_INSIDE

View File

@ -0,0 +1,159 @@
/* sysprof-visualizer-group-header.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-visualizer-group-header"
#include "config.h"
#include <glib/gi18n.h>
#include "sysprof-visualizer.h"
#include "sysprof-visualizer-group.h"
#include "sysprof-visualizer-group-header.h"
struct _SysprofVisualizerGroupHeader
{
GtkListBoxRow parent_instance;
GtkBox *box;
};
G_DEFINE_TYPE (SysprofVisualizerGroupHeader, sysprof_visualizer_group_header, GTK_TYPE_LIST_BOX_ROW)
static void
sysprof_visualizer_group_header_finalize (GObject *object)
{
G_OBJECT_CLASS (sysprof_visualizer_group_header_parent_class)->finalize (object);
}
static void
sysprof_visualizer_group_header_class_init (SysprofVisualizerGroupHeaderClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = sysprof_visualizer_group_header_finalize;
}
static void
sysprof_visualizer_group_header_init (SysprofVisualizerGroupHeader *self)
{
self->box = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_VERTICAL,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->box));
}
void
_sysprof_visualizer_group_header_add_row (SysprofVisualizerGroupHeader *self,
guint position,
const gchar *title,
GMenuModel *menu,
GtkWidget *widget)
{
GtkBox *box;
GtkWidget *group;
g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP_HEADER (self));
g_return_if_fail (SYSPROF_IS_VISUALIZER (widget));
g_return_if_fail (!menu || G_IS_MENU_MODEL (menu));
box = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"spacing", 6,
"visible", TRUE,
NULL);
g_object_bind_property (widget, "visible", box, "visible", G_BINDING_SYNC_CREATE);
gtk_container_add_with_properties (GTK_CONTAINER (self->box), GTK_WIDGET (box),
"position", position,
NULL);
if (title != NULL)
{
g_autoptr(GtkSizeGroup) size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
PangoAttrList *attrs = pango_attr_list_new ();
GtkLabel *label;
pango_attr_list_insert (attrs, pango_attr_scale_new (0.83333));
label = g_object_new (GTK_TYPE_LABEL,
"attributes", attrs,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE,
"margin", 6,
"hexpand", TRUE,
"label", title,
"visible", TRUE,
"xalign", 0.0f,
NULL);
gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (label));
pango_attr_list_unref (attrs);
gtk_size_group_add_widget (size_group, widget);
gtk_size_group_add_widget (size_group, GTK_WIDGET (box));
}
group = gtk_widget_get_ancestor (widget, SYSPROF_TYPE_VISUALIZER_GROUP);
if (position == 0 && sysprof_visualizer_group_get_has_page (SYSPROF_VISUALIZER_GROUP (group)))
{
GtkImage *image;
image = g_object_new (GTK_TYPE_IMAGE,
"icon-name", "view-paged-symbolic",
"tooltip-text", _("Select for more details"),
"pixel-size", 16,
"visible", TRUE,
NULL);
dzl_gtk_widget_add_style_class (GTK_WIDGET (image), "dim-label");
gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (image));
}
if (menu != NULL)
{
GtkStyleContext *style_context;
GtkMenuButton *button;
button = g_object_new (GTK_TYPE_MENU_BUTTON,
"child", g_object_new (GTK_TYPE_IMAGE,
"icon-name", "view-more-symbolic",
"visible", TRUE,
NULL),
"margin-right", 6,
"direction", GTK_ARROW_RIGHT,
"halign", GTK_ALIGN_CENTER,
"menu-model", menu,
"tooltip-text", _("Display supplimental graphs"),
"use-popover", FALSE,
"valign", GTK_ALIGN_CENTER,
"visible", TRUE,
NULL);
style_context = gtk_widget_get_style_context (GTK_WIDGET (button));
gtk_style_context_add_class (style_context, "image-button");
gtk_style_context_add_class (style_context, "small-button");
gtk_style_context_add_class (style_context, "flat");
gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (button));
}
}
SysprofVisualizerGroupHeader *
_sysprof_visualizer_group_header_new (void)
{
return g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP_HEADER, NULL);
}

View File

@ -0,0 +1,31 @@
/* sysprof-visualizer-group-header.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define SYSPROF_TYPE_VISUALIZER_GROUP_HEADER (sysprof_visualizer_group_header_get_type())
G_DECLARE_FINAL_TYPE (SysprofVisualizerGroupHeader, sysprof_visualizer_group_header, SYSPROF, VISUALIZER_GROUP_HEADER, GtkListBoxRow)
G_END_DECLS

View File

@ -0,0 +1,48 @@
/* sysprof-visualizers-group-private.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <sysprof-capture.h>
#include "sysprof-visualizer-group.h"
#include "sysprof-visualizer-group-header.h"
G_BEGIN_DECLS
void _sysprof_visualizer_set_data_width (SysprofVisualizer *self,
gint width);
void _sysprof_visualizer_group_set_data_width (SysprofVisualizerGroup *self,
gint width);
void _sysprof_visualizer_group_set_reader (SysprofVisualizerGroup *self,
SysprofCaptureReader *reader);
SysprofVisualizerGroupHeader *_sysprof_visualizer_group_header_new (void);
void _sysprof_visualizer_group_header_add_row (SysprofVisualizerGroupHeader *self,
guint position,
const gchar *title,
GMenuModel *menu,
GtkWidget *row);
void _sysprof_visualizer_group_header_remove_row (SysprofVisualizerGroupHeader *self,
guint row);
void _sysprof_visualizer_group_set_header (SysprofVisualizerGroup *self,
SysprofVisualizerGroupHeader *header);
G_END_DECLS

View File

@ -0,0 +1,511 @@
/* sysprof-visualizer-group.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-visualizer-group"
#include "config.h"
#include <glib/gi18n.h>
#include "sysprof-visualizer.h"
#include "sysprof-visualizer-group.h"
#include "sysprof-visualizer-group-private.h"
typedef struct
{
/* Owned pointers */
GMenuModel *menu;
GMenu *default_menu;
GMenu *rows_menu;
gchar *title;
GtkSizeGroup *size_group;
GSimpleActionGroup *actions;
gint priority;
guint has_page : 1;
/* Weak pointers */
SysprofVisualizerGroupHeader *header;
/* Child Widgets */
GtkBox *visualizers;
} SysprofVisualizerGroupPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (SysprofVisualizerGroup, sysprof_visualizer_group, GTK_TYPE_LIST_BOX_ROW)
enum {
PROP_0,
PROP_HAS_PAGE,
PROP_MENU,
PROP_PRIORITY,
PROP_TITLE,
N_PROPS
};
enum {
GROUP_ACTIVATED,
N_SIGNALS
};
static GParamSpec *properties [N_PROPS];
static guint signals [N_SIGNALS];
/**
* sysprof_visualizer_group_new:
*
* Create a new #SysprofVisualizerGroup.
*
* Returns: (transfer full): a newly created #SysprofVisualizerGroup
*/
SysprofVisualizerGroup *
sysprof_visualizer_group_new (void)
{
return g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP, NULL);
}
const gchar *
sysprof_visualizer_group_get_title (SysprofVisualizerGroup *self)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self), NULL);
return priv->title;
}
void
sysprof_visualizer_group_set_title (SysprofVisualizerGroup *self,
const gchar *title)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self));
if (g_strcmp0 (priv->title, title) != 0)
{
g_free (priv->title);
priv->title = g_strdup (title);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
}
}
/**
* sysprof_visualizer_group_get_menu:
*
* Gets the menu for the group.
*
* Returns: (transfer none) (nullable): a #GMenuModel or %NULL
*
* Since: 3.34
*/
GMenuModel *
sysprof_visualizer_group_get_menu (SysprofVisualizerGroup *self)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self), NULL);
return priv->menu;
}
void
sysprof_visualizer_group_set_menu (SysprofVisualizerGroup *self,
GMenuModel *menu)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self));
g_return_if_fail (!menu || G_IS_MENU_MODEL (menu));
if (g_set_object (&priv->menu, menu))
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MENU]);
}
static gchar *
create_action_name (const gchar *str)
{
GString *ret = g_string_new (NULL);
for (; *str; str = g_utf8_next_char (str))
{
gunichar ch = g_utf8_get_char (str);
if (g_unichar_isalnum (ch))
g_string_append_unichar (ret, ch);
else
g_string_append_c (ret, '_');
}
return g_string_free (ret, FALSE);
}
static void
sysprof_visualizer_group_add (GtkContainer *container,
GtkWidget *child)
{
SysprofVisualizerGroup *self = (SysprofVisualizerGroup *)container;
g_assert (SYSPROF_IS_VISUALIZER_GROUP (self));
g_assert (GTK_IS_WIDGET (child));
if (SYSPROF_IS_VISUALIZER (child))
sysprof_visualizer_group_insert (self, SYSPROF_VISUALIZER (child), -1, FALSE);
else
GTK_CONTAINER_CLASS (sysprof_visualizer_group_parent_class)->add (container, child);
}
static void
sysprof_visualizer_group_finalize (GObject *object)
{
SysprofVisualizerGroup *self = (SysprofVisualizerGroup *)object;
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_clear_pointer (&priv->title, g_free);
g_clear_object (&priv->menu);
g_clear_object (&priv->size_group);
g_clear_object (&priv->default_menu);
g_clear_object (&priv->rows_menu);
g_clear_object (&priv->actions);
g_clear_weak_pointer (&priv->header);
G_OBJECT_CLASS (sysprof_visualizer_group_parent_class)->finalize (object);
}
static void
sysprof_visualizer_group_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofVisualizerGroup *self = SYSPROF_VISUALIZER_GROUP (object);
switch (prop_id)
{
case PROP_HAS_PAGE:
g_value_set_boolean (value, sysprof_visualizer_group_get_has_page (self));
break;
case PROP_MENU:
g_value_set_object (value, sysprof_visualizer_group_get_menu (self));
break;
case PROP_PRIORITY:
g_value_set_int (value, sysprof_visualizer_group_get_priority (self));
break;
case PROP_TITLE:
g_value_set_string (value, sysprof_visualizer_group_get_title (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_group_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofVisualizerGroup *self = SYSPROF_VISUALIZER_GROUP (object);
switch (prop_id)
{
case PROP_HAS_PAGE:
sysprof_visualizer_group_set_has_page (self, g_value_get_boolean (value));
break;
case PROP_MENU:
sysprof_visualizer_group_set_menu (self, g_value_get_object (value));
break;
case PROP_PRIORITY:
sysprof_visualizer_group_set_priority (self, g_value_get_int (value));
break;
case PROP_TITLE:
sysprof_visualizer_group_set_title (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_group_class_init (SysprofVisualizerGroupClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
object_class->finalize = sysprof_visualizer_group_finalize;
object_class->get_property = sysprof_visualizer_group_get_property;
object_class->set_property = sysprof_visualizer_group_set_property;
container_class->add = sysprof_visualizer_group_add;
properties [PROP_HAS_PAGE] =
g_param_spec_boolean ("has-page",
"Has Page",
"Has Page",
FALSE,
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
properties [PROP_MENU] =
g_param_spec_object ("menu",
"Menu",
"Menu",
G_TYPE_MENU_MODEL,
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
properties [PROP_PRIORITY] =
g_param_spec_int ("priority",
"Priority",
"The Priority of the group, used for sorting",
G_MININT, G_MAXINT, 0,
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
properties [PROP_TITLE] =
g_param_spec_string ("title",
"Title",
"The title of the row",
NULL,
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
signals [GROUP_ACTIVATED] =
g_signal_new ("group-activated",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
gtk_widget_class_set_css_name (widget_class, "SysprofVisualizerGroup");
}
static void
sysprof_visualizer_group_init (SysprofVisualizerGroup *self)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_autoptr(GMenuItem) item = NULL;
priv->actions = g_simple_action_group_new ();
priv->default_menu = g_menu_new ();
priv->rows_menu = g_menu_new ();
item = g_menu_item_new_section (NULL, G_MENU_MODEL (priv->rows_menu));
g_menu_append_item (priv->default_menu, item);
priv->menu = g_object_ref (G_MENU_MODEL (priv->default_menu));
priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
gtk_size_group_add_widget (priv->size_group, GTK_WIDGET (self));
priv->visualizers = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_VERTICAL,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (priv->visualizers));
}
void
_sysprof_visualizer_group_set_header (SysprofVisualizerGroup *self,
SysprofVisualizerGroupHeader *header)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self));
g_return_if_fail (!header || SYSPROF_IS_VISUALIZER_GROUP_HEADER (header));
if (g_set_weak_pointer (&priv->header, header))
{
if (header != NULL)
{
GList *children;
guint position = 0;
gtk_widget_insert_action_group (GTK_WIDGET (header),
"group",
G_ACTION_GROUP (priv->actions));
gtk_size_group_add_widget (priv->size_group, GTK_WIDGET (header));
children = gtk_container_get_children (GTK_CONTAINER (priv->visualizers));
for (const GList *iter = children; iter; iter = iter->next)
{
SysprofVisualizer *vis = iter->data;
const gchar *title;
GMenuModel *menu = NULL;
g_assert (SYSPROF_IS_VISUALIZER (vis));
if (position == 0)
menu = priv->menu;
title = sysprof_visualizer_get_title (vis);
if (title == NULL)
title = priv->title;
_sysprof_visualizer_group_header_add_row (header,
position,
title,
menu,
GTK_WIDGET (vis));
position++;
}
g_list_free (children);
}
}
}
static void
sysprof_visualizer_group_set_reader_cb (SysprofVisualizer *visualizer,
SysprofCaptureReader *reader)
{
sysprof_visualizer_set_reader (visualizer, reader);
}
void
_sysprof_visualizer_group_set_reader (SysprofVisualizerGroup *self,
SysprofCaptureReader *reader)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self));
g_return_if_fail (reader != NULL);
gtk_container_foreach (GTK_CONTAINER (priv->visualizers),
(GtkCallback) sysprof_visualizer_group_set_reader_cb,
reader);
}
void
sysprof_visualizer_group_insert (SysprofVisualizerGroup *self,
SysprofVisualizer *visualizer,
gint position,
gboolean can_toggle)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self));
g_return_if_fail (SYSPROF_IS_VISUALIZER (visualizer));
gtk_container_add_with_properties (GTK_CONTAINER (priv->visualizers), GTK_WIDGET (visualizer),
"position", position,
NULL);
if (can_toggle)
{
const gchar *title = sysprof_visualizer_get_title (visualizer);
g_autofree gchar *action_name = create_action_name (title);
g_autofree gchar *full_action_name = g_strdup_printf ("group.%s", action_name);
g_autoptr(GMenuItem) item = g_menu_item_new (title, full_action_name);
g_autoptr(GPropertyAction) action = NULL;
action = g_property_action_new (action_name, visualizer, "visible");
g_action_map_add_action (G_ACTION_MAP (priv->actions), G_ACTION (action));
g_menu_item_set_attribute (item, "role", "s", "check");
g_menu_append_item (priv->rows_menu, item);
}
}
static void
propagate_data_width_cb (GtkWidget *widget,
gpointer user_data)
{
_sysprof_visualizer_set_data_width (SYSPROF_VISUALIZER (widget),
GPOINTER_TO_INT (user_data));
}
void
_sysprof_visualizer_group_set_data_width (SysprofVisualizerGroup *self,
gint width)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self));
gtk_container_foreach (GTK_CONTAINER (priv->visualizers),
propagate_data_width_cb,
GINT_TO_POINTER (width));
}
gint
sysprof_visualizer_group_get_priority (SysprofVisualizerGroup *self)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self), 0);
return priv->priority;
}
void
sysprof_visualizer_group_set_priority (SysprofVisualizerGroup *self,
gint priority)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self));
if (priv->priority != priority)
{
priv->priority = priority;
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PRIORITY]);
}
}
gboolean
sysprof_visualizer_group_get_has_page (SysprofVisualizerGroup *self)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self), FALSE);
return priv->has_page;
}
void
sysprof_visualizer_group_set_has_page (SysprofVisualizerGroup *self,
gboolean has_page)
{
SysprofVisualizerGroupPrivate *priv = sysprof_visualizer_group_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_GROUP (self));
has_page = !!has_page;
if (has_page != priv->has_page)
{
priv->has_page = has_page;
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HAS_PAGE]);
}
}

View File

@ -0,0 +1,76 @@
/* sysprof-visualizer-group.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include "sysprof-visualizer.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_VISUALIZER_GROUP (sysprof_visualizer_group_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofVisualizerGroup, sysprof_visualizer_group, SYSPROF, VISUALIZER_GROUP, GtkListBoxRow)
struct _SysprofVisualizerGroupClass
{
GtkListBoxRowClass parent_class;
void (*group_activated) (SysprofVisualizerGroup *self);
/*< private >*/
gpointer _reserved[16];
};
SYSPROF_AVAILABLE_IN_ALL
SysprofVisualizerGroup *sysprof_visualizer_group_new (void);
SYSPROF_AVAILABLE_IN_ALL
GMenuModel *sysprof_visualizer_group_get_menu (SysprofVisualizerGroup *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_group_set_menu (SysprofVisualizerGroup *self,
GMenuModel *menu);
SYSPROF_AVAILABLE_IN_ALL
gint sysprof_visualizer_group_get_priority (SysprofVisualizerGroup *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_group_set_priority (SysprofVisualizerGroup *self,
gint priority);
SYSPROF_AVAILABLE_IN_ALL
const gchar *sysprof_visualizer_group_get_title (SysprofVisualizerGroup *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_group_set_title (SysprofVisualizerGroup *self,
const gchar *title);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_visualizer_group_get_has_page (SysprofVisualizerGroup *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_group_set_has_page (SysprofVisualizerGroup *self,
gboolean has_page);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_group_insert (SysprofVisualizerGroup *self,
SysprofVisualizer *visualizer,
gint position,
gboolean can_toggle);
G_END_DECLS

View File

@ -1,582 +0,0 @@
/* sysprof-visualizer-list.c
*
* Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-visualizer-list"
#include "config.h"
#include <glib/gi18n.h>
#include <sysprof.h>
#include "sysprof-cpu-visualizer-row.h"
#include "sysprof-depth-visualizer-row.h"
#include "sysprof-visualizer-list.h"
#include "sysprof-visualizer-row.h"
#include "sysprof-mark-visualizer-row.h"
#include "sysprof-zoom-manager.h"
typedef struct
{
SysprofCaptureReader *reader;
SysprofZoomManager *zoom_manager;
} SysprofVisualizerListPrivate;
typedef struct
{
SysprofCaptureCursor *cursor;
GHashTable *mark_groups;
guint fps_counter;
guint pixels_counter;
guint combined_cpu_counter;
GArray *memory;
guint batteries[4];
guint has_battery : 1;
guint has_cpu : 1;
guint has_sample : 1;
} Discovery;
enum {
PROP_0,
PROP_READER,
PROP_ZOOM_MANAGER,
N_PROPS
};
G_DEFINE_TYPE_WITH_PRIVATE (SysprofVisualizerList, sysprof_visualizer_list, GTK_TYPE_LIST_BOX)
static GParamSpec *properties [N_PROPS];
static void
discovery_free (Discovery *state)
{
g_clear_pointer (&state->mark_groups, g_hash_table_unref);
g_clear_pointer (&state->memory, g_array_unref);
g_clear_pointer (&state->cursor, sysprof_capture_cursor_unref);
g_slice_free (Discovery, state);
}
static void
sysprof_visualizer_list_add (GtkContainer *container,
GtkWidget *widget)
{
SysprofVisualizerList *self = (SysprofVisualizerList *)container;
SysprofVisualizerListPrivate *priv = sysprof_visualizer_list_get_instance_private (self);
GTK_CONTAINER_CLASS (sysprof_visualizer_list_parent_class)->add (container, widget);
if (SYSPROF_IS_VISUALIZER_ROW (widget))
{
sysprof_visualizer_row_set_reader (SYSPROF_VISUALIZER_ROW (widget), priv->reader);
sysprof_visualizer_row_set_zoom_manager (SYSPROF_VISUALIZER_ROW (widget), priv->zoom_manager);
}
}
static void
sysprof_visualizer_list_finalize (GObject *object)
{
SysprofVisualizerList *self = (SysprofVisualizerList *)object;
SysprofVisualizerListPrivate *priv = sysprof_visualizer_list_get_instance_private (self);
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
G_OBJECT_CLASS (sysprof_visualizer_list_parent_class)->finalize (object);
}
static void
sysprof_visualizer_list_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofVisualizerList *self = SYSPROF_VISUALIZER_LIST (object);
switch (prop_id)
{
case PROP_READER:
g_value_set_boxed (value, sysprof_visualizer_list_get_reader (self));
break;
case PROP_ZOOM_MANAGER:
g_value_set_object (value, sysprof_visualizer_list_get_zoom_manager (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_list_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofVisualizerList *self = SYSPROF_VISUALIZER_LIST (object);
switch (prop_id)
{
case PROP_READER:
sysprof_visualizer_list_set_reader (self, g_value_get_boxed (value));
break;
case PROP_ZOOM_MANAGER:
sysprof_visualizer_list_set_zoom_manager (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_list_class_init (SysprofVisualizerListClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
object_class->finalize = sysprof_visualizer_list_finalize;
object_class->get_property = sysprof_visualizer_list_get_property;
object_class->set_property = sysprof_visualizer_list_set_property;
container_class->add = sysprof_visualizer_list_add;
properties [PROP_READER] =
g_param_spec_boxed ("reader",
"Reader",
"The capture reader",
SYSPROF_TYPE_CAPTURE_READER,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties [PROP_ZOOM_MANAGER] =
g_param_spec_object ("zoom-manager",
"Zoom Manager",
"The zoom manager",
SYSPROF_TYPE_ZOOM_MANAGER,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
sysprof_visualizer_list_init (SysprofVisualizerList *self)
{
}
GtkWidget *
sysprof_visualizer_list_new (void)
{
return g_object_new (SYSPROF_TYPE_VISUALIZER_ROW, NULL);
}
/**
* sysprof_visualizer_list_get_reader:
*
* Gets the reader that is being used for the #SysprofVisualizerList.
*
* Returns: (transfer none): An #SysprofCaptureReader
*/
SysprofCaptureReader *
sysprof_visualizer_list_get_reader (SysprofVisualizerList *self)
{
SysprofVisualizerListPrivate *priv = sysprof_visualizer_list_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_LIST (self), NULL);
return priv->reader;
}
static void
add_battery_id (Discovery *state,
guint battery_id)
{
for (guint i = 0; i < G_N_ELEMENTS (state->batteries); i++)
{
if (state->batteries[i] == 0)
{
state->batteries[i] = battery_id;
break;
}
}
}
static gboolean
discover_new_rows_frame_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
Discovery *state = user_data;
g_assert (frame != NULL);
g_assert (state != NULL);
/*
* NOTE:
*
* It would be nice if we could redesign this all around the concept of
* an "gadget" or something which combines a data collection series
* and widget views to be displayed.
*/
if (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE)
{
state->has_sample = TRUE;
}
else if (frame->type == SYSPROF_CAPTURE_FRAME_MARK)
{
const SysprofCaptureMark *mark = (const SysprofCaptureMark *)frame;
if (!g_hash_table_contains (state->mark_groups, mark->group))
g_hash_table_add (state->mark_groups, g_strdup (mark->group));
}
else if (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF)
{
const SysprofCaptureCounterDefine *def = (const SysprofCaptureCounterDefine *)frame;
for (guint i = 0; i < def->n_counters; i++)
{
const SysprofCaptureCounter *ctr = &def->counters[i];
if (!state->combined_cpu_counter &&
strcmp (ctr->category, "CPU Percent") == 0 &&
strcmp (ctr->name, "Combined") == 0)
state->combined_cpu_counter = ctr->id;
else if (!state->has_cpu &&
strstr (ctr->category, "CPU Percent") != NULL)
state->has_cpu = TRUE;
else if (!state->fps_counter &&
strstr (ctr->category, "gtk") != NULL && strstr (ctr->name, "fps") != NULL)
state->fps_counter = ctr->id;
else if (!state->pixels_counter &&
strstr (ctr->category, "gtk") != NULL && strstr (ctr->name, "frame pixels") != NULL)
state->pixels_counter = ctr->id;
else if (strcmp (ctr->category, "Battery Charge") == 0)
{
state->has_battery = TRUE;
add_battery_id (state, ctr->id);
}
else if (strcmp ("Memory", ctr->category) == 0 &&
strcmp ("Used", ctr->name) == 0)
{
guint counter_id = ctr->id;
g_array_append_val (state->memory, counter_id);
}
}
}
return TRUE;
}
static void
discover_new_rows_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
Discovery *state = task_data;
g_assert (state != NULL);
g_assert (state->cursor != NULL);
sysprof_capture_cursor_foreach (state->cursor, discover_new_rows_frame_cb, state);
g_task_return_boolean (task, TRUE);
}
static void
handle_capture_results (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofVisualizerList *self = (SysprofVisualizerList *)object;
SysprofVisualizerListPrivate *priv = sysprof_visualizer_list_get_instance_private (self);
Discovery *state;
const gchar *key;
g_assert (SYSPROF_IS_VISUALIZER_LIST (self));
g_assert (G_IS_TASK (result));
g_assert (user_data == NULL);
state = g_task_get_task_data (G_TASK (result));
/*
* TODO: It would be really nice if we had a more structured way to do this
* so that data collections and visualizations could be mapped
* together. One way to do so might be to create the concept of an
* "instrument" which represents that pair and allows the user to
* select what sort of data collections they'd like to see.
*/
if (state->combined_cpu_counter != 0)
{
GdkRGBA rgba;
GtkWidget *row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER_ROW,
/* Translators: CPU is the processor. */
"title", _("CPU (Combined)"),
"height-request", 35,
"selectable", FALSE,
"visible", TRUE,
"y-lower", 0.0,
"y-upper", 100.0,
NULL);
gdk_rgba_parse (&rgba, "#3465a4");
sysprof_line_visualizer_row_add_counter (SYSPROF_LINE_VISUALIZER_ROW (row),
state->combined_cpu_counter,
&rgba);
rgba.alpha = 0.5;
sysprof_line_visualizer_row_set_fill (SYSPROF_LINE_VISUALIZER_ROW (row),
state->combined_cpu_counter,
&rgba);
gtk_container_add (GTK_CONTAINER (self), row);
}
else if (state->has_cpu)
{
GtkWidget *row = g_object_new (SYSPROF_TYPE_CPU_VISUALIZER_ROW,
"category", "CPU Percent",
/* Translators: CPU is the processor. */
"title", _("CPU"),
"height-request", 35,
"selectable", FALSE,
"visible", TRUE,
"y-lower", 0.0,
"y-upper", 100.0,
NULL);
gtk_container_add (GTK_CONTAINER (self), row);
}
if (state->has_cpu)
{
GtkWidget *row = g_object_new (SYSPROF_TYPE_CPU_VISUALIZER_ROW,
"category", "CPU Frequency",
/* Translators: CPU is the processor. */
"title", _("CPU Frequency"),
"height-request", 35,
"selectable", FALSE,
"visible", TRUE,
"y-lower", 0.0,
"y-upper", 100.0,
"use-dash", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (self), row);
}
if (state->has_battery)
{
for (guint i = 0; i < G_N_ELEMENTS (state->batteries); i++)
{
GtkWidget *row;
if (state->batteries[i] == 0)
break;
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER_ROW,
/* Translators: CPU is the processor. */
"title", _("Battery Charge"),
"height-request", 35,
"selectable", FALSE,
"visible", TRUE,
NULL);
sysprof_line_visualizer_row_add_counter (SYSPROF_LINE_VISUALIZER_ROW (row),
state->batteries[i],
NULL);
gtk_container_add (GTK_CONTAINER (self), row);
}
}
if (state->has_sample)
{
GtkWidget *row = g_object_new (SYSPROF_TYPE_DEPTH_VISUALIZER_ROW,
"zoom-manager", priv->zoom_manager,
"height-request", 35,
"selectable", FALSE,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (self), row);
}
for (guint i = 0; i < state->memory->len; i++)
{
guint counter_id = g_array_index (state->memory, guint, i);
GdkRGBA rgba;
GtkWidget *row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER_ROW,
"title", _("Memory Used"),
"height-request", 35,
"selectable", FALSE,
"visible", TRUE,
"y-lower", 0.0,
NULL);
gdk_rgba_parse (&rgba, "#204a87");
sysprof_line_visualizer_row_add_counter (SYSPROF_LINE_VISUALIZER_ROW (row), counter_id, &rgba);
rgba.alpha = 0.3;
sysprof_line_visualizer_row_set_fill (SYSPROF_LINE_VISUALIZER_ROW (row), counter_id, &rgba);
gtk_container_add (GTK_CONTAINER (self), row);
}
if (state->fps_counter)
{
GdkRGBA rgba;
GtkWidget *row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER_ROW,
/* Translators: FPS is frames per second. */
"title", _("FPS"),
"height-request", 35,
"selectable", FALSE,
"visible", TRUE,
"y-lower", 0.0,
"y-upper", 150.0,
NULL);
gdk_rgba_parse (&rgba, "#204a87");
sysprof_line_visualizer_row_add_counter (SYSPROF_LINE_VISUALIZER_ROW (row), state->fps_counter, &rgba);
rgba.alpha = 0.3;
sysprof_line_visualizer_row_set_fill (SYSPROF_LINE_VISUALIZER_ROW (row), state->fps_counter, &rgba);
gtk_container_add (GTK_CONTAINER (self), row);
}
if (state->pixels_counter)
{
GdkRGBA rgba;
GtkWidget *row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER_ROW,
/* Translators: amount of pixels drawn per frame. */
"title", _("Pixel Bandwidth"),
"height-request", 35,
"selectable", FALSE,
"visible", TRUE,
"y-lower", 0.0,
NULL);
gdk_rgba_parse (&rgba, "#ad7fa8");
sysprof_line_visualizer_row_add_counter (SYSPROF_LINE_VISUALIZER_ROW (row), state->pixels_counter, &rgba);
rgba.alpha = 0.3;
sysprof_line_visualizer_row_set_fill (SYSPROF_LINE_VISUALIZER_ROW (row), state->pixels_counter, &rgba);
gtk_container_add (GTK_CONTAINER (self), row);
}
if (g_hash_table_size (state->mark_groups) < 30)
{
GHashTableIter iter;
g_hash_table_iter_init (&iter, state->mark_groups);
while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL))
{
GtkWidget *row = g_object_new (SYSPROF_TYPE_MARK_VISUALIZER_ROW,
"group", key,
"title", key,
"height-request", 35,
"selectable", FALSE,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (self), row);
}
}
}
static void
discover_new_rows (SysprofVisualizerList *self,
SysprofCaptureReader *reader)
{
static const SysprofCaptureFrameType types[] = {
SYSPROF_CAPTURE_FRAME_CTRDEF,
SYSPROF_CAPTURE_FRAME_MARK,
SYSPROF_CAPTURE_FRAME_SAMPLE,
};
g_autoptr(SysprofCaptureCursor) cursor = NULL;
g_autoptr(GTask) task = NULL;
SysprofCaptureCondition *condition;
Discovery *state;
g_assert (SYSPROF_IS_VISUALIZER_LIST (self));
g_assert (reader != NULL);
/*
* The goal here is to automatically discover what rows should be added to
* the visualizer list based on events we find in the capture file. In the
* future, we might be able to add a UI flow to ask what the user wants or
* denote capabilities at the beginning of the capture stream.
*/
cursor = sysprof_capture_cursor_new (reader);
condition = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
state = g_slice_new0 (Discovery);
state->mark_groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
state->cursor = g_steal_pointer (&cursor);
state->memory = g_array_new (FALSE, FALSE, sizeof (guint));
task = g_task_new (self, NULL, handle_capture_results, NULL);
g_task_set_task_data (task, g_steal_pointer (&state), (GDestroyNotify)discovery_free);
g_task_run_in_thread (task, discover_new_rows_worker);
}
void
sysprof_visualizer_list_set_reader (SysprofVisualizerList *self,
SysprofCaptureReader *reader)
{
SysprofVisualizerListPrivate *priv = sysprof_visualizer_list_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_LIST (self));
if (reader != priv->reader)
{
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
if (reader != NULL)
{
priv->reader = sysprof_capture_reader_ref (reader);
discover_new_rows (self, reader);
}
gtk_container_foreach (GTK_CONTAINER (self),
(GtkCallback)sysprof_visualizer_row_set_reader,
reader);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_READER]);
}
}
void
sysprof_visualizer_list_set_zoom_manager (SysprofVisualizerList *self,
SysprofZoomManager *zoom_manager)
{
SysprofVisualizerListPrivate *priv = sysprof_visualizer_list_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_LIST (self));
g_return_if_fail (SYSPROF_IS_ZOOM_MANAGER (zoom_manager));
if (g_set_object (&priv->zoom_manager, zoom_manager))
{
gtk_container_foreach (GTK_CONTAINER (self),
(GtkCallback)sysprof_visualizer_row_set_zoom_manager,
zoom_manager);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ZOOM_MANAGER]);
}
}
/**
* sysprof_visualizer_list_get_zoom_manager:
*
* Returns: (nullable) (transfer): A #SysprofZoomManager or %NULL.
*/
SysprofZoomManager *
sysprof_visualizer_list_get_zoom_manager (SysprofVisualizerList *self)
{
SysprofVisualizerListPrivate *priv = sysprof_visualizer_list_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_LIST (self), NULL);
return priv->zoom_manager;
}

View File

@ -1,60 +0,0 @@
/* sysprof-visualizer-list.h
*
* Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include "sysprof-capture-reader.h"
#include "sysprof-zoom-manager.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_VISUALIZER_LIST (sysprof_visualizer_list_get_type())
G_DECLARE_DERIVABLE_TYPE (SysprofVisualizerList, sysprof_visualizer_list, SYSPROF, VISUALIZER_LIST, GtkListBox)
struct _SysprofVisualizerListClass
{
GtkListBoxClass parent_class;
gpointer _reserved1;
gpointer _reserved2;
gpointer _reserved3;
gpointer _reserved4;
gpointer _reserved5;
gpointer _reserved6;
gpointer _reserved7;
gpointer _reserved8;
};
GtkWidget *sysprof_visualizer_list_new (void);
void sysprof_visualizer_list_set_reader (SysprofVisualizerList *self,
SysprofCaptureReader *reader);
SysprofCaptureReader *sysprof_visualizer_list_get_reader (SysprofVisualizerList *self);
SysprofZoomManager *sysprof_visualizer_list_get_zoom_manager (SysprofVisualizerList *self);
void sysprof_visualizer_list_set_zoom_manager (SysprofVisualizerList *self,
SysprofZoomManager *zoom_manager);
G_END_DECLS

View File

@ -1,300 +0,0 @@
/* sysprof-visualizer-row.c
*
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-visualizer-row"
#include "config.h"
#include "sysprof-visualizer-row.h"
#include "sysprof-visualizer-row-private.h"
typedef struct
{
SysprofCaptureReader *reader;
SysprofZoomManager *zoom_manager;
} SysprofVisualizerRowPrivate;
enum {
PROP_0,
PROP_ZOOM_MANAGER,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (SysprofVisualizerRow, sysprof_visualizer_row, GTK_TYPE_LIST_BOX_ROW)
gint
_sysprof_visualizer_row_get_graph_width (SysprofVisualizerRow *self)
{
SysprofVisualizerRowPrivate *priv = sysprof_visualizer_row_get_instance_private (self);
gint64 begin_time;
gint64 end_time;
g_assert (SYSPROF_IS_VISUALIZER_ROW (self));
if (priv->reader == NULL || priv->zoom_manager == NULL)
return 0;
begin_time = sysprof_capture_reader_get_start_time (priv->reader);
end_time = sysprof_capture_reader_get_end_time (priv->reader);
return sysprof_zoom_manager_get_width_for_duration (priv->zoom_manager, end_time - begin_time);
}
static void
sysprof_visualizer_row_get_preferred_width (GtkWidget *widget,
gint *min_width,
gint *nat_width)
{
SysprofVisualizerRow *self = (SysprofVisualizerRow *)widget;
gint graph_width;
gint real_min_width = 0;
gint real_nat_width = 0;
g_assert (SYSPROF_IS_VISUALIZER_ROW (self));
GTK_WIDGET_CLASS (sysprof_visualizer_row_parent_class)->get_preferred_width (widget, &real_min_width, &real_nat_width);
graph_width = _sysprof_visualizer_row_get_graph_width (self);
*min_width = *nat_width = real_min_width + graph_width;
}
static void
sysprof_visualizer_row_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofVisualizerRow *self = SYSPROF_VISUALIZER_ROW (object);
switch (prop_id)
{
case PROP_ZOOM_MANAGER:
g_value_set_object (value, sysprof_visualizer_row_get_zoom_manager (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_row_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofVisualizerRow *self = SYSPROF_VISUALIZER_ROW (object);
switch (prop_id)
{
case PROP_ZOOM_MANAGER:
sysprof_visualizer_row_set_zoom_manager (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_row_finalize (GObject *object)
{
SysprofVisualizerRow *self = (SysprofVisualizerRow *)object;
SysprofVisualizerRowPrivate *priv = sysprof_visualizer_row_get_instance_private (self);
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
g_clear_object (&priv->zoom_manager);
G_OBJECT_CLASS (sysprof_visualizer_row_parent_class)->finalize (object);
}
static void
sysprof_visualizer_row_class_init (SysprofVisualizerRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = sysprof_visualizer_row_finalize;
object_class->get_property = sysprof_visualizer_row_get_property;
object_class->set_property = sysprof_visualizer_row_set_property;
widget_class->get_preferred_width = sysprof_visualizer_row_get_preferred_width;
properties [PROP_ZOOM_MANAGER] =
g_param_spec_object ("zoom-manager",
"Zoom Manager",
"Zoom Manager",
SYSPROF_TYPE_ZOOM_MANAGER,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
sysprof_visualizer_row_init (SysprofVisualizerRow *self)
{
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (self), FALSE);
gtk_list_box_row_set_selectable (GTK_LIST_BOX_ROW (self), FALSE);
}
static void
sysprof_visualizer_row_zoom_manager_notify_zoom (SysprofVisualizerRow *self,
GParamSpec *pspec,
SysprofZoomManager *zoom_manager)
{
g_assert (SYSPROF_IS_VISUALIZER_ROW (self));
g_assert (SYSPROF_IS_ZOOM_MANAGER (zoom_manager));
gtk_widget_queue_resize (GTK_WIDGET (self));
}
/**
* sysprof_visualizer_row_get_zoom_manager:
*
* Returns: (transfer none) (nullable): A #SysprofZoomManager or %NULL.
*/
SysprofZoomManager *
sysprof_visualizer_row_get_zoom_manager (SysprofVisualizerRow *self)
{
SysprofVisualizerRowPrivate *priv = sysprof_visualizer_row_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_ROW (self), NULL);
return priv->zoom_manager;
}
void
sysprof_visualizer_row_set_zoom_manager (SysprofVisualizerRow *self,
SysprofZoomManager *zoom_manager)
{
SysprofVisualizerRowPrivate *priv = sysprof_visualizer_row_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_ROW (self));
g_return_if_fail (!zoom_manager || SYSPROF_IS_ZOOM_MANAGER (zoom_manager));
if (priv->zoom_manager != zoom_manager)
{
if (priv->zoom_manager != NULL)
{
g_signal_handlers_disconnect_by_func (priv->zoom_manager,
G_CALLBACK (sysprof_visualizer_row_zoom_manager_notify_zoom),
self);
g_clear_object (&priv->zoom_manager);
}
if (zoom_manager != NULL)
{
priv->zoom_manager = g_object_ref (zoom_manager);
g_signal_connect_object (priv->zoom_manager,
"notify::zoom",
G_CALLBACK (sysprof_visualizer_row_zoom_manager_notify_zoom),
self,
G_CONNECT_SWAPPED);
}
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ZOOM_MANAGER]);
gtk_widget_queue_resize (GTK_WIDGET (self));
}
}
void
sysprof_visualizer_row_set_reader (SysprofVisualizerRow *self,
SysprofCaptureReader *reader)
{
SysprofVisualizerRowPrivate *priv = sysprof_visualizer_row_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_ROW (self));
if (priv->reader != reader)
{
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
if (reader != NULL)
priv->reader = sysprof_capture_reader_ref (reader);
if (SYSPROF_VISUALIZER_ROW_GET_CLASS (self)->set_reader)
SYSPROF_VISUALIZER_ROW_GET_CLASS (self)->set_reader (self, reader);
gtk_widget_queue_resize (GTK_WIDGET (self));
}
}
static inline void
subtract_border (GtkAllocation *alloc,
GtkBorder *border)
{
#if 0
g_print ("Border; %d %d %d %d\n", border->top, border->left, border->bottom, border->right);
#endif
alloc->x += border->left;
alloc->y += border->top;
alloc->width -= border->left + border->right;
alloc->height -= border->top + border->bottom;
}
static void
adjust_alloc_for_borders (SysprofVisualizerRow *self,
GtkAllocation *alloc)
{
GtkStyleContext *style_context;
GtkBorder border;
GtkStateFlags state;
g_assert (SYSPROF_IS_VISUALIZER_ROW (self));
g_assert (alloc != NULL);
state = gtk_widget_get_state_flags (GTK_WIDGET (self));
style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
gtk_style_context_get_border (style_context, state, &border);
subtract_border (alloc, &border);
}
void
sysprof_visualizer_row_translate_points (SysprofVisualizerRow *self,
const SysprofVisualizerRowRelativePoint *in_points,
guint n_in_points,
SysprofVisualizerRowAbsolutePoint *out_points,
guint n_out_points)
{
GtkAllocation alloc;
gint graph_width;
g_return_if_fail (SYSPROF_IS_VISUALIZER_ROW (self));
g_return_if_fail (in_points != NULL);
g_return_if_fail (out_points != NULL);
g_return_if_fail (n_in_points == n_out_points);
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
adjust_alloc_for_borders (self, &alloc);
graph_width = _sysprof_visualizer_row_get_graph_width (self);
for (guint i = 0; i < n_in_points; i++)
{
out_points[i].x = (in_points[i].x * graph_width);
out_points[i].y = alloc.height - (ABS (in_points[i].y) * alloc.height);
}
}

View File

@ -1,83 +0,0 @@
/* sysprof-visualizer-row.h
*
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include <sysprof.h>
#include "sysprof-zoom-manager.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_VISUALIZER_ROW (sysprof_visualizer_row_get_type())
G_DECLARE_DERIVABLE_TYPE (SysprofVisualizerRow, sysprof_visualizer_row, SYSPROF, VISUALIZER_ROW, GtkListBoxRow)
typedef struct
{
gdouble x;
gdouble y;
} SysprofVisualizerRowRelativePoint;
typedef struct
{
gint x;
gint y;
} SysprofVisualizerRowAbsolutePoint;
struct _SysprofVisualizerRowClass
{
GtkListBoxRowClass parent_class;
/**
* SysprofVisualizerRow::set_reader:
*
* Sets the reader that the row should use to extract counters.
* This reader is private to the row and should be freed when
* no longer in use with sysprof_capture_reader_unref().
*/
void (*set_reader) (SysprofVisualizerRow *self,
SysprofCaptureReader *reader);
/*< private >*/
gpointer _reserved[16];
};
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_row_set_reader (SysprofVisualizerRow *self,
SysprofCaptureReader *reader);
SYSPROF_AVAILABLE_IN_ALL
SysprofZoomManager *sysprof_visualizer_row_get_zoom_manager (SysprofVisualizerRow *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_row_set_zoom_manager (SysprofVisualizerRow *self,
SysprofZoomManager *zoom_manager);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_row_translate_points (SysprofVisualizerRow *self,
const SysprofVisualizerRowRelativePoint *in_points,
guint n_in_points,
SysprofVisualizerRowAbsolutePoint *out_points,
guint n_out_points);
G_END_DECLS

View File

@ -18,19 +18,24 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-visualizer-ticks"
#include "config.h"
#include <glib/gi18n.h>
#include <sysprof.h>
#include "sysprof-visualizer-ticks.h"
#define NSEC_PER_SEC G_GINT64_CONSTANT(1000000000)
#define NSEC_PER_HOUR (NSEC_PER_SEC * 60 * 60)
#define NSEC_PER_MIN (NSEC_PER_SEC * 60)
#define NSEC_PER_DAY (NSEC_PER_SEC * 60L * 60L * 24L)
#define NSEC_PER_HOUR (NSEC_PER_SEC * 60L * 60L)
#define NSEC_PER_MIN (NSEC_PER_SEC * 60L)
#define NSEC_PER_MSEC (NSEC_PER_SEC/G_GINT64_CONSTANT(1000))
#define MIN_TICK_DISTANCE 20
#define LABEL_HEIGHT_PX 8
#define LABEL_HEIGHT_PX 10
SYSPROF_ALIGNED_BEGIN (8)
struct _SysprofVisualizerTicks
{
GtkDrawingArea parent_instance;
@ -38,7 +43,7 @@ struct _SysprofVisualizerTicks
gint64 epoch;
gint64 begin_time;
gint64 end_time;
} __attribute__((aligned(8)));
} SYSPROF_ALIGNED_END (8);
enum {
TICK_MINUTES,
@ -50,6 +55,7 @@ enum {
TICK_TENTHS,
TICK_HUNDREDTHS,
TICK_THOUSANDTHS,
TICK_TEN_THOUSANDTHS,
N_TICKS
};
@ -67,6 +73,7 @@ struct {
{ 1, 5, NSEC_PER_SEC / 10 },
{ 1, 4, NSEC_PER_SEC / 100 },
{ 1, 3, NSEC_PER_SEC / 1000 },
{ 1, 1, NSEC_PER_SEC / 10000 },
};
G_DEFINE_TYPE (SysprofVisualizerTicks, sysprof_visualizer_ticks, GTK_TYPE_DRAWING_AREA)
@ -82,6 +89,7 @@ update_label_text (PangoLayout *layout,
gint hours = 0;
gint min = 0;
gint sec = 0;
G_GNUC_UNUSED gint days = 0;
g_assert (PANGO_IS_LAYOUT (layout));
@ -89,6 +97,12 @@ update_label_text (PangoLayout *layout,
time -= tmp;
msec = tmp / 100000L;
if (time >= NSEC_PER_DAY)
{
days = time / NSEC_PER_DAY;
time %= NSEC_PER_DAY;
}
if (time >= NSEC_PER_HOUR)
{
hours = time / NSEC_PER_HOUR;
@ -135,18 +149,6 @@ get_x_for_time (SysprofVisualizerTicks *self,
return alloc->width * x_ratio;
}
#if 0
static inline gint64
get_time_at_x (SysprofVisualizerTicks *self,
const GtkAllocation *alloc,
gdouble x)
{
return self->begin_time
- self->epoch
+ ((self->end_time - self->begin_time) / (gdouble)alloc->width * x);
}
#endif
static gboolean
draw_ticks (SysprofVisualizerTicks *self,
cairo_t *cr,
@ -186,8 +188,10 @@ draw_ticks (SysprofVisualizerTicks *self,
PangoLayout *layout;
PangoFontDescription *font_desc;
gboolean want_msec;
gint last_x2 = G_MININT;
gint w, h;
layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "00:10:00");
layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "00:10:00.0000");
font_desc = pango_font_description_new ();
pango_font_description_set_family_static (font_desc, "Monospace");
@ -195,6 +199,8 @@ draw_ticks (SysprofVisualizerTicks *self,
pango_layout_set_font_description (layout, font_desc);
pango_font_description_free (font_desc);
pango_layout_get_pixel_size (layout, &w, &h);
/* If we are operating on smaller than seconds here, then we want
* to ensure we include msec with the timestamps.
*/
@ -206,9 +212,15 @@ draw_ticks (SysprofVisualizerTicks *self,
{
gdouble x = get_x_for_time (self, &alloc, t);
cairo_move_to (cr, (gint)x + .5 - (gint)half, alloc.height - LABEL_HEIGHT_PX);
if (x < (last_x2 + MIN_TICK_DISTANCE))
continue;
cairo_move_to (cr, (gint)x + 2.5 - (gint)half, 2);
update_label_text (layout, t - self->epoch, want_msec);
pango_layout_get_pixel_size (layout, &w, &h);
pango_cairo_show_layout (cr, layout);
last_x2 = x + w;
}
g_clear_object (&layout);
@ -221,8 +233,8 @@ draw_ticks (SysprofVisualizerTicks *self,
{
gdouble x = get_x_for_time (self, &alloc, t);
cairo_move_to (cr, (gint)x - .5 - (gint)half, 0);
cairo_line_to (cr, (gint)x - .5 - (gint)half, tick_sizing[ticks].height);
cairo_move_to (cr, (gint)x - .5 - (gint)half, alloc.height);
cairo_line_to (cr, (gint)x - .5 - (gint)half, alloc.height - tick_sizing[ticks].height);
count++;
}
@ -235,7 +247,7 @@ draw_ticks (SysprofVisualizerTicks *self,
static gboolean
sysprof_visualizer_ticks_draw (GtkWidget *widget,
cairo_t *cr)
cairo_t *cr)
{
SysprofVisualizerTicks *self = SYSPROF_VISUALIZER_TICKS (widget);
GtkStyleContext *style;
@ -250,9 +262,12 @@ sysprof_visualizer_ticks_draw (GtkWidget *widget,
if (0 == (timespan = self->end_time - self->begin_time))
return GDK_EVENT_PROPAGATE;
style = gtk_widget_get_style_context (widget);
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
style = gtk_widget_get_style_context (widget);
gtk_render_background (style, cr, 0, 0, alloc.width, alloc.height);
state = gtk_widget_get_state_flags (widget);
gtk_style_context_get_color (style, state, &color);
@ -290,8 +305,8 @@ sysprof_visualizer_ticks_draw (GtkWidget *widget,
static void
sysprof_visualizer_ticks_get_preferred_height (GtkWidget *widget,
gint *min_height,
gint *nat_height)
gint *min_height,
gint *nat_height)
{
g_assert (SYSPROF_IS_VISUALIZER_TICKS (widget));
@ -306,7 +321,7 @@ sysprof_visualizer_ticks_class_init (SysprofVisualizerTicksClass *klass)
widget_class->draw = sysprof_visualizer_ticks_draw;
widget_class->get_preferred_height = sysprof_visualizer_ticks_get_preferred_height;
gtk_widget_class_set_css_name (widget_class, "ticks");
gtk_widget_class_set_css_name (widget_class, "SysprofVisualizerTicks");
}
static void
@ -325,8 +340,8 @@ sysprof_visualizer_ticks_new (void)
void
sysprof_visualizer_ticks_get_time_range (SysprofVisualizerTicks *self,
gint64 *begin_time,
gint64 *end_time)
gint64 *begin_time,
gint64 *end_time)
{
g_return_if_fail (SYSPROF_IS_VISUALIZER_TICKS (self));
g_return_if_fail (begin_time != NULL || end_time != NULL);
@ -340,8 +355,8 @@ sysprof_visualizer_ticks_get_time_range (SysprofVisualizerTicks *self,
void
sysprof_visualizer_ticks_set_time_range (SysprofVisualizerTicks *self,
gint64 begin_time,
gint64 end_time)
gint64 begin_time,
gint64 end_time)
{
g_return_if_fail (SYSPROF_IS_VISUALIZER_TICKS (self));
@ -390,3 +405,11 @@ sysprof_visualizer_ticks_set_epoch (SysprofVisualizerTicks *self,
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
gint64
sysprof_visualizer_ticks_get_duration (SysprofVisualizerTicks *self)
{
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_TICKS (self), 0);
return self->end_time - self->begin_time;
}

View File

@ -20,10 +20,6 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
G_BEGIN_DECLS
@ -42,5 +38,6 @@ void sysprof_visualizer_ticks_get_time_range (SysprofVisualizerTicks *self
void sysprof_visualizer_ticks_set_time_range (SysprofVisualizerTicks *self,
gint64 begin_time,
gint64 end_time);
gint64 sysprof_visualizer_ticks_get_duration (SysprofVisualizerTicks *self);
G_END_DECLS

View File

@ -1,762 +0,0 @@
/* sysprof-visualizer-view.c
*
* Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-visualizer-view"
#include "config.h"
#include <glib/gi18n.h>
#include "sysprof-theme-manager.h"
#include "sysprof-visualizer-list.h"
#include "sysprof-visualizer-row.h"
#include "sysprof-visualizer-row-private.h"
#include "sysprof-visualizer-ticks.h"
#include "sysprof-visualizer-view.h"
typedef struct
{
SysprofCaptureReader *reader;
SysprofZoomManager *zoom_manager;
SysprofSelection *selection;
SysprofVisualizerList *list;
GtkScrolledWindow *scroller;
SysprofVisualizerTicks *ticks;
gint64 drag_begin_at;
gint64 drag_selection_at;
guint button_pressed : 1;
} SysprofVisualizerViewPrivate;
typedef struct
{
SysprofVisualizerView *self;
GtkStyleContext *style_context;
cairo_t *cr;
GtkAllocation alloc;
} SelectionDraw;
enum {
PROP_0,
PROP_READER,
PROP_ZOOM_MANAGER,
N_PROPS
};
enum {
VISUALIZER_ADDED,
VISUALIZER_REMOVED,
N_SIGNALS
};
static void buildable_iface_init (GtkBuildableIface *iface);
G_DEFINE_TYPE_EXTENDED (SysprofVisualizerView, sysprof_visualizer_view, GTK_TYPE_BIN, 0,
G_ADD_PRIVATE (SysprofVisualizerView)
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
static GParamSpec *properties [N_PROPS];
static guint signals [N_SIGNALS];
static GtkBuildableIface *parent_buildable;
static void
find_row1 (GtkWidget *widget,
gpointer data)
{
GtkWidget **row1 = data;
if (*row1 == NULL && SYSPROF_IS_VISUALIZER_ROW (widget))
*row1 = widget;
}
static gint64
get_time_from_coordinates (SysprofVisualizerView *self,
gint x,
gint y)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
SysprofVisualizerRow *row1 = NULL;
gint64 begin_time;
gint64 end_time;
gint graph_width;
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
if (priv->reader == NULL)
return 0;
/*
* Find the first row so we can get an idea of how wide the graph is
* (ignoring spacing caused by the widget being wider than the data points.
*/
gtk_container_foreach (GTK_CONTAINER (priv->list), find_row1, &row1);
if (!SYSPROF_IS_VISUALIZER_ROW (row1))
return 0;
begin_time = sysprof_capture_reader_get_start_time (priv->reader);
end_time = sysprof_capture_reader_get_end_time (priv->reader);
graph_width = _sysprof_visualizer_row_get_graph_width (row1);
return begin_time + ((end_time - begin_time) * (x / (gdouble)graph_width));
}
static gint
get_x_for_time_at (SysprofVisualizerView *self,
const GtkAllocation *alloc,
gint64 time_at)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
SysprofVisualizerRow *row1 = NULL;
GtkAdjustment *hadjustment;
gdouble nsec_per_pixel;
gdouble value;
gint64 begin_time;
gint64 end_time;
gint graph_width;
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (alloc != NULL);
/*
* Find the first row so we can get an idea of how wide the graph is
* (ignoring spacing caused by the widget being wider than the data points.
*/
gtk_container_foreach (GTK_CONTAINER (priv->list), find_row1, &row1);
if (!SYSPROF_IS_VISUALIZER_ROW (row1))
return 0;
hadjustment = gtk_scrolled_window_get_hadjustment (priv->scroller);
value = gtk_adjustment_get_value (hadjustment);
begin_time = sysprof_capture_reader_get_start_time (priv->reader);
end_time = sysprof_capture_reader_get_end_time (priv->reader);
graph_width = _sysprof_visualizer_row_get_graph_width (row1);
nsec_per_pixel = (end_time - begin_time) / (gdouble)graph_width;
begin_time += value * nsec_per_pixel;
return ((time_at - begin_time) / nsec_per_pixel);
}
static void
sysprof_visualizer_view_row_added (SysprofVisualizerView *self,
GtkWidget *widget,
SysprofVisualizerList *list)
{
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (GTK_IS_WIDGET (widget));
g_assert (SYSPROF_IS_VISUALIZER_LIST (list));
if (SYSPROF_IS_VISUALIZER_ROW (widget))
g_signal_emit (self, signals [VISUALIZER_ADDED], 0, widget);
}
static void
sysprof_visualizer_view_row_removed (SysprofVisualizerView *self,
GtkWidget *widget,
SysprofVisualizerList *list)
{
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (GTK_IS_WIDGET (widget));
g_assert (SYSPROF_IS_VISUALIZER_LIST (list));
if (SYSPROF_IS_VISUALIZER_ROW (widget))
g_signal_emit (self, signals [VISUALIZER_REMOVED], 0, widget);
}
static void
sysprof_visualizer_view_update_ticks (SysprofVisualizerView *self)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
GtkAdjustment *hadjustment;
GtkAllocation alloc;
gdouble value;
gint64 begin_time;
gint64 end_time;
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
hadjustment = gtk_scrolled_window_get_hadjustment (priv->scroller);
value = gtk_adjustment_get_value (hadjustment);
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
begin_time = get_time_from_coordinates (self, alloc.x + value, alloc.y);
end_time = get_time_from_coordinates (self, alloc.x + value + alloc.width, alloc.y);
sysprof_visualizer_ticks_set_time_range (priv->ticks, begin_time, end_time);
}
static void
sysprof_visualizer_view_hadjustment_value_changed (SysprofVisualizerView *self,
GtkAdjustment *adjustment)
{
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (GTK_IS_ADJUSTMENT (adjustment));
sysprof_visualizer_view_update_ticks (self);
}
static void
sysprof_visualizer_view_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
SysprofVisualizerView *self = (SysprofVisualizerView *)widget;
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (allocation != NULL);
GTK_WIDGET_CLASS (sysprof_visualizer_view_parent_class)->size_allocate (widget, allocation);
sysprof_visualizer_view_update_ticks (self);
}
static void
draw_selection_cb (SysprofSelection *selection,
gint64 range_begin,
gint64 range_end,
gpointer user_data)
{
SelectionDraw *draw = user_data;
GdkRectangle area;
g_assert (SYSPROF_IS_SELECTION (selection));
g_assert (draw != NULL);
g_assert (draw->cr != NULL);
g_assert (SYSPROF_IS_VISUALIZER_VIEW (draw->self));
area.x = get_x_for_time_at (draw->self, &draw->alloc, range_begin);
area.width = get_x_for_time_at (draw->self, &draw->alloc, range_end) - area.x;
area.y = 0;
area.height = draw->alloc.height;
if (area.width < 0)
{
area.width = ABS (area.width);
area.x -= area.width;
}
gtk_render_background (draw->style_context, draw->cr, area.x, area.y, area.width, area.height);
}
static gboolean
sysprof_visualizer_view_draw (GtkWidget *widget,
cairo_t *cr)
{
SysprofVisualizerView *self = (SysprofVisualizerView *)widget;
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
SelectionDraw draw = { 0 };
gboolean ret;
g_assert (GTK_IS_WIDGET (widget));
g_assert (cr != NULL);
draw.style_context = gtk_widget_get_style_context (widget);
draw.self = self;
draw.cr = cr;
gtk_widget_get_allocation (widget, &draw.alloc);
ret = GTK_WIDGET_CLASS (sysprof_visualizer_view_parent_class)->draw (widget, cr);
if (sysprof_selection_get_has_selection (priv->selection) || priv->button_pressed)
{
gtk_style_context_add_class (draw.style_context, "selection");
sysprof_selection_foreach (priv->selection, draw_selection_cb, &draw);
if (priv->button_pressed)
draw_selection_cb (priv->selection, priv->drag_begin_at, priv->drag_selection_at, &draw);
gtk_style_context_remove_class (draw.style_context, "selection");
}
return ret;
}
static gboolean
sysprof_visualizer_view_list_button_press_event (SysprofVisualizerView *self,
GdkEventButton *ev,
SysprofVisualizerList *list)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (ev != NULL);
g_assert (SYSPROF_IS_VISUALIZER_LIST (list));
if (priv->reader == NULL)
return GDK_EVENT_PROPAGATE;
if (ev->button != GDK_BUTTON_PRIMARY)
{
if (sysprof_selection_get_has_selection (priv->selection))
{
sysprof_selection_unselect_all (priv->selection);
return GDK_EVENT_STOP;
}
return GDK_EVENT_PROPAGATE;
}
if ((ev->state & GDK_SHIFT_MASK) == 0)
sysprof_selection_unselect_all (priv->selection);
priv->button_pressed = TRUE;
priv->drag_begin_at = get_time_from_coordinates (self, ev->x, ev->y);
priv->drag_selection_at = priv->drag_begin_at;
gtk_widget_queue_draw (GTK_WIDGET (self));
return GDK_EVENT_PROPAGATE;
}
static gboolean
sysprof_visualizer_view_list_button_release_event (SysprofVisualizerView *self,
GdkEventButton *ev,
SysprofVisualizerList *list)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (ev != NULL);
g_assert (SYSPROF_IS_VISUALIZER_LIST (list));
if (!priv->button_pressed || ev->button != GDK_BUTTON_PRIMARY)
return GDK_EVENT_PROPAGATE;
priv->button_pressed = FALSE;
if (priv->drag_begin_at != priv->drag_selection_at)
{
sysprof_selection_select_range (priv->selection,
priv->drag_begin_at,
priv->drag_selection_at);
priv->drag_begin_at = -1;
priv->drag_selection_at = -1;
}
gtk_widget_queue_draw (GTK_WIDGET (self));
return GDK_EVENT_STOP;
}
static gboolean
sysprof_visualizer_view_list_motion_notify_event (SysprofVisualizerView *self,
GdkEventMotion *ev,
SysprofVisualizerList *list)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (ev != NULL);
g_assert (SYSPROF_IS_VISUALIZER_LIST (list));
if (!priv->button_pressed)
return GDK_EVENT_PROPAGATE;
priv->drag_selection_at = get_time_from_coordinates (self, ev->x, ev->y);
gtk_widget_queue_draw (GTK_WIDGET (self));
return GDK_EVENT_PROPAGATE;
}
static void
sysprof_visualizer_view_list_realize_after (SysprofVisualizerView *self,
SysprofVisualizerList *list)
{
GdkDisplay *display;
GdkWindow *window;
GdkCursor *cursor;
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (SYSPROF_IS_VISUALIZER_LIST (list));
window = gtk_widget_get_window (GTK_WIDGET (list));
display = gdk_window_get_display (window);
cursor = gdk_cursor_new_from_name (display, "text");
gdk_window_set_cursor (window, cursor);
g_clear_object (&cursor);
}
static void
sysprof_visualizer_view_selection_changed (SysprofVisualizerView *self,
SysprofSelection *selection)
{
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (SYSPROF_IS_SELECTION (selection));
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
sysprof_visualizer_view_finalize (GObject *object)
{
SysprofVisualizerView *self = (SysprofVisualizerView *)object;
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
g_clear_object (&priv->zoom_manager);
g_clear_object (&priv->selection);
G_OBJECT_CLASS (sysprof_visualizer_view_parent_class)->finalize (object);
}
static void
sysprof_visualizer_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofVisualizerView *self = SYSPROF_VISUALIZER_VIEW (object);
switch (prop_id)
{
case PROP_READER:
g_value_set_boxed (value, sysprof_visualizer_view_get_reader (self));
break;
case PROP_ZOOM_MANAGER:
g_value_set_object (value, sysprof_visualizer_view_get_zoom_manager (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofVisualizerView *self = SYSPROF_VISUALIZER_VIEW (object);
switch (prop_id)
{
case PROP_READER:
sysprof_visualizer_view_set_reader (self, g_value_get_boxed (value));
break;
case PROP_ZOOM_MANAGER:
sysprof_visualizer_view_set_zoom_manager (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_view_class_init (SysprofVisualizerViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
SysprofThemeManager *theme_manager = sysprof_theme_manager_get_default ();
object_class->finalize = sysprof_visualizer_view_finalize;
object_class->get_property = sysprof_visualizer_view_get_property;
object_class->set_property = sysprof_visualizer_view_set_property;
widget_class->draw = sysprof_visualizer_view_draw;
widget_class->size_allocate = sysprof_visualizer_view_size_allocate;
properties [PROP_READER] =
g_param_spec_boxed ("reader",
"Reader",
"The reader for the visualizers",
SYSPROF_TYPE_CAPTURE_READER,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties [PROP_ZOOM_MANAGER] =
g_param_spec_object ("zoom-manager",
"Zoom Manager",
"The zoom manager for the view",
SYSPROF_TYPE_ZOOM_MANAGER,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
signals [VISUALIZER_ADDED] =
g_signal_new ("visualizer-added",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (SysprofVisualizerViewClass, visualizer_added),
NULL, NULL, NULL,
G_TYPE_NONE, 1, SYSPROF_TYPE_VISUALIZER_ROW);
signals [VISUALIZER_REMOVED] =
g_signal_new ("visualizer-removed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (SysprofVisualizerViewClass, visualizer_removed),
NULL, NULL, NULL,
G_TYPE_NONE, 1, SYSPROF_TYPE_VISUALIZER_ROW);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-visualizer-view.ui");
gtk_widget_class_bind_template_child_private (widget_class, SysprofVisualizerView, list);
gtk_widget_class_bind_template_child_private (widget_class, SysprofVisualizerView, scroller);
gtk_widget_class_bind_template_child_private (widget_class, SysprofVisualizerView, ticks);
gtk_widget_class_set_css_name (widget_class, "visualizers");
sysprof_theme_manager_register_resource (theme_manager, NULL, NULL, "/org/gnome/sysprof/css/SysprofVisualizerView-shared.css");
sysprof_theme_manager_register_resource (theme_manager, "Adwaita", NULL, "/org/gnome/sysprof/css/SysprofVisualizerView-Adwaita.css");
sysprof_theme_manager_register_resource (theme_manager, "Adwaita", "dark", "/org/gnome/sysprof/css/SysprofVisualizerView-Adwaita-dark.css");
g_type_ensure (SYSPROF_TYPE_VISUALIZER_LIST);
g_type_ensure (SYSPROF_TYPE_VISUALIZER_TICKS);
}
static void
sysprof_visualizer_view_init (SysprofVisualizerView *self)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
GtkAdjustment *hadjustment;
priv->drag_begin_at = -1;
priv->drag_selection_at = -1;
gtk_widget_init_template (GTK_WIDGET (self));
priv->selection = g_object_new (SYSPROF_TYPE_SELECTION, NULL);
g_signal_connect_object (priv->selection,
"changed",
G_CALLBACK (sysprof_visualizer_view_selection_changed),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->list,
"button-press-event",
G_CALLBACK (sysprof_visualizer_view_list_button_press_event),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->list,
"button-release-event",
G_CALLBACK (sysprof_visualizer_view_list_button_release_event),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->list,
"motion-notify-event",
G_CALLBACK (sysprof_visualizer_view_list_motion_notify_event),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->list,
"realize",
G_CALLBACK (sysprof_visualizer_view_list_realize_after),
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
g_signal_connect_object (priv->list,
"add",
G_CALLBACK (sysprof_visualizer_view_row_added),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->list,
"remove",
G_CALLBACK (sysprof_visualizer_view_row_removed),
self,
G_CONNECT_SWAPPED);
hadjustment = gtk_scrolled_window_get_hadjustment (priv->scroller);
g_signal_connect_object (hadjustment,
"value-changed",
G_CALLBACK (sysprof_visualizer_view_hadjustment_value_changed),
self,
G_CONNECT_SWAPPED);
}
/**
* sysprof_visualizer_view_get_reader:
*
* Returns: (transfer none): An #SysprofCaptureReader
*/
SysprofCaptureReader *
sysprof_visualizer_view_get_reader (SysprofVisualizerView *self)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_VIEW (self), NULL);
return priv->reader;
}
void
sysprof_visualizer_view_set_reader (SysprofVisualizerView *self,
SysprofCaptureReader *reader)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_VIEW (self));
if (priv->reader != reader)
{
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
if (reader != NULL)
{
gint64 begin_time;
gint64 end_time;
priv->reader = sysprof_capture_reader_ref (reader);
begin_time = sysprof_capture_reader_get_start_time (priv->reader);
end_time = sysprof_capture_reader_get_end_time (priv->reader);
sysprof_visualizer_ticks_set_epoch (priv->ticks, begin_time);
sysprof_visualizer_ticks_set_time_range (priv->ticks, begin_time, end_time);
sysprof_selection_unselect_all (priv->selection);
}
sysprof_visualizer_list_set_reader (priv->list, reader);
sysprof_visualizer_view_update_ticks (self);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_READER]);
}
}
static void
sysprof_visualizer_view_add_child (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *child,
const gchar *type)
{
SysprofVisualizerView *self = (SysprofVisualizerView *)buildable;
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (GTK_IS_BUILDER (builder));
g_assert (G_IS_OBJECT (child));
if (g_strcmp0 (type, "visualizer") == 0 && GTK_IS_WIDGET (child))
{
gtk_container_add (GTK_CONTAINER (priv->list), GTK_WIDGET (child));
return;
}
parent_buildable->add_child (buildable, builder, child, type);
}
static void
buildable_iface_init (GtkBuildableIface *iface)
{
parent_buildable = g_type_interface_peek_parent (iface);
iface->add_child = sysprof_visualizer_view_add_child;
}
static void
sysprof_visualizer_view_zoom_manager_notify_zoom (SysprofVisualizerView *self,
GParamSpec *pspec,
SysprofZoomManager *zoom_manager)
{
g_assert (SYSPROF_IS_VISUALIZER_VIEW (self));
g_assert (SYSPROF_IS_ZOOM_MANAGER (zoom_manager));
sysprof_visualizer_view_update_ticks (self);
}
/**
* sysprof_visualizer_view_get_zoom_manager:
*
* Returns: (transfer none) (nullable): An #SysprofZoomManager or %NULL
*/
SysprofZoomManager *
sysprof_visualizer_view_get_zoom_manager (SysprofVisualizerView *self)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_VIEW (self), NULL);
return priv->zoom_manager;
}
void
sysprof_visualizer_view_set_zoom_manager (SysprofVisualizerView *self,
SysprofZoomManager *zoom_manager)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_VIEW (self));
g_return_if_fail (!zoom_manager || SYSPROF_IS_ZOOM_MANAGER (zoom_manager));
if (priv->zoom_manager != zoom_manager)
{
if (priv->zoom_manager != NULL)
{
g_signal_handlers_disconnect_by_func (priv->zoom_manager,
G_CALLBACK (sysprof_visualizer_view_zoom_manager_notify_zoom),
self);
g_clear_object (&priv->zoom_manager);
}
if (zoom_manager != NULL)
{
priv->zoom_manager = g_object_ref (zoom_manager);
g_signal_connect_object (priv->zoom_manager,
"notify::zoom",
G_CALLBACK (sysprof_visualizer_view_zoom_manager_notify_zoom),
self,
G_CONNECT_SWAPPED);
}
sysprof_visualizer_list_set_zoom_manager (priv->list, zoom_manager);
gtk_widget_queue_resize (GTK_WIDGET (self));
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ZOOM_MANAGER]);
}
}
/**
* sysprof_visualizer_view_get_selection:
*
* Gets the #SysprofSelection instance for the visualizer view.
* This can be used to alter the selection or selections of the visualizers.
*
* Returns: (transfer none): An #SysprofSelection.
*/
SysprofSelection *
sysprof_visualizer_view_get_selection (SysprofVisualizerView *self)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER_VIEW (self), NULL);
return priv->selection;
}
void
_sysprof_visualizer_view_set_hadjustment (SysprofVisualizerView *self,
GtkAdjustment *hadjustment)
{
SysprofVisualizerViewPrivate *priv = sysprof_visualizer_view_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER_VIEW (self));
g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
gtk_scrolled_window_set_hadjustment (priv->scroller, hadjustment);
}

View File

@ -1,70 +0,0 @@
/* sysprof-visualizer-view.h
*
* Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <gtk/gtk.h>
#include <sysprof.h>
#include "sysprof-visualizer-row.h"
#include "sysprof-selection.h"
#include "sysprof-zoom-manager.h"
#include "sysprof-version-macros.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_VISUALIZER_VIEW (sysprof_visualizer_view_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofVisualizerView, sysprof_visualizer_view, SYSPROF, VISUALIZER_VIEW, GtkBin)
struct _SysprofVisualizerViewClass
{
GtkBinClass parent_class;
void (*visualizer_added) (SysprofVisualizerView *self,
SysprofVisualizerRow *visualizer);
void (*visualizer_removed) (SysprofVisualizerView *self,
SysprofVisualizerRow *visualizer);
/*< private >*/
gpointer _reserved[16];
};
SYSPROF_AVAILABLE_IN_ALL
GtkWidget *sysprof_visualizer_view_new (void);
SYSPROF_AVAILABLE_IN_ALL
SysprofCaptureReader *sysprof_visualizer_view_get_reader (SysprofVisualizerView *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_view_set_reader (SysprofVisualizerView *self,
SysprofCaptureReader *reader);
SYSPROF_AVAILABLE_IN_ALL
SysprofZoomManager *sysprof_visualizer_view_get_zoom_manager (SysprofVisualizerView *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_view_set_zoom_manager (SysprofVisualizerView *self,
SysprofZoomManager *zoom_manager);
SYSPROF_AVAILABLE_IN_ALL
SysprofSelection *sysprof_visualizer_view_get_selection (SysprofVisualizerView *self);
G_END_DECLS

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SysprofVisualizerView" parent="GtkBin">
<child>
<object class="GtkOverlay">
<property name="visible">true</property>
<child type="overlay">
<object class="SysprofVisualizerTicks" id="ticks">
<property name="valign">start</property>
<property name="hexpand">true</property>
<property name="visible">true</property>
</object>
<packing>
<property name="pass-through">true</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scroller">
<property name="propagate-natural-height">true</property>
<property name="propagate-natural-width">false</property>
<property name="visible">true</property>
<child>
<object class="SysprofVisualizerList" id="list">
<property name="visible">true</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@ -0,0 +1,346 @@
/* sysprof-visualizer.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-visualizer"
#include "config.h"
#include "sysprof-visualizer.h"
typedef struct
{
gchar *title;
gint64 begin_time;
gint64 end_time;
gint64 duration;
/* The width for [begin_time..end_time] which may be less
* than what the widgets allocation is.
*/
gint data_width;
} SysprofVisualizerPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (SysprofVisualizer, sysprof_visualizer, DZL_TYPE_BIN)
enum {
PROP_0,
PROP_BEGIN_TIME,
PROP_END_TIME,
PROP_TITLE,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
static gboolean
sysprof_visualizer_draw (GtkWidget *widget,
cairo_t *cr)
{
g_assert (SYSPROF_IS_VISUALIZER (widget));
g_assert (cr != NULL);
GTK_WIDGET_CLASS (sysprof_visualizer_parent_class)->draw (widget, cr);
return GDK_EVENT_PROPAGATE;
}
static void
sysprof_visualizer_get_preferred_width (GtkWidget *widget,
gint *min_width,
gint *nat_width)
{
SysprofVisualizer *self = (SysprofVisualizer *)widget;
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
g_assert (SYSPROF_IS_VISUALIZER (self));
g_assert (min_width != NULL);
g_assert (nat_width != NULL);
*min_width = *nat_width = priv->data_width ? priv->data_width : 1;
}
static void
sysprof_visualizer_finalize (GObject *object)
{
SysprofVisualizer *self = (SysprofVisualizer *)object;
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
g_clear_pointer (&priv->title, g_free);
G_OBJECT_CLASS (sysprof_visualizer_parent_class)->finalize (object);
}
static void
sysprof_visualizer_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofVisualizer *self = SYSPROF_VISUALIZER (object);
switch (prop_id)
{
case PROP_TITLE:
g_value_set_string (value, sysprof_visualizer_get_title (self));
break;
case PROP_BEGIN_TIME:
g_value_set_int64 (value, sysprof_visualizer_get_begin_time (self));
break;
case PROP_END_TIME:
g_value_set_int64 (value, sysprof_visualizer_get_end_time (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SysprofVisualizer *self = SYSPROF_VISUALIZER (object);
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
switch (prop_id)
{
case PROP_TITLE:
sysprof_visualizer_set_title (self, g_value_get_string (value));
break;
case PROP_BEGIN_TIME:
priv->begin_time = g_value_get_int64 (value);
priv->duration = priv->end_time - priv->begin_time;
break;
case PROP_END_TIME:
priv->end_time = g_value_get_int64 (value);
priv->duration = priv->end_time - priv->begin_time;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizer_class_init (SysprofVisualizerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = sysprof_visualizer_finalize;
object_class->get_property = sysprof_visualizer_get_property;
object_class->set_property = sysprof_visualizer_set_property;
widget_class->draw = sysprof_visualizer_draw;
widget_class->get_preferred_width = sysprof_visualizer_get_preferred_width;
properties [PROP_BEGIN_TIME] =
g_param_spec_int64 ("begin-time",
"Begin Time",
"Begin Time",
G_MININT64,
G_MAXINT64,
0,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
properties [PROP_END_TIME] =
g_param_spec_int64 ("end-time",
"End Time",
"End Time",
G_MININT64,
G_MAXINT64,
0,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
properties [PROP_TITLE] =
g_param_spec_string ("title",
"Title",
"The title for the row",
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_css_name (widget_class, "SysprofVisualizer");
}
static void
sysprof_visualizer_init (SysprofVisualizer *self)
{
}
const gchar *
sysprof_visualizer_get_title (SysprofVisualizer *self)
{
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER (self), 0);
return priv->title;
}
void
sysprof_visualizer_set_title (SysprofVisualizer *self,
const gchar *title)
{
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER (self));
if (g_strcmp0 (priv->title, title) != 0)
{
g_free (priv->title);
priv->title = g_strdup (title);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
}
}
gint64
sysprof_visualizer_get_begin_time (SysprofVisualizer *self)
{
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER (self), 0);
return priv->begin_time;
}
gint64
sysprof_visualizer_get_end_time (SysprofVisualizer *self)
{
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
g_return_val_if_fail (SYSPROF_IS_VISUALIZER (self), 0);
return priv->end_time;
}
void
sysprof_visualizer_set_reader (SysprofVisualizer *self,
SysprofCaptureReader *reader)
{
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER (self));
g_return_if_fail (reader != NULL);
if (priv->begin_time == 0 || priv->end_time == 0)
{
priv->begin_time = sysprof_capture_reader_get_start_time (reader);
priv->end_time = sysprof_capture_reader_get_end_time (reader);
priv->duration = priv->end_time - priv->begin_time;
}
if (SYSPROF_VISUALIZER_GET_CLASS (self)->set_reader)
SYSPROF_VISUALIZER_GET_CLASS (self)->set_reader (self, reader);
gtk_widget_queue_resize (GTK_WIDGET (self));
}
static inline void
subtract_border (GtkAllocation *alloc,
GtkBorder *border)
{
#if 0
g_print ("Border; %d %d %d %d\n", border->top, border->left, border->bottom, border->right);
#endif
alloc->x += border->left;
alloc->y += border->top;
alloc->width -= border->left + border->right;
alloc->height -= border->top + border->bottom;
}
static void
adjust_alloc_for_borders (SysprofVisualizer *self,
GtkAllocation *alloc)
{
GtkStyleContext *style_context;
GtkBorder border;
GtkStateFlags state;
g_assert (SYSPROF_IS_VISUALIZER (self));
g_assert (alloc != NULL);
state = gtk_widget_get_state_flags (GTK_WIDGET (self));
style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
gtk_style_context_get_border (style_context, state, &border);
subtract_border (alloc, &border);
}
void
sysprof_visualizer_translate_points (SysprofVisualizer *self,
const SysprofVisualizerRelativePoint *in_points,
guint n_in_points,
SysprofVisualizerAbsolutePoint *out_points,
guint n_out_points)
{
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
GtkAllocation alloc;
gint graph_width;
g_return_if_fail (SYSPROF_IS_VISUALIZER (self));
g_return_if_fail (in_points != NULL);
g_return_if_fail (out_points != NULL);
g_return_if_fail (n_in_points == n_out_points);
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
adjust_alloc_for_borders (self, &alloc);
graph_width = priv->data_width;
for (guint i = 0; i < n_in_points; i++)
{
out_points[i].x = (in_points[i].x * graph_width);
out_points[i].y = alloc.height - (ABS (in_points[i].y) * alloc.height);
}
}
void
_sysprof_visualizer_set_data_width (SysprofVisualizer *self,
gint data_width)
{
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
g_return_if_fail (SYSPROF_IS_VISUALIZER (self));
if (priv->data_width != data_width)
{
priv->data_width = data_width;
gtk_widget_queue_resize (GTK_WIDGET (self));
}
}
gint
sysprof_visualizer_get_x_for_time (SysprofVisualizer *self,
gint64 time)
{
SysprofVisualizerPrivate *priv = sysprof_visualizer_get_instance_private (self);
return ((time - priv->begin_time) / (gdouble)priv->duration) * priv->data_width;
}

View File

@ -0,0 +1,82 @@
/* sysprof-visualizer.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <dazzle.h>
#include <sysprof.h>
G_BEGIN_DECLS
typedef struct
{
gdouble x;
gdouble y;
} SysprofVisualizerRelativePoint;
typedef struct
{
gint x;
gint y;
} SysprofVisualizerAbsolutePoint;
#define SYSPROF_TYPE_VISUALIZER (sysprof_visualizer_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (SysprofVisualizer, sysprof_visualizer, SYSPROF, VISUALIZER, DzlBin)
struct _SysprofVisualizerClass
{
DzlBinClass parent_class;
void (*set_reader) (SysprofVisualizer *self,
SysprofCaptureReader *reader);
/*< private >*/
gpointer _reserved[16];
};
SYSPROF_AVAILABLE_IN_ALL
const gchar *sysprof_visualizer_get_title (SysprofVisualizer *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_set_title (SysprofVisualizer *self,
const gchar *title);
SYSPROF_AVAILABLE_IN_ALL
gint64 sysprof_visualizer_get_begin_time (SysprofVisualizer *self);
SYSPROF_AVAILABLE_IN_ALL
gint64 sysprof_visualizer_get_end_time (SysprofVisualizer *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_set_reader (SysprofVisualizer *self,
SysprofCaptureReader *reader);
SYSPROF_AVAILABLE_IN_ALL
gint sysprof_visualizer_get_x_for_time (SysprofVisualizer *self,
gint64 time);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_visualizer_translate_points (SysprofVisualizer *self,
const SysprofVisualizerRelativePoint *in_points,
guint n_in_points,
SysprofVisualizerAbsolutePoint *out_points,
guint n_out_points);
G_END_DECLS

View File

@ -0,0 +1,767 @@
/* sysprof-visualizers-frame.c
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "sysprof-visualizers-frame"
#include "config.h"
#include "sysprof-scrollmap.h"
#include "sysprof-visualizer-group-private.h"
#include "sysprof-visualizer-ticks.h"
#include "sysprof-visualizers-frame.h"
#include "sysprof-zoom-manager.h"
struct _SysprofVisualizersFrame
{
GtkBin parent_instance;
/* Drag selection tracking */
SysprofSelection *selection;
gint64 drag_begin_at;
gint64 drag_selection_at;
guint button_pressed : 1;
/* Help avoid over-resizing/allocating */
GtkAllocation last_alloc;
gdouble last_zoom;
/* Known time range from the capture */
gint64 begin_time;
gint64 end_time;
/* Template Widgets */
GtkListBox *groups;
GtkListBox *visualizers;
SysprofScrollmap *hscrollbar;
SysprofVisualizerTicks *ticks;
GtkScrolledWindow *ticks_scroller;
GtkScrolledWindow *hscroller;
GtkScrolledWindow *vscroller;
SysprofZoomManager *zoom_manager;
GtkScale *zoom_scale;
GtkSizeGroup *left_column;
};
typedef struct
{
GtkListBox *list;
GtkStyleContext *style_context;
cairo_t *cr;
GtkAllocation alloc;
gint64 begin_time;
gint64 duration;
} SelectionDraw;
G_DEFINE_TYPE (SysprofVisualizersFrame, sysprof_visualizers_frame, GTK_TYPE_BIN)
enum {
PROP_0,
PROP_SELECTED_GROUP,
PROP_SELECTION,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
static gint64
get_time_from_x (SysprofVisualizersFrame *self,
gdouble x)
{
GtkAllocation alloc;
gdouble ratio;
gint64 duration;
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
gtk_widget_get_allocation (GTK_WIDGET (self->ticks), &alloc);
duration = sysprof_visualizer_ticks_get_duration (self->ticks);
if (alloc.width < 1)
return 0;
ratio = x / alloc.width;
return self->begin_time + (ratio * duration);
}
static void
draw_selection_cb (SysprofSelection *selection,
gint64 range_begin,
gint64 range_end,
gpointer user_data)
{
SelectionDraw *draw = user_data;
GdkRectangle area;
gdouble x, x2;
g_assert (SYSPROF_IS_SELECTION (selection));
g_assert (draw != NULL);
g_assert (draw->cr != NULL);
g_assert (GTK_IS_LIST_BOX (draw->list));
x = (range_begin - draw->begin_time) / (gdouble)draw->duration;
x2 = (range_end - draw->begin_time) / (gdouble)draw->duration;
area.x = x * draw->alloc.width;
area.width = (x2 * draw->alloc.width) - area.x;
area.y = 0;
area.height = draw->alloc.height;
if (area.width < 0)
{
area.width = ABS (area.width);
area.x -= area.width;
}
gtk_render_background (draw->style_context, draw->cr, area.x + 2, area.y + 2, area.width - 4, area.height - 4);
}
static gboolean
visualizers_draw_after_cb (SysprofVisualizersFrame *self,
cairo_t *cr,
GtkListBox *list)
{
SelectionDraw draw;
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (GTK_IS_LIST_BOX (list));
draw.style_context = gtk_widget_get_style_context (GTK_WIDGET (list));
draw.list = list;
draw.cr = cr;
draw.begin_time = self->begin_time;
draw.duration = sysprof_visualizer_ticks_get_duration (self->ticks);
if (draw.duration == 0)
return GDK_EVENT_PROPAGATE;
gtk_widget_get_allocation (GTK_WIDGET (list), &draw.alloc);
if (sysprof_selection_get_has_selection (self->selection) || self->button_pressed)
{
gtk_style_context_add_class (draw.style_context, "selection");
sysprof_selection_foreach (self->selection, draw_selection_cb, &draw);
if (self->button_pressed)
draw_selection_cb (self->selection, self->drag_begin_at, self->drag_selection_at, &draw);
gtk_style_context_remove_class (draw.style_context, "selection");
}
return GDK_EVENT_PROPAGATE;
}
static void
visualizers_realize_after_cb (SysprofVisualizersFrame *self,
GtkListBox *list)
{
GdkDisplay *display;
GdkWindow *window;
GdkCursor *cursor;
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (GTK_IS_LIST_BOX (list));
window = gtk_widget_get_window (GTK_WIDGET (list));
display = gdk_window_get_display (window);
cursor = gdk_cursor_new_from_name (display, "text");
gdk_window_set_cursor (window, cursor);
g_clear_object (&cursor);
}
static gboolean
visualizers_button_press_event_cb (SysprofVisualizersFrame *self,
GdkEventButton *ev,
GtkListBox *visualizers)
{
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (ev != NULL);
g_assert (GTK_IS_LIST_BOX (visualizers));
if (ev->button != GDK_BUTTON_PRIMARY)
{
if (sysprof_selection_get_has_selection (self->selection))
{
sysprof_selection_unselect_all (self->selection);
return GDK_EVENT_STOP;
}
return GDK_EVENT_PROPAGATE;
}
if ((ev->state & GDK_SHIFT_MASK) == 0)
sysprof_selection_unselect_all (self->selection);
self->button_pressed = TRUE;
self->drag_begin_at = get_time_from_x (self, ev->x);
self->drag_selection_at = self->drag_begin_at;
gtk_widget_queue_draw (GTK_WIDGET (visualizers));
return GDK_EVENT_PROPAGATE;
}
static gboolean
visualizers_button_release_event_cb (SysprofVisualizersFrame *self,
GdkEventButton *ev,
GtkListBox *list)
{
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (ev != NULL);
g_assert (GTK_IS_LIST_BOX (list));
if (!self->button_pressed || ev->button != GDK_BUTTON_PRIMARY)
return GDK_EVENT_PROPAGATE;
self->button_pressed = FALSE;
if (self->drag_begin_at != self->drag_selection_at)
{
sysprof_selection_select_range (self->selection,
self->drag_begin_at,
self->drag_selection_at);
self->drag_begin_at = -1;
self->drag_selection_at = -1;
}
gtk_widget_queue_draw (GTK_WIDGET (list));
return GDK_EVENT_STOP;
}
static gboolean
visualizers_motion_notify_event_cb (SysprofVisualizersFrame *self,
GdkEventMotion *ev,
GtkListBox *list)
{
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (ev != NULL);
g_assert (GTK_IS_LIST_BOX (list));
if (!self->button_pressed)
return GDK_EVENT_PROPAGATE;
self->drag_selection_at = get_time_from_x (self, ev->x);
gtk_widget_queue_draw (GTK_WIDGET (list));
return GDK_EVENT_PROPAGATE;
}
static void
propagate_data_width_cb (GtkWidget *widget,
gpointer user_data)
{
_sysprof_visualizer_group_set_data_width (SYSPROF_VISUALIZER_GROUP (widget),
GPOINTER_TO_INT (user_data));
}
static void
sysprof_visualizers_frame_notify_zoom (SysprofVisualizersFrame *self,
GParamSpec *pspec,
SysprofZoomManager *zoom_manager)
{
gint data_width;
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (SYSPROF_IS_ZOOM_MANAGER (zoom_manager));
data_width = sysprof_zoom_manager_get_width_for_duration (self->zoom_manager,
self->end_time - self->begin_time);
gtk_container_foreach (GTK_CONTAINER (self->visualizers),
propagate_data_width_cb,
GINT_TO_POINTER (data_width));
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
sysprof_visualizers_frame_apply_zoom (SysprofVisualizersFrame *self,
const GtkAllocation *alloc)
{
gint64 duration;
gint64 end_time;
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
duration = sysprof_zoom_manager_get_duration_for_width (self->zoom_manager, alloc->width);
end_time = self->begin_time + duration;
sysprof_scrollmap_set_time_range (self->hscrollbar,
self->begin_time,
MAX (self->end_time, end_time));
sysprof_visualizer_ticks_set_epoch (self->ticks, self->begin_time);
sysprof_visualizer_ticks_set_time_range (self->ticks, self->begin_time, end_time);
}
static gint
find_pos (SysprofVisualizersFrame *self,
const gchar *title,
gint priority)
{
GList *list;
gint pos = 0;
if (title == NULL)
return -1;
list = gtk_container_get_children (GTK_CONTAINER (self->visualizers));
for (const GList *iter = list; iter; iter = iter->next)
{
SysprofVisualizerGroup *group = iter->data;
gint prio = sysprof_visualizer_group_get_priority (group);
const gchar *item = sysprof_visualizer_group_get_title (group);
if (priority < prio ||
(priority == prio && g_strcmp0 (title, item) < 0))
break;
pos++;
}
g_list_free (list);
return pos;
}
static void
sysprof_visualizers_frame_add (GtkContainer *container,
GtkWidget *child)
{
SysprofVisualizersFrame *self = (SysprofVisualizersFrame *)container;
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (GTK_IS_WIDGET (child));
if (SYSPROF_IS_VISUALIZER_GROUP (child))
{
SysprofVisualizerGroupHeader *header;
const gchar *title = sysprof_visualizer_group_get_title (SYSPROF_VISUALIZER_GROUP (child));
gint priority = sysprof_visualizer_group_get_priority (SYSPROF_VISUALIZER_GROUP (child));
gint pos = find_pos (self, title, priority);
gtk_list_box_insert (self->visualizers, child, pos);
header = _sysprof_visualizer_group_header_new ();
g_object_set_data (G_OBJECT (header), "VISUALIZER_GROUP", child);
gtk_list_box_insert (self->groups, GTK_WIDGET (header), pos);
_sysprof_visualizer_group_set_header (SYSPROF_VISUALIZER_GROUP (child), header);
gtk_widget_show (GTK_WIDGET (header));
sysprof_visualizers_frame_notify_zoom (self, NULL, self->zoom_manager);
return;
}
GTK_CONTAINER_CLASS (sysprof_visualizers_frame_parent_class)->add (container, child);
}
static void
sysprof_visualizers_frame_size_allocate (GtkWidget *widget,
GtkAllocation *alloc)
{
SysprofVisualizersFrame *self = (SysprofVisualizersFrame *)widget;
gdouble zoom;
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (alloc != NULL);
GTK_WIDGET_CLASS (sysprof_visualizers_frame_parent_class)->size_allocate (widget, alloc);
zoom = sysprof_zoom_manager_get_zoom (self->zoom_manager);
if (alloc->width != self->last_alloc.width || zoom != self->last_zoom)
sysprof_visualizers_frame_apply_zoom (self, alloc);
self->last_alloc = *alloc;
self->last_zoom = zoom;
}
static void
sysprof_visualizers_frame_selection_changed (SysprofVisualizersFrame *self,
SysprofSelection *selection)
{
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (SYSPROF_IS_SELECTION (selection));
gtk_widget_queue_draw (GTK_WIDGET (self->visualizers));
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SELECTION]);
}
static void
sysprof_visualizers_frame_group_activated_cb (SysprofVisualizersFrame *self,
SysprofVisualizerGroupHeader *row,
GtkListBox *list)
{
SysprofVisualizerGroup *group;
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_assert (SYSPROF_IS_VISUALIZER_GROUP_HEADER (row));
group = g_object_get_data (G_OBJECT (row), "VISUALIZER_GROUP");
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
g_signal_emit_by_name (group, "group-activated");
}
static void
sysprof_visualizers_frame_finalize (GObject *object)
{
SysprofVisualizersFrame *self = (SysprofVisualizersFrame *)object;
g_clear_object (&self->selection);
G_OBJECT_CLASS (sysprof_visualizers_frame_parent_class)->finalize (object);
}
static void
sysprof_visualizers_frame_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofVisualizersFrame *self = SYSPROF_VISUALIZERS_FRAME (object);
switch (prop_id)
{
case PROP_SELECTED_GROUP:
g_value_set_object (value, sysprof_visualizers_frame_get_selected_group (self));
break;
case PROP_SELECTION:
g_value_set_object (value, sysprof_visualizers_frame_get_selection (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_visualizers_frame_class_init (SysprofVisualizersFrameClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
object_class->finalize = sysprof_visualizers_frame_finalize;
object_class->get_property = sysprof_visualizers_frame_get_property;
widget_class->size_allocate = sysprof_visualizers_frame_size_allocate;
container_class->add = sysprof_visualizers_frame_add;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-visualizers-frame.ui");
gtk_widget_class_set_css_name (widget_class, "SysprofVisualizersFrame");
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, groups);
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, hscrollbar);
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, hscroller);
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, left_column);
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, ticks);
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, ticks_scroller);
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, visualizers);
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, vscroller);
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, zoom_manager);
gtk_widget_class_bind_template_child (widget_class, SysprofVisualizersFrame, zoom_scale);
properties [PROP_SELECTED_GROUP] =
g_param_spec_object ("selected-group",
"Selected Group",
"The selected group",
SYSPROF_TYPE_VISUALIZER_GROUP,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
properties [PROP_SELECTION] =
g_param_spec_object ("selection",
"Selection",
"The time selection",
SYSPROF_TYPE_SELECTION,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
g_type_ensure (SYSPROF_TYPE_SCROLLMAP);
g_type_ensure (SYSPROF_TYPE_VISUALIZER_TICKS);
g_type_ensure (SYSPROF_TYPE_ZOOM_MANAGER);
}
static void
sysprof_visualizers_frame_init (SysprofVisualizersFrame *self)
{
GtkAdjustment *hadj;
GtkAdjustment *zadj;
gtk_widget_init_template (GTK_WIDGET (self));
self->selection = g_object_new (SYSPROF_TYPE_SELECTION, NULL);
zadj = sysprof_zoom_manager_get_adjustment (self->zoom_manager);
hadj = gtk_scrolled_window_get_hadjustment (self->hscroller);
gtk_scrolled_window_set_hadjustment (self->ticks_scroller, hadj);
gtk_range_set_adjustment (GTK_RANGE (self->hscrollbar), hadj);
gtk_range_set_adjustment (GTK_RANGE (self->zoom_scale), zadj);
gtk_widget_insert_action_group (GTK_WIDGET (self),
"zoom",
G_ACTION_GROUP (self->zoom_manager));
g_signal_connect_object (self->groups,
"row-activated",
G_CALLBACK (sysprof_visualizers_frame_group_activated_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (self->selection,
"changed",
G_CALLBACK (sysprof_visualizers_frame_selection_changed),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (self->visualizers,
"draw",
G_CALLBACK (visualizers_draw_after_cb),
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
g_signal_connect_object (self->visualizers,
"realize",
G_CALLBACK (visualizers_realize_after_cb),
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
g_signal_connect_object (self->visualizers,
"button-press-event",
G_CALLBACK (visualizers_button_press_event_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (self->visualizers,
"button-release-event",
G_CALLBACK (visualizers_button_release_event_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (self->visualizers,
"motion-notify-event",
G_CALLBACK (visualizers_motion_notify_event_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (self->zoom_manager,
"notify::zoom",
G_CALLBACK (sysprof_visualizers_frame_notify_zoom),
self,
G_CONNECT_SWAPPED | G_CONNECT_AFTER);
}
/**
* sysprof_visualizers_frame_get_selected_group:
*
* Gets the currently selected group.
*
* Returns: (transfer none) (nullable): the selected row
*
* Since: 3.34
*/
SysprofVisualizerGroup *
sysprof_visualizers_frame_get_selected_group (SysprofVisualizersFrame *self)
{
GtkListBoxRow *row;
g_return_val_if_fail (SYSPROF_IS_VISUALIZERS_FRAME (self), NULL);
row = gtk_list_box_get_selected_row (self->groups);
return SYSPROF_VISUALIZER_GROUP (row);
}
/**
* sysprof_visualizers_frame_get_selection:
*
* Get the time selection
*
* Returns: (transfer none): a #SysprofSelection
*
* Since: 3.34
*/
SysprofSelection *
sysprof_visualizers_frame_get_selection (SysprofVisualizersFrame *self)
{
g_return_val_if_fail (SYSPROF_IS_VISUALIZERS_FRAME (self), NULL);
return self->selection;
}
static gint
compare_gint64 (const gint64 *a,
const gint64 *b)
{
if (*a < *b)
return -1;
else if (*a > *b)
return 1;
else
return 0;
}
static gboolean
index_frame_times_frame_cb (const SysprofCaptureFrame *frame,
gpointer user_data)
{
GArray *array = user_data;
/* Track timing, but ignore some common types at startup */
if (frame->type != SYSPROF_CAPTURE_FRAME_MAP &&
frame->type != SYSPROF_CAPTURE_FRAME_PROCESS)
g_array_append_val (array, frame->time);
return TRUE;
}
static void
index_frame_times_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
SysprofCaptureCursor *cursor = task_data;
GArray *timings = NULL;
g_assert (G_IS_TASK (task));
g_assert (SYSPROF_IS_VISUALIZERS_FRAME (source_object));
g_assert (cursor != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
timings = g_array_new (FALSE, FALSE, sizeof (gint64));
sysprof_capture_cursor_foreach (cursor, index_frame_times_frame_cb, timings);
g_array_sort (timings, (GCompareFunc) compare_gint64);
g_task_return_pointer (task,
g_steal_pointer (&timings),
(GDestroyNotify) g_array_unref);
}
void
sysprof_visualizers_frame_load_async (SysprofVisualizersFrame *self,
SysprofCaptureReader *reader,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
GtkAllocation alloc;
g_return_if_fail (SYSPROF_IS_VISUALIZERS_FRAME (self));
g_return_if_fail (reader != NULL);
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
gtk_widget_get_allocation (GTK_WIDGET (self->ticks), &alloc);
/* At this point, the SysprofDisplay should have already scanned the
* reader for all of the events and therefore we can trust the begin
* and end time for the capture.
*/
self->begin_time = sysprof_capture_reader_get_start_time (reader);
self->end_time = sysprof_capture_reader_get_end_time (reader);
if (alloc.width)
sysprof_visualizers_frame_apply_zoom (self, &alloc);
/* Now we need to run through the frames and index their times
* so that we can calculate the number of items per bucket when
* drawing the scrollbar.
*/
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, sysprof_visualizers_frame_load_async);
g_task_set_task_data (task,
sysprof_capture_cursor_new (reader),
(GDestroyNotify) sysprof_capture_cursor_unref);
g_task_run_in_thread (task, index_frame_times_worker);
}
gboolean
sysprof_visualizers_frame_load_finish (SysprofVisualizersFrame *self,
GAsyncResult *result,
GError **error)
{
g_autoptr(GArray) timings = NULL;
g_return_val_if_fail (SYSPROF_IS_VISUALIZERS_FRAME (self), FALSE);
g_return_val_if_fail (G_IS_TASK (result), FALSE);
if ((timings = g_task_propagate_pointer (G_TASK (result), error)))
{
GtkAllocation alloc;
gtk_widget_get_allocation (GTK_WIDGET (self->ticks), &alloc);
sysprof_scrollmap_set_timings (self->hscrollbar, timings);
sysprof_visualizers_frame_apply_zoom (self, &alloc);
gtk_widget_queue_resize (GTK_WIDGET (self));
return TRUE;
}
return FALSE;
}
/**
* sysprof_visualizers_frame_get_zoom_manager:
*
* Gets the zoom manager for the frame.
*
* Returns: (transfer none): a #SysprofZoomManager
*/
SysprofZoomManager *
sysprof_visualizers_frame_get_zoom_manager (SysprofVisualizersFrame *self)
{
g_return_val_if_fail (SYSPROF_IS_VISUALIZERS_FRAME (self), NULL);
return self->zoom_manager;
}
/**
* sysprof_visualizers_frame_get_size_group:
*
* gets the left column size group.
*
* Returns: (transfer none): a size group
*/
GtkSizeGroup *
sysprof_visualizers_frame_get_size_group (SysprofVisualizersFrame *self)
{
g_return_val_if_fail (SYSPROF_IS_VISUALIZERS_FRAME (self), NULL);
return self->left_column;
}
/**
* sysprof_visualizers_frame_get_hadjustment:
*
* Gets the scroll adjustment used for horizontal scrolling
*
* Returns: (transfer none): a #GtkAdjustment
*/
GtkAdjustment *
sysprof_visualizers_frame_get_hadjustment (SysprofVisualizersFrame *self)
{
g_return_val_if_fail (SYSPROF_IS_VISUALIZERS_FRAME (self), NULL);
return gtk_range_get_adjustment (GTK_RANGE (self->hscrollbar));
}

View File

@ -0,0 +1,49 @@
/* sysprof-visualizers-frame.h
*
* Copyright 2019 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <gtk/gtk.h>
#include <sysprof.h>
#include "sysprof-visualizer-group.h"
#include "sysprof-zoom-manager.h"
G_BEGIN_DECLS
#define SYSPROF_TYPE_VISUALIZERS_FRAME (sysprof_visualizers_frame_get_type())
G_DECLARE_FINAL_TYPE (SysprofVisualizersFrame, sysprof_visualizers_frame, SYSPROF, VISUALIZERS_FRAME, GtkBin)
SysprofSelection *sysprof_visualizers_frame_get_selection (SysprofVisualizersFrame *self);
SysprofVisualizerGroup *sysprof_visualizers_frame_get_selected_group (SysprofVisualizersFrame *self);
SysprofZoomManager *sysprof_visualizers_frame_get_zoom_manager (SysprofVisualizersFrame *self);
void sysprof_visualizers_frame_load_async (SysprofVisualizersFrame *self,
SysprofCaptureReader *reader,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean sysprof_visualizers_frame_load_finish (SysprofVisualizersFrame *self,
GAsyncResult *result,
GError **error);
GtkSizeGroup *sysprof_visualizers_frame_get_size_group (SysprofVisualizersFrame *self);
GtkAdjustment *sysprof_visualizers_frame_get_hadjustment (SysprofVisualizersFrame *self);
G_END_DECLS

View File

@ -0,0 +1,419 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<template class="SysprofVisualizersFrame" parent="GtkBin">
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox" id="box1">
<property name="width_request">125</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="visible">true</property>
<property name="margin-top">3</property>
<property name="margin-bottom">3</property>
<property name="margin-start">7</property>
<property name="margin-end">7</property>
<style>
<class name="left-column"/>
</style>
<child type="center">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">6</property>
<property name="margin_end">6</property>
<property name="margin_top">3</property>
<property name="margin_bottom">3</property>
<property name="label" translatable="yes">Instruments</property>
<style>
<class name="dim-label"/>
</style>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkButton">
<property name="action-name">display.page</property>
<property name="action-target">'details'</property>
<property name="tooltip-text" translatable="yes">Select for more details</property>
<property name="visible">true</property>
<style>
<class name="image-button"/>
<class name="small-button"/>
<class name="flat"/>
</style>
<child>
<object class="GtkImage">
<property name="icon-name">preferences-system-details-symbolic</property>
<property name="pixel-size">16</property>
<property name="visible">true</property>
</object>
</child>
</object>
<packing>
<property name="pack-type">end</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="ticks_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="vexpand">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="ticks_scroller">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="hscrollbar_policy">external</property>
<property name="vscrollbar_policy">never</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="SysprofVisualizerTicks" id="ticks">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="vscroller">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="vexpand">True</property>
<property name="hscrollbar_policy">never</property>
<property name="propagate_natural_height">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkListBox" id="groups">
<property name="width_request">125</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">False</property>
<property name="selection_mode">browse</property>
<style>
<class name="left-column"/>
<class name="visualizer-groups"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="hscroller">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="hscrollbar_policy">external</property>
<property name="vscrollbar_policy">never</property>
<property name="propagate_natural_height">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkListBox" id="visualizers">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">none</property>
<property name="activate_on_single_click">False</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<style>
<class name="inline-toolbar"/>
</style>
<child>
<object class="GtkBox" id="box2">
<property name="width_request">125</property>
<property name="visible">True</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="can_focus">False</property>
<property name="hexpand">False</property>
<style>
<class name="left-column"/>
</style>
<child>
<object class="GtkButton" id="zoom_out">
<property name="action-name">zoom.zoom-out</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">zoom-out-symbolic</property>
</object>
</child>
<style>
<class name="image-button"/>
<class name="small-button"/>
<class name="flat"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScale" id="zoom_scale">
<property name="width_request">175</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="round_digits">1</property>
<property name="draw_value">False</property>
<marks>
<mark value="0.0" position="bottom"/>
</marks>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="zoom_in">
<property name="action-name">zoom.zoom-in</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="relief">none</property>
<property name="valign">center</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">zoom-in-symbolic</property>
</object>
</child>
<style>
<class name="image-button"/>
<class name="small-button"/>
<class name="flat"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="SysprofScrollmap" id="hscrollbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</template>
<object class="GtkSizeGroup" id="left_column">
<widgets>
<widget name="box1"/>
<widget name="groups"/>
<widget name="box2"/>
</widgets>
</object>
<object class="GtkSizeGroup" id="top_row">
<property name="mode">vertical</property>
<widgets>
<widget name="box1"/>
<widget name="ticks_box"/>
</widgets>
</object>
<object class="GtkSizeGroup" id="row_size_group">
<widgets>
<widget name="ticks"/>
<widget name="visualizers"/>
</widgets>
</object>
<object class="SysprofZoomManager" id="zoom_manager"/>
</interface>

View File

@ -20,61 +20,38 @@
#pragma once
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
# error "Only <sysprof-ui.h> can be included directly."
#endif
#include <glib-object.h>
#include "sysprof-version-macros.h"
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define SYSPROF_TYPE_ZOOM_MANAGER (sysprof_zoom_manager_get_type())
SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (SysprofZoomManager, sysprof_zoom_manager, SYSPROF, ZOOM_MANAGER, GObject)
SYSPROF_AVAILABLE_IN_ALL
SysprofZoomManager *sysprof_zoom_manager_new (void);
SYSPROF_AVAILABLE_IN_ALL
GtkAdjustment *sysprof_zoom_manager_get_adjustment (SysprofZoomManager *self);
gboolean sysprof_zoom_manager_get_can_zoom_in (SysprofZoomManager *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_zoom_manager_get_can_zoom_out (SysprofZoomManager *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_zoom_manager_get_min_zoom (SysprofZoomManager *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_zoom_manager_get_max_zoom (SysprofZoomManager *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_zoom_manager_set_min_zoom (SysprofZoomManager *self,
gdouble min_zoom);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_zoom_manager_set_max_zoom (SysprofZoomManager *self,
gdouble max_zoom);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_zoom_manager_zoom_in (SysprofZoomManager *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_zoom_manager_zoom_out (SysprofZoomManager *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_zoom_manager_reset (SysprofZoomManager *self);
SYSPROF_AVAILABLE_IN_ALL
gdouble sysprof_zoom_manager_get_zoom (SysprofZoomManager *self);
SYSPROF_AVAILABLE_IN_ALL
void sysprof_zoom_manager_set_zoom (SysprofZoomManager *self,
gdouble zoom);
SYSPROF_AVAILABLE_IN_ALL
gchar *sysprof_zoom_manager_get_zoom_label (SysprofZoomManager *self);
SYSPROF_AVAILABLE_IN_ALL
gint sysprof_zoom_manager_get_width_for_duration (SysprofZoomManager *self,
gint64 duration);
SYSPROF_AVAILABLE_IN_ALL
gint64 sysprof_zoom_manager_get_duration_for_width (SysprofZoomManager *self,
gint width);
SYSPROF_AVAILABLE_IN_ALL
gdouble sysprof_zoom_manager_fit_zoom_for_duration (SysprofZoomManager *self,
gint64 duration,
gint width);
SYSPROF_AVAILABLE_IN_ALL
gdouble sysprof_zoom_manager_get_offset_at_time (SysprofZoomManager *self,
gint64 offset,
gint width);

View File

@ -61,7 +61,8 @@ if get_option('enable_gtk')
dependencies: test_ui_deps,
)
test_zoom = executable('test-zoom', 'test-zoom.c',
test_zoom = executable('test-zoom',
['test-zoom.c', '../libsysprof-ui/sysprof-zoom-manager.c'],
c_args: test_cflags,
dependencies: test_ui_deps,
)

View File

@ -25,7 +25,7 @@ main (gint argc,
gchar *argv[])
{
GtkWindow *window;
SysprofCaptureView *view;
SysprofDisplay *view;
SysprofCaptureReader *reader;
g_autoptr(GError) error = NULL;
@ -44,16 +44,16 @@ main (gint argc,
}
window = g_object_new (GTK_TYPE_WINDOW,
"title", "SysprofCaptureView",
"title", "SysprofDisplay",
"default-width", 800,
"default-height", 600,
NULL);
view = g_object_new (SYSPROF_TYPE_CAPTURE_VIEW,
view = g_object_new (SYSPROF_TYPE_DISPLAY,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (view));
sysprof_capture_view_load_async (view, reader, NULL, NULL, NULL);
sysprof_display_load_async (view, reader, NULL, NULL, NULL);
g_signal_connect (window, "delete-event", gtk_main_quit, NULL);
gtk_window_present (GTK_WINDOW (window));