diff --git a/src/libsysprof-gtk/sysprof-mark-chart-item.c b/src/libsysprof-gtk/sysprof-mark-chart-item.c index a2c9e813..a78ec88f 100644 --- a/src/libsysprof-gtk/sysprof-mark-chart-item.c +++ b/src/libsysprof-gtk/sysprof-mark-chart-item.c @@ -159,7 +159,8 @@ sysprof_mark_chart_item_init (SysprofMarkChartItem *self) 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")); + gtk_property_expression_new (SYSPROF_TYPE_DOCUMENT_MARK, NULL, "duration"), + gtk_property_expression_new (SYSPROF_TYPE_DOCUMENT_MARK, NULL, "message")); } SysprofMarkChartItem * diff --git a/src/libsysprof-gtk/sysprof-session-discover.c b/src/libsysprof-gtk/sysprof-session-discover.c index cc3e50fc..0ba7e420 100644 --- a/src/libsysprof-gtk/sysprof-session-discover.c +++ b/src/libsysprof-gtk/sysprof-session-discover.c @@ -387,7 +387,8 @@ create_chart_for_marks (SysprofTrack *track, time_series = sysprof_time_series_new (sysprof_track_get_title (track), g_object_ref (G_LIST_MODEL (info->model)), gtk_property_expression_new (SYSPROF_TYPE_DOCUMENT_MARK, NULL, "time"), - gtk_property_expression_new (SYSPROF_TYPE_DOCUMENT_MARK, NULL, "duration")); + gtk_property_expression_new (SYSPROF_TYPE_DOCUMENT_MARK, NULL, "duration"), + gtk_property_expression_new (SYSPROF_TYPE_DOCUMENT_MARK, NULL, "message")); chart = g_object_new (SYSPROF_TYPE_CHART, NULL); layer = g_object_new (SYSPROF_TYPE_TIME_SPAN_LAYER, diff --git a/src/libsysprof-gtk/sysprof-time-series.c b/src/libsysprof-gtk/sysprof-time-series.c index fe00dbd4..6b7df724 100644 --- a/src/libsysprof-gtk/sysprof-time-series.c +++ b/src/libsysprof-gtk/sysprof-time-series.c @@ -29,6 +29,7 @@ struct _SysprofTimeSeries SysprofSeries parent_instance; GtkExpression *time_expression; GtkExpression *duration_expression; + GtkExpression *label_expression; }; struct _SysprofTimeSeriesClass @@ -38,8 +39,9 @@ struct _SysprofTimeSeriesClass enum { PROP_0, - PROP_TIME_EXPRESSION, PROP_DURATION_EXPRESSION, + PROP_LABEL_EXPRESSION, + PROP_TIME_EXPRESSION, N_PROPS }; @@ -64,8 +66,9 @@ sysprof_time_series_finalize (GObject *object) { SysprofTimeSeries *self = (SysprofTimeSeries *)object; - g_clear_pointer (&self->time_expression, gtk_expression_unref); g_clear_pointer (&self->duration_expression, gtk_expression_unref); + g_clear_pointer (&self->label_expression, gtk_expression_unref); + g_clear_pointer (&self->time_expression, gtk_expression_unref); G_OBJECT_CLASS (sysprof_time_series_parent_class)->finalize (object); } @@ -88,6 +91,10 @@ sysprof_time_series_get_property (GObject *object, gtk_value_set_expression (value, self->duration_expression); break; + case PROP_LABEL_EXPRESSION: + gtk_value_set_expression (value, self->label_expression); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -111,6 +118,10 @@ sysprof_time_series_set_property (GObject *object, sysprof_time_series_set_duration_expression (self, gtk_value_get_expression (value)); break; + case PROP_LABEL_EXPRESSION: + sysprof_time_series_set_label_expression (self, gtk_value_get_expression (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -137,6 +148,10 @@ sysprof_time_series_class_init (SysprofTimeSeriesClass *klass) gtk_param_spec_expression ("y-expression", NULL, NULL, (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + properties [PROP_LABEL_EXPRESSION] = + gtk_param_spec_expression ("label-expression", NULL, NULL, + (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_properties (object_class, N_PROPS, properties); } @@ -153,6 +168,8 @@ sysprof_time_series_init (SysprofTimeSeries *self) * extracting the time value from @model items. * @duration_expression: (transfer full) (nullable): a #GtkExpression for * extracting the duration value from @model items. + * @label_expression: (transfer full) (nullable): a #GtkExpression for + * extracting the label from @model items. * * A #SysprofSeries which contains Time,Duration pairs. * @@ -162,7 +179,8 @@ SysprofSeries * sysprof_time_series_new (const char *title, GListModel *model, GtkExpression *time_expression, - GtkExpression *duration_expression) + GtkExpression *duration_expression, + GtkExpression *label_expression) { SysprofTimeSeries *xy; @@ -171,10 +189,12 @@ sysprof_time_series_new (const char *title, "model", model, "x-expression", time_expression, "y-expression", duration_expression, + "label-expression", label_expression, NULL); g_clear_pointer (&time_expression, gtk_expression_unref); g_clear_pointer (&duration_expression, gtk_expression_unref); + g_clear_pointer (&label_expression, gtk_expression_unref); g_clear_object (&model); return SYSPROF_SERIES (xy); @@ -253,3 +273,64 @@ sysprof_time_series_set_duration_expression (SysprofTimeSeries *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION_EXPRESSION]); } + +/** + * sysprof_time_series_get_label_expression: + * @self: a #SysprofTimeSeries + * + * Gets the #SysprofTimeSeries:y-expression property. + * + * This is used to extract the Y coordinate from items in the #GListModel. + * + * Returns: (transfer none) (nullable): a #GtkExpression or %NULL + */ +GtkExpression * +sysprof_time_series_get_label_expression (SysprofTimeSeries *self) +{ + g_return_val_if_fail (SYSPROF_IS_TIME_SERIES (self), NULL); + + return self->label_expression; +} + +void +sysprof_time_series_set_label_expression (SysprofTimeSeries *self, + GtkExpression *label_expression) +{ + g_return_if_fail (SYSPROF_IS_TIME_SERIES (self)); + + if (self->label_expression == label_expression) + return; + + if (label_expression) + gtk_expression_ref (label_expression); + + g_clear_pointer (&self->label_expression, gtk_expression_unref); + + self->label_expression = label_expression; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LABEL_EXPRESSION]); +} + +char * +sysprof_time_series_dup_label (SysprofTimeSeries *self, + guint position) +{ + g_autoptr(GObject) item = NULL; + g_auto(GValue) value = G_VALUE_INIT; + GListModel *model; + + g_return_val_if_fail (SYSPROF_IS_TIME_SERIES (self), NULL); + + if (self->label_expression == NULL) + return NULL; + + if (!(model = sysprof_series_get_model (SYSPROF_SERIES (self)))) + return NULL; + + if (!(item = g_list_model_get_item (model, position))) + return NULL; + + g_value_init (&value, G_TYPE_STRING); + gtk_expression_evaluate (self->label_expression, item, &value); + return g_value_dup_string (&value); +} diff --git a/src/libsysprof-gtk/sysprof-time-series.h b/src/libsysprof-gtk/sysprof-time-series.h index d94b7960..dce6ebb6 100644 --- a/src/libsysprof-gtk/sysprof-time-series.h +++ b/src/libsysprof-gtk/sysprof-time-series.h @@ -40,7 +40,8 @@ SYSPROF_AVAILABLE_IN_ALL SysprofSeries *sysprof_time_series_new (const char *title, GListModel *model, GtkExpression *time_expression, - GtkExpression *duration_expression); + GtkExpression *duration_expression, + GtkExpression *label_expression); SYSPROF_AVAILABLE_IN_ALL GtkExpression *sysprof_time_series_get_time_expression (SysprofTimeSeries *self); SYSPROF_AVAILABLE_IN_ALL @@ -51,6 +52,14 @@ GtkExpression *sysprof_time_series_get_duration_expression (SysprofTimeSeries *s SYSPROF_AVAILABLE_IN_ALL void sysprof_time_series_set_duration_expression (SysprofTimeSeries *self, GtkExpression *duration_expression); +SYSPROF_AVAILABLE_IN_ALL +GtkExpression *sysprof_time_series_get_label_expression (SysprofTimeSeries *self); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_time_series_set_label_expression (SysprofTimeSeries *self, + GtkExpression *label_expression); +SYSPROF_AVAILABLE_IN_ALL +char *sysprof_time_series_dup_label (SysprofTimeSeries *self, + guint position); G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofTimeSeries, g_object_unref) diff --git a/src/libsysprof-gtk/sysprof-time-span-layer.c b/src/libsysprof-gtk/sysprof-time-span-layer.c index d1a12c10..b009df39 100644 --- a/src/libsysprof-gtk/sysprof-time-span-layer.c +++ b/src/libsysprof-gtk/sysprof-time-span-layer.c @@ -138,6 +138,18 @@ sysprof_time_span_layer_snapshot (GtkWidget *widget, if (color->alpha > 0) { + const GdkRGBA *label_color = _sysprof_chart_layer_get_accent_fg_color (); + PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), NULL); + int layout_y; + int layout_h; + + pango_layout_set_single_paragraph_mode (layout, TRUE); + pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); + pango_layout_set_text (layout, "XM0", -1); + pango_layout_get_pixel_size (layout, NULL, &layout_h); + + layout_y = (height - layout_h) / 2; + /* First pass, draw our rectangles for duration which we * always want in the background compared to "points" which * are marks w/o a duration. @@ -147,6 +159,12 @@ sysprof_time_span_layer_snapshot (GtkWidget *widget, float begin = x_values[i]; float end = x2_values[i]; + if (end < .0) + continue; + + if (begin > 1.) + break; + if (begin != end) { graphene_rect_t rect; @@ -157,7 +175,7 @@ sysprof_time_span_layer_snapshot (GtkWidget *widget, ceilf ((end - begin) * width), height); - /* Ignore empty sized draws */ + /* Ignore empty draws */ if (rect.size.width == 0) continue; @@ -169,8 +187,26 @@ sysprof_time_span_layer_snapshot (GtkWidget *widget, last_end_x = end_x; gtk_snapshot_append_color (snapshot, color, &rect); + + if (rect.size.width > 20) + { + g_autofree char *label = sysprof_time_series_dup_label (self->series, i); + + if (label != NULL) + { + pango_layout_set_text (layout, label, -1); + pango_layout_set_width (layout, (rect.size.width - 6) * PANGO_SCALE); + + gtk_snapshot_save (snapshot); + gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (rect.origin.x + 3, layout_y)); + gtk_snapshot_append_layout (snapshot, layout, label_color); + gtk_snapshot_restore (snapshot); + } + } } } + + g_object_unref (layout); } if (event_color->alpha > 0)