From d68f2ff87a4691da2378698a5aea61783344a074 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Tue, 20 Jun 2023 12:45:43 -0700 Subject: [PATCH] libsysprof-gtk: add snapshot_motion to chart layer This allows snapshoting the motion highlight separate from the rest of the layer so that we can have better render tree diffs. Otherwise we risk having to snapshot a large dataset from the chart layer itself rather than just the hightlight areas that changed. --- src/libsysprof-gtk/sysprof-chart-layer.c | 13 +++ src/libsysprof-gtk/sysprof-chart-layer.h | 16 +++- src/libsysprof-gtk/sysprof-chart.c | 104 +++++++++++++++++++++++ 3 files changed, 130 insertions(+), 3 deletions(-) diff --git a/src/libsysprof-gtk/sysprof-chart-layer.c b/src/libsysprof-gtk/sysprof-chart-layer.c index 4dd401de..5d48a858 100644 --- a/src/libsysprof-gtk/sysprof-chart-layer.c +++ b/src/libsysprof-gtk/sysprof-chart-layer.c @@ -129,3 +129,16 @@ sysprof_chart_layer_set_title (SysprofChartLayer *self, if (g_set_str (&priv->title, title)) g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]); } + +void +sysprof_chart_layer_snapshot_motion (SysprofChartLayer *self, + GtkSnapshot *snapshot, + double x, + double y) +{ + g_return_if_fail (SYSPROF_IS_CHART_LAYER (self)); + g_return_if_fail (GTK_IS_SNAPSHOT (snapshot)); + + if (SYSPROF_CHART_LAYER_GET_CLASS (self)->snapshot_motion) + SYSPROF_CHART_LAYER_GET_CLASS (self)->snapshot_motion (self, snapshot, x, y); +} diff --git a/src/libsysprof-gtk/sysprof-chart-layer.h b/src/libsysprof-gtk/sysprof-chart-layer.h index b6aba5ff..5b4c6871 100644 --- a/src/libsysprof-gtk/sysprof-chart-layer.h +++ b/src/libsysprof-gtk/sysprof-chart-layer.h @@ -35,14 +35,24 @@ struct _SysprofChartLayerClass { GtkWidgetClass parent_class; + void (*snapshot_motion) (SysprofChartLayer *self, + GtkSnapshot *snapshot, + double x, + double y); + /*< private >*/ gpointer _reserved[16]; }; SYSPROF_AVAILABLE_IN_ALL -const char *sysprof_chart_layer_get_title (SysprofChartLayer *self); +const char *sysprof_chart_layer_get_title (SysprofChartLayer *self); SYSPROF_AVAILABLE_IN_ALL -void sysprof_chart_layer_set_title (SysprofChartLayer *self, - const char *title); +void sysprof_chart_layer_set_title (SysprofChartLayer *self, + const char *title); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_chart_layer_snapshot_motion (SysprofChartLayer *self, + GtkSnapshot *snapshot, + double x, + double y); G_END_DECLS diff --git a/src/libsysprof-gtk/sysprof-chart.c b/src/libsysprof-gtk/sysprof-chart.c index b0315cb5..d154fec4 100644 --- a/src/libsysprof-gtk/sysprof-chart.c +++ b/src/libsysprof-gtk/sysprof-chart.c @@ -26,6 +26,11 @@ typedef struct { SysprofSession *session; char *title; + + double motion_x; + double motion_y; + + guint pointer_in_chart : 1; } SysprofChartPrivate; enum { @@ -39,6 +44,58 @@ G_DEFINE_TYPE_WITH_PRIVATE (SysprofChart, sysprof_chart, GTK_TYPE_WIDGET) static GParamSpec *properties [N_PROPS]; + +static void +sysprof_chart_motion_enter_cb (SysprofChart *self, + double x, + double y, + GtkEventControllerMotion *motion) +{ + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_assert (SYSPROF_IS_CHART (self)); + g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion)); + + priv->motion_x = x; + priv->motion_y = y; + priv->pointer_in_chart = TRUE; + + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static void +sysprof_chart_motion_cb (SysprofChart *self, + double x, + double y, + GtkEventControllerMotion *motion) +{ + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_assert (SYSPROF_IS_CHART (self)); + g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion)); + + priv->motion_x = x; + priv->motion_y = y; + + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static void +sysprof_chart_motion_leave_cb (SysprofChart *self, + GtkEventControllerMotion *motion) +{ + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_assert (SYSPROF_IS_CHART (self)); + g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion)); + + priv->motion_x = -1; + priv->motion_y = -1; + priv->pointer_in_chart = FALSE; + + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + static void sysprof_chart_size_allocate (GtkWidget *widget, int width, @@ -57,6 +114,29 @@ sysprof_chart_size_allocate (GtkWidget *widget, baseline); } +static void +sysprof_chart_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) +{ + SysprofChart *self = (SysprofChart *)widget; + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_assert (SYSPROF_IS_CHART (self)); + + GTK_WIDGET_CLASS (sysprof_chart_parent_class)->snapshot (widget, snapshot); + + if (priv->pointer_in_chart) + { + GtkWidget *pick = gtk_widget_pick (widget, priv->motion_x, priv->motion_y, GTK_PICK_DEFAULT); + + if (SYSPROF_IS_CHART_LAYER (pick)) + sysprof_chart_layer_snapshot_motion (SYSPROF_CHART_LAYER (pick), + snapshot, + priv->motion_x, + priv->motion_y); + } +} + static void sysprof_chart_dispose (GObject *object) { @@ -130,6 +210,7 @@ sysprof_chart_class_init (SysprofChartClass *klass) object_class->set_property = sysprof_chart_set_property; widget_class->size_allocate = sysprof_chart_size_allocate; + widget_class->snapshot = sysprof_chart_snapshot; properties [PROP_SESSION] = g_param_spec_object ("session", NULL, NULL, @@ -147,6 +228,29 @@ sysprof_chart_class_init (SysprofChartClass *klass) static void sysprof_chart_init (SysprofChart *self) { + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + GtkEventController *motion; + + priv->motion_x = -1; + priv->motion_y = -1; + + motion = gtk_event_controller_motion_new (); + g_signal_connect_object (motion, + "enter", + G_CALLBACK (sysprof_chart_motion_enter_cb), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (motion, + "leave", + G_CALLBACK (sysprof_chart_motion_leave_cb), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (motion, + "motion", + G_CALLBACK (sysprof_chart_motion_cb), + self, + G_CONNECT_SWAPPED); + gtk_widget_add_controller (GTK_WIDGET (self), g_steal_pointer (&motion)); } const char *