libsysprof-gtk: port mark-chart to use Chart and Series

This commit is contained in:
Christian Hergert
2023-06-26 15:32:54 -07:00
parent 045877dabc
commit a3912b27e3
5 changed files with 92 additions and 569 deletions

View File

@ -3,6 +3,7 @@
<gresource prefix="/libsysprof-gtk">
<file preprocess="xml-stripblanks">sysprof-callgraph-view.ui</file>
<file preprocess="xml-stripblanks">sysprof-mark-chart.ui</file>
<file preprocess="xml-stripblanks">sysprof-mark-chart-row.ui</file>
<file preprocess="xml-stripblanks">sysprof-mark-table.ui</file>
<file preprocess="xml-stripblanks">sysprof-weighted-callgraph-view.ui</file>
<file>style.css</file>

View File

@ -23,6 +23,7 @@
#include <sysprof-analyze.h>
#include "sysprof-session.h"
#include "sysprof-time-series.h"
G_BEGIN_DECLS
@ -30,16 +31,10 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (SysprofMarkChartItem, sysprof_mark_chart_item, SYSPROF, MARK_CHART_ITEM, GObject)
SysprofMarkChartItem *sysprof_mark_chart_item_new (SysprofSession *session,
SysprofMarkCatalog *catalog);
SysprofMarkCatalog *sysprof_mark_chart_item_get_catalog (SysprofMarkChartItem *self);
SysprofSession *sysprof_mark_chart_item_get_session (SysprofMarkChartItem *self);
void sysprof_mark_chart_item_load_time_series (SysprofMarkChartItem *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
SysprofTimeSeries *sysprof_mark_chart_item_load_time_series_finish (SysprofMarkChartItem *self,
GAsyncResult *result,
GError **error);
SysprofMarkChartItem *sysprof_mark_chart_item_new (SysprofSession *session,
SysprofMarkCatalog *catalog);
SysprofMarkCatalog *sysprof_mark_chart_item_get_catalog (SysprofMarkChartItem *self);
SysprofSession *sysprof_mark_chart_item_get_session (SysprofMarkChartItem *self);
SysprofTimeSeries *sysprof_mark_chart_item_get_series (SysprofMarkChartItem *self);
G_END_DECLS

View File

@ -24,37 +24,39 @@
struct _SysprofMarkChartItem
{
GObject parent_instance;
SysprofSession *session;
GObject parent_instance;
SysprofSession *session;
SysprofMarkCatalog *catalog;
GtkFilterListModel *filtered;
SysprofSeries *series;
};
enum {
PROP_0,
PROP_SESSION,
PROP_CATALOG,
PROP_SERIES,
N_PROPS
};
enum {
CHANGED,
N_SIGNALS
};
G_DEFINE_FINAL_TYPE (SysprofMarkChartItem, sysprof_mark_chart_item, G_TYPE_OBJECT)
static GParamSpec *properties[N_PROPS];
static guint signals[N_SIGNALS];
static void
sysprof_mark_chart_item_session_notify_selected_time_cb (SysprofMarkChartItem *self,
GParamSpec *pspec,
SysprofSession *session)
sysprof_mark_chart_item_constructed (GObject *object)
{
g_assert (SYSPROF_IS_MARK_CHART_ITEM (self));
g_assert (SYSPROF_IS_SESSION (session));
SysprofMarkChartItem *self = (SysprofMarkChartItem *)object;
g_signal_emit (self, signals[CHANGED], 0);
G_OBJECT_CLASS (sysprof_mark_chart_item_parent_class)->constructed (object);
if (self->catalog == NULL || self->session == NULL)
g_return_if_reached ();
g_object_set (self->filtered,
"model", G_LIST_MODEL (self->catalog),
"filter", sysprof_session_get_filter (self->session),
NULL);
}
static void
@ -64,6 +66,8 @@ sysprof_mark_chart_item_dispose (GObject *object)
g_clear_object (&self->session);
g_clear_object (&self->catalog);
g_clear_object (&self->filtered);
g_clear_object (&self->series);
G_OBJECT_CLASS (sysprof_mark_chart_item_parent_class)->dispose (object);
}
@ -86,6 +90,10 @@ sysprof_mark_chart_item_get_property (GObject *object,
g_value_set_object (value, sysprof_mark_chart_item_get_session (self));
break;
case PROP_SERIES:
g_value_set_object (value, sysprof_mark_chart_item_get_series (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -107,11 +115,6 @@ sysprof_mark_chart_item_set_property (GObject *object,
case PROP_SESSION:
self->session = g_value_dup_object (value);
g_signal_connect_object (self->session,
"notify::selected-time",
G_CALLBACK (sysprof_mark_chart_item_session_notify_selected_time_cb),
self,
G_CONNECT_SWAPPED);
break;
default:
@ -124,6 +127,7 @@ sysprof_mark_chart_item_class_init (SysprofMarkChartItemClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = sysprof_mark_chart_item_constructed;
object_class->dispose = sysprof_mark_chart_item_dispose;
object_class->get_property = sysprof_mark_chart_item_get_property;
object_class->set_property = sysprof_mark_chart_item_set_property;
@ -138,20 +142,24 @@ sysprof_mark_chart_item_class_init (SysprofMarkChartItemClass *klass)
SYSPROF_TYPE_SESSION,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
properties[PROP_SERIES] =
g_param_spec_object ("series", NULL, NULL,
SYSPROF_TYPE_TIME_SERIES,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
signals[CHANGED] = g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
sysprof_mark_chart_item_init (SysprofMarkChartItem *self)
{
self->filtered = gtk_filter_list_model_new (NULL, NULL);
gtk_filter_list_model_set_incremental (self->filtered, TRUE);
self->series = sysprof_time_series_new (NULL,
g_object_ref (G_LIST_MODEL (self->filtered)),
gtk_property_expression_new (SYSPROF_TYPE_DOCUMENT_MARK, NULL, "time"),
gtk_property_expression_new (SYSPROF_TYPE_DOCUMENT_MARK, NULL, "duration"));
}
SysprofMarkChartItem *
@ -179,92 +187,10 @@ sysprof_mark_chart_item_get_session (SysprofMarkChartItem *self)
return self->session;
}
typedef struct _LoadTimeSeries
{
GListModel *model;
SysprofTimeSpan time_span;
} LoadTimeSeries;
static void
load_time_series_free (LoadTimeSeries *state)
{
g_clear_object (&state->model);
g_free (state);
}
static void
load_time_series_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
LoadTimeSeries *state = task_data;
g_autoptr(SysprofTimeSeries) series = NULL;
guint n_items;
g_assert (G_IS_TASK (task));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
series = sysprof_time_series_new (state->model, state->time_span);
n_items = g_list_model_get_n_items (state->model);
for (guint i = 0; i < n_items; i++)
{
g_autoptr(SysprofDocumentMark) mark = g_list_model_get_item (state->model, i);
SysprofTimeSpan time_span;
time_span.begin_nsec = sysprof_document_frame_get_time (SYSPROF_DOCUMENT_FRAME (mark));
time_span.end_nsec = time_span.begin_nsec + sysprof_document_mark_get_duration (mark);
sysprof_time_series_add (series, time_span, i);
}
sysprof_time_series_sort (series);
g_task_return_pointer (task,
g_steal_pointer (&series),
(GDestroyNotify)sysprof_time_series_unref);
}
void
sysprof_mark_chart_item_load_time_series (SysprofMarkChartItem *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
LoadTimeSeries *state;
g_return_if_fail (SYSPROF_IS_MARK_CHART_ITEM (self));
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_mark_chart_item_load_time_series);
if (self->catalog == NULL || self->session == NULL)
{
g_task_return_new_error (task,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"No available data to generate");
return;
}
state = g_new0 (LoadTimeSeries, 1);
state->model = g_object_ref (G_LIST_MODEL (self->catalog));
state->time_span = *sysprof_session_get_selected_time (self->session);
g_task_set_task_data (task, state, (GDestroyNotify)load_time_series_free);
g_task_run_in_thread (task, load_time_series_worker);
}
SysprofTimeSeries *
sysprof_mark_chart_item_load_time_series_finish (SysprofMarkChartItem *self,
GAsyncResult *result,
GError **error)
sysprof_mark_chart_item_get_series (SysprofMarkChartItem *self)
{
g_return_val_if_fail (SYSPROF_IS_MARK_CHART_ITEM (self), NULL);
g_return_val_if_fail (G_IS_TASK (result), NULL);
return g_task_propagate_pointer (G_TASK (result), error);
return SYSPROF_TIME_SERIES (self->series);
}

View File

@ -23,26 +23,18 @@
#include <sysprof-analyze.h>
#include "sysprof-mark-chart-row-private.h"
#include "sysprof-chart.h"
#include "sysprof-time-series-item.h"
#include "sysprof-time-span-layer.h"
struct _SysprofMarkChartRow
{
GtkWidget parent_instance;
GCancellable *cancellable;
SysprofTimeSeries *series;
SysprofMarkChartItem *item;
GdkRGBA accent_fg_color;
GdkRGBA accent_bg_color;
GdkRGBA success_bg_color;
double pointer_x;
double pointer_y;
guint update_source;
guint pointer_in_row : 1;
guint in_dispose : 1;
SysprofChart *chart;
SysprofTimeSpanLayer *layer;
};
enum {
@ -55,394 +47,18 @@ G_DEFINE_FINAL_TYPE (SysprofMarkChartRow, sysprof_mark_chart_row, GTK_TYPE_WIDGE
static GParamSpec *properties [N_PROPS];
static void
cancel_and_clear (GCancellable **cancellable)
{
g_cancellable_cancel (*cancellable);
g_clear_object (cancellable);
}
static void
sysprof_mark_chart_row_set_series (SysprofMarkChartRow *self,
SysprofTimeSeries *series)
{
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
g_clear_pointer (&self->series, sysprof_time_series_unref);
self->series = series ? sysprof_time_series_ref (series) : NULL;
if (!self->in_dispose)
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
sysprof_mark_chart_row_css_changed (GtkWidget *widget,
GtkCssStyleChange *change)
{
SysprofMarkChartRow *self = (SysprofMarkChartRow *)widget;
g_assert (SYSPROF_MARK_CHART_ROW (self));
GTK_WIDGET_CLASS (sysprof_mark_chart_row_parent_class)->css_changed (widget, change);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
{
GtkStyleContext *style_context;
style_context = gtk_widget_get_style_context (widget);
gtk_style_context_lookup_color (style_context, "accent_bg_color", &self->accent_bg_color);
gtk_style_context_lookup_color (style_context, "accent_fg_color", &self->accent_fg_color);
gtk_style_context_lookup_color (style_context, "success_bg_color", &self->success_bg_color);
}
G_GNUC_END_IGNORE_DEPRECATIONS
}
static void
sysprof_mark_chart_row_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
SysprofMarkChartRow *self = (SysprofMarkChartRow *)widget;
const SysprofTimeSeriesValue *best_match = NULL;
const SysprofTimeSeriesValue *values;
graphene_point_t pointer;
PangoLayout *layout;
GListModel *model;
guint n_values;
float last_end_x;
int width;
int height;
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
g_assert (GTK_IS_SNAPSHOT (snapshot));
if (self->series == NULL)
return;
model = sysprof_time_series_get_model (self->series);
values = sysprof_time_series_get_values (self->series, &n_values);
if (model == NULL || n_values == 0)
return;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
pointer = GRAPHENE_POINT_INIT (self->pointer_x, self->pointer_y);
layout = gtk_widget_create_pango_layout (widget, NULL);
pango_layout_set_single_paragraph_mode (layout, TRUE);
pango_layout_set_height (layout, height * PANGO_SCALE);
pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
last_end_x = 0;
/* First pass, draw our rectangles for duration which we
* always want in the background compared to "points" which
* are marks w/o a duration.
*/
for (guint i = 0; i < n_values; i++)
{
const SysprofTimeSeriesValue *v = &values[i];
if (v->begin != v->end)
{
graphene_rect_t rect;
float end_x;
rect = GRAPHENE_RECT_INIT (floorf (v->begin * width),
0,
ceilf ((v->end - v->begin) * width),
height);
if (graphene_rect_contains_point (&rect, &pointer))
best_match = v;
/* Ignore empty sized draws */
if (rect.size.width == 0)
continue;
/* Cull draw unless it will extend past last rect */
end_x = rect.origin.x + rect.size.width;
if (end_x <= last_end_x)
continue;
else
last_end_x = end_x;
gtk_snapshot_append_color (snapshot, &self->accent_bg_color, &rect);
/* Only show the message text if the next item does
* not overlap and there are at least 20 pixels
* available to render into.
*/
if ((i + 1 == n_values || values[i+1].begin > v->end) &&
rect.size.width > 20)
{
g_autoptr(SysprofDocumentMark) mark = g_list_model_get_item (model, v->index);
const char *message = sysprof_document_mark_get_message (mark);
if (message && message[0])
{
pango_layout_set_width (layout, rect.size.width * PANGO_SCALE);
pango_layout_set_text (layout, message, -1);
gtk_snapshot_save (snapshot);
gtk_snapshot_push_clip (snapshot,
&GRAPHENE_RECT_INIT (v->begin * width,
0,
v->end * width,
height));
gtk_snapshot_translate (snapshot,
&GRAPHENE_POINT_INIT (v->begin * width, 0));
gtk_snapshot_append_layout (snapshot, layout, &self->accent_fg_color);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
}
}
}
}
for (guint i = 0; i < n_values; i++)
{
const SysprofTimeSeriesValue *v = &values[i];
if (v->begin == v->end)
{
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot,
&GRAPHENE_POINT_INIT (v->begin * width, height / 2));
gtk_snapshot_rotate (snapshot, 45.f);
gtk_snapshot_append_color (snapshot,
&self->success_bg_color,
&GRAPHENE_RECT_INIT (-4, -4, 8, 8));
gtk_snapshot_restore (snapshot);
}
}
/* Draw the best hover match fully, drawing over any other items. */
if (self->pointer_in_row && best_match != NULL)
{
const SysprofTimeSeriesValue *v = best_match;
g_autoptr(SysprofDocumentMark) mark = g_list_model_get_item (model, v->index);
const char *message = sysprof_document_mark_get_message (mark);
graphene_rect_t rect;
rect = GRAPHENE_RECT_INIT (floorf (v->begin * width),
0,
ceilf ((v->end - v->begin) * width),
height);
gtk_snapshot_append_color (snapshot, &self->accent_bg_color, &rect);
if (message && message[0])
{
int w, h;
pango_layout_set_width (layout, -1);
pango_layout_set_text (layout, message, -1);
pango_layout_get_pixel_size (layout, &w, &h);
if (w > rect.size.width)
{
GdkRGBA color = self->accent_bg_color;
color.alpha *= .9;
gtk_snapshot_append_color (snapshot,
&color,
&GRAPHENE_RECT_INIT (rect.origin.x + rect.size.width,
0,
w - rect.size.width,
rect.origin.y + rect.size.height));
}
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot,
&GRAPHENE_POINT_INIT (v->begin * width, 0));
gtk_snapshot_append_layout (snapshot, layout, &self->accent_fg_color);
gtk_snapshot_restore (snapshot);
}
}
g_clear_object (&layout);
}
static void
sysprof_mark_chart_row_load_time_series_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
SysprofMarkChartItem *item = (SysprofMarkChartItem *)object;
g_autoptr(SysprofMarkChartRow) self = user_data;
g_autoptr(SysprofTimeSeries) series = NULL;
g_assert (SYSPROF_IS_MARK_CHART_ITEM (item));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
series = sysprof_mark_chart_item_load_time_series_finish (item, result, NULL);
sysprof_mark_chart_row_set_series (self, series);
}
static gboolean
sysprof_mark_chart_row_dispatch_update (gpointer user_data)
{
SysprofMarkChartRow *self = user_data;
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
g_clear_handle_id (&self->update_source, g_source_remove);
cancel_and_clear (&self->cancellable);
if (self->item != NULL)
{
self->cancellable = g_cancellable_new ();
sysprof_mark_chart_item_load_time_series (self->item,
self->cancellable,
sysprof_mark_chart_row_load_time_series_cb,
g_object_ref (self));
}
return G_SOURCE_REMOVE;
}
static void
sysprof_mark_chart_row_queue_update (SysprofMarkChartRow *self)
{
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
cancel_and_clear (&self->cancellable);
g_clear_handle_id (&self->update_source, g_source_remove);
if (!self->in_dispose)
self->update_source = g_idle_add (sysprof_mark_chart_row_dispatch_update, self);
}
static void
sysprof_mark_chart_row_item_changed_cb (SysprofMarkChartRow *self,
SysprofMarkChartItem *item)
{
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
g_assert (SYSPROF_IS_MARK_CHART_ITEM (item));
sysprof_mark_chart_row_queue_update (self);
}
static void
sysprof_mark_chart_row_motion_enter_cb (SysprofMarkChartRow *self,
double x,
double y,
GtkEventControllerMotion *motion)
{
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
self->pointer_in_row = TRUE;
self->pointer_x = x;
self->pointer_y = y;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
sysprof_mark_chart_row_motion_motion_cb (SysprofMarkChartRow *self,
double x,
double y,
GtkEventControllerMotion *motion)
{
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
self->pointer_x = x;
self->pointer_y = y;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
sysprof_mark_chart_row_motion_leave_cb (SysprofMarkChartRow *self,
GtkEventControllerMotion *motion)
{
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
self->pointer_in_row = FALSE;
self->pointer_x = 0;
self->pointer_y = 0;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
sysprof_mark_chart_row_click_pressed_cb (SysprofMarkChartRow *self,
guint n_press,
double x,
double y,
GtkGestureClick *click)
{
const SysprofTimeSeriesValue *best_match = NULL;
const SysprofTimeSeriesValue *values;
g_autoptr(SysprofDocumentMark) mark = NULL;
SysprofSession *session;
GListModel *model;
double normalized_x;
gint64 t;
guint n_values;
int width;
g_assert (SYSPROF_IS_MARK_CHART_ROW (self));
g_assert (GTK_IS_GESTURE_CLICK (click));
if (n_press != 2 || self->series == NULL || self->item == NULL)
return;
if (!(session = sysprof_mark_chart_item_get_session (self->item)) ||
!(model = sysprof_time_series_get_model (self->series)))
return;
values = sysprof_time_series_get_values (self->series, &n_values);
if (values == NULL || n_values == 0)
return;
width = gtk_widget_get_width (GTK_WIDGET (self));
normalized_x = x / width;
for (guint i = 0; i < n_values; i++)
{
const SysprofTimeSeriesValue *v = &values[i];
if (v->begin > normalized_x)
break;
if (v->end >= normalized_x)
best_match = v;
}
if (best_match == NULL)
return;
mark = g_list_model_get_item (model, best_match->index);
t = sysprof_document_frame_get_time (SYSPROF_DOCUMENT_FRAME (mark));
sysprof_session_select_time (session,
&(SysprofTimeSpan) {
t,
t + sysprof_document_mark_get_duration (mark)
});
}
static void
sysprof_mark_chart_row_dispose (GObject *object)
{
SysprofMarkChartRow *self = (SysprofMarkChartRow *)object;
GtkWidget *child;
self->in_dispose = TRUE;
self->chart = NULL;
cancel_and_clear (&self->cancellable);
g_clear_handle_id (&self->update_source, g_source_remove);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
gtk_widget_unparent (child);
sysprof_mark_chart_row_set_item (self, NULL);
sysprof_mark_chart_row_set_series (self, NULL);
g_clear_object (&self->item);
G_OBJECT_CLASS (sysprof_mark_chart_row_parent_class)->dispose (object);
}
@ -495,9 +111,6 @@ sysprof_mark_chart_row_class_init (SysprofMarkChartRowClass *klass)
object_class->get_property = sysprof_mark_chart_row_get_property;
object_class->set_property = sysprof_mark_chart_row_set_property;
widget_class->css_changed = sysprof_mark_chart_row_css_changed;
widget_class->snapshot = sysprof_mark_chart_row_snapshot;
properties [PROP_ITEM] =
g_param_spec_object ("item", NULL, NULL,
SYSPROF_TYPE_MARK_CHART_ITEM,
@ -506,38 +119,20 @@ sysprof_mark_chart_row_class_init (SysprofMarkChartRowClass *klass)
g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_css_name (widget_class, "markchartrow");
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_template_from_resource (widget_class, "/libsysprof-gtk/sysprof-mark-chart-row.ui");
gtk_widget_class_bind_template_child (widget_class, SysprofMarkChartRow, chart);
gtk_widget_class_bind_template_child (widget_class, SysprofMarkChartRow, layer);
g_type_ensure (SYSPROF_TYPE_CHART);
g_type_ensure (SYSPROF_TYPE_TIME_SERIES_ITEM);
g_type_ensure (SYSPROF_TYPE_TIME_SPAN_LAYER);
}
static void
sysprof_mark_chart_row_init (SysprofMarkChartRow *self)
{
GtkEventController *controller;
controller = gtk_event_controller_motion_new ();
g_signal_connect_object (controller,
"enter",
G_CALLBACK (sysprof_mark_chart_row_motion_enter_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (controller,
"leave",
G_CALLBACK (sysprof_mark_chart_row_motion_leave_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (controller,
"motion",
G_CALLBACK (sysprof_mark_chart_row_motion_motion_cb),
self,
G_CONNECT_SWAPPED);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
g_signal_connect_object (controller,
"pressed",
G_CALLBACK (sysprof_mark_chart_row_click_pressed_cb),
self,
G_CONNECT_SWAPPED);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
gtk_widget_init_template (GTK_WIDGET (self));
}
SysprofMarkChartItem *
@ -555,27 +150,6 @@ sysprof_mark_chart_row_set_item (SysprofMarkChartRow *self,
g_return_if_fail (SYSPROF_IS_MARK_CHART_ROW (self));
g_return_if_fail (!item || SYSPROF_IS_MARK_CHART_ITEM (item));
if (self->item == item)
return;
cancel_and_clear (&self->cancellable);
g_clear_handle_id (&self->update_source, g_source_remove);
if (self->item)
g_signal_handlers_disconnect_by_func (self->item,
G_CALLBACK (sysprof_mark_chart_row_item_changed_cb),
self);
g_set_object (&self->item, item);
if (item)
g_signal_connect_object (self->item,
"changed",
G_CALLBACK (sysprof_mark_chart_row_item_changed_cb),
self,
G_CONNECT_SWAPPED);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
sysprof_mark_chart_row_queue_update (self);
if (g_set_object (&self->item, item))
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SysprofMarkChartRow" parent="GtkWidget">
<child>
<object class="SysprofChart" id="chart">
<property name="hexpand">true</property>
<property name="vexpand">false</property>
<child>
<object class="SysprofTimeSpanLayer" id="layer">
<binding name="axis">
<lookup name="selected-time-axis" type="SysprofSession">
<lookup name="session" type="SysprofMarkChartItem">
<lookup name="item">SysprofMarkChartRow</lookup>
</lookup>
</lookup>
</binding>
<binding name="series">
<lookup name="series" type="SysprofMarkChartItem">
<lookup name="item">SysprofMarkChartRow</lookup>
</lookup>
</binding>
</object>
</child>
</object>
</child>
</template>
</interface>