diff --git a/src/libsysprof-gtk/style.css b/src/libsysprof-gtk/style.css index 672858a3..09108324 100644 --- a/src/libsysprof-gtk/style.css +++ b/src/libsysprof-gtk/style.css @@ -69,6 +69,7 @@ timeruler { color: alpha(currentColor, .8); } +tracks informative, tracks timecode { border-radius: 7px; background: @accent_bg_color; diff --git a/src/libsysprof-gtk/sysprof-session-private.h b/src/libsysprof-gtk/sysprof-session-private.h index 8eee33d8..561f1cc5 100644 --- a/src/libsysprof-gtk/sysprof-session-private.h +++ b/src/libsysprof-gtk/sysprof-session-private.h @@ -24,8 +24,10 @@ G_BEGIN_DECLS -void _sysprof_session_discover_tracks (SysprofSession *session, - SysprofDocument *document, - GListStore *tracks); +void _sysprof_session_discover_tracks (SysprofSession *session, + SysprofDocument *document, + GListStore *tracks); +char *_sysprof_session_describe (SysprofSession *self, + gpointer item); G_END_DECLS diff --git a/src/libsysprof-gtk/sysprof-session.c b/src/libsysprof-gtk/sysprof-session.c index d4cea732..bcf83054 100644 --- a/src/libsysprof-gtk/sysprof-session.c +++ b/src/libsysprof-gtk/sysprof-session.c @@ -379,3 +379,77 @@ sysprof_session_zoom_to_selection (SysprofSession *self) sysprof_session_update_axis (self); } + +static char * +get_time_str (gint64 o) +{ + char str[32]; + + if (o == 0) + g_snprintf (str, sizeof str, "%.3lfs", .0); + else if (o < 1000000) + g_snprintf (str, sizeof str, "%.3lfμs", o/1000.); + else if (o < SYSPROF_NSEC_PER_SEC) + g_snprintf (str, sizeof str, "%.3lfms", o/1000000.); + else + g_snprintf (str, sizeof str, "%.3lfs", o/(double)SYSPROF_NSEC_PER_SEC); + + return g_strdup (str); +} + +static void +append_time_string (GString *str, + const SysprofTimeSpan *span) +{ + g_autofree char *begin_str = NULL; + + g_assert (str != NULL); + g_assert (span != NULL); + + begin_str = get_time_str (span->begin_nsec); + + g_string_append (str, begin_str); + + if (span->begin_nsec != span->end_nsec) + { + g_autofree char *end_str = get_time_str (span->end_nsec - span->begin_nsec); + + g_string_append_printf (str, " (%s)", end_str); + } +} + +char * +_sysprof_session_describe (SysprofSession *self, + gpointer item) +{ + g_return_val_if_fail (SYSPROF_IS_SESSION (self), NULL); + + if (self->document == NULL) + return NULL; + + if (SYSPROF_IS_DOCUMENT_MARK (item)) + { + SysprofDocumentMark *mark = item; + const SysprofTimeSpan *begin = sysprof_document_get_time_span (self->document); + GString *str = g_string_new (NULL); + const char *group = sysprof_document_mark_get_group (mark); + const char *name = sysprof_document_mark_get_name (mark); + const char *message = sysprof_document_mark_get_message (mark); + SysprofTimeSpan span = { + .begin_nsec = sysprof_document_frame_get_time (item), + .end_nsec = sysprof_document_frame_get_time (item) + sysprof_document_mark_get_duration (mark), + }; + + span = sysprof_time_span_relative_to (span, begin->begin_nsec); + + append_time_string (str, &span); + g_string_append_printf (str, ": %s / %s", group, name); + + if (message && message[0]) + g_string_append_printf (str, ": %s", message); + + return g_string_free (str, FALSE); + } + + return NULL; +} diff --git a/src/libsysprof-gtk/sysprof-time-span-layer.c b/src/libsysprof-gtk/sysprof-time-span-layer.c index b009df39..897b97af 100644 --- a/src/libsysprof-gtk/sysprof-time-span-layer.c +++ b/src/libsysprof-gtk/sysprof-time-span-layer.c @@ -241,6 +241,66 @@ sysprof_time_span_layer_snapshot (GtkWidget *widget, } } +static gpointer +sysprof_time_span_layer_lookup_item (SysprofChartLayer *layer, + double x, + double y) +{ + SysprofTimeSpanLayer *self = (SysprofTimeSpanLayer *)layer; + const float *x_values; + const float *x2_values; + GListModel *model; + guint n_x_values = 0; + guint n_x2_values = 0; + guint n_values; + int width; + int height; + + g_assert (SYSPROF_IS_TIME_SPAN_LAYER (self)); + + width = gtk_widget_get_width (GTK_WIDGET (self)); + height = gtk_widget_get_height (GTK_WIDGET (self)); + + if (width == 0 || height == 0 || self->series == NULL) + return NULL; + + if (!(model = sysprof_series_get_model (SYSPROF_SERIES (self->series)))) + return NULL; + + if (!(x_values = sysprof_normalized_series_get_values (self->normal_x, &n_x_values)) || + !(x2_values = sysprof_normalized_series_get_values (self->normal_x2, &n_x2_values)) || + !(n_values = MIN (n_x_values, n_x2_values))) + return NULL; + + /* First match our non-duration marks (diamonds) */ + for (guint i = 0; i < n_values; i++) + { + int begin = x_values[i] * width - 3; + int end = x2_values[i] * width + 3; + + if (x_values[i] != x2_values[i]) + continue; + + if (x >= begin && x < end) + return g_list_model_get_item (model, i); + } + + /* Then match regular duration events */ + for (guint i = 0; i < n_values; i++) + { + float begin = x_values[i] * width; + float end = x2_values[i] * width; + + if (x_values[i] == x2_values[i]) + continue; + + if (x >= begin && x < end) + return g_list_model_get_item (model, i); + } + + return NULL; +} + static void sysprof_time_span_layer_finalize (GObject *object) { @@ -321,6 +381,7 @@ sysprof_time_span_layer_class_init (SysprofTimeSpanLayerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + SysprofChartLayerClass *chart_layer_class = SYSPROF_CHART_LAYER_CLASS (klass); object_class->finalize = sysprof_time_span_layer_finalize; object_class->get_property = sysprof_time_span_layer_get_property; @@ -328,6 +389,8 @@ sysprof_time_span_layer_class_init (SysprofTimeSpanLayerClass *klass) widget_class->snapshot = sysprof_time_span_layer_snapshot; + chart_layer_class->lookup_item = sysprof_time_span_layer_lookup_item; + properties[PROP_AXIS] = g_param_spec_object ("axis", NULL, NULL, SYSPROF_TYPE_AXIS, diff --git a/src/libsysprof-gtk/sysprof-tracks-view.c b/src/libsysprof-gtk/sysprof-tracks-view.c index 73d358ce..1f2fe29b 100644 --- a/src/libsysprof-gtk/sysprof-tracks-view.c +++ b/src/libsysprof-gtk/sysprof-tracks-view.c @@ -20,7 +20,9 @@ #include "config.h" +#include "sysprof-chart-layer.h" #include "sysprof-css-private.h" +#include "sysprof-session-private.h" #include "sysprof-track-view.h" #include "sysprof-tracks-view.h" #include "sysprof-time-ruler.h" @@ -32,6 +34,7 @@ struct _SysprofTracksView SysprofSession *session; GtkBox *box; + GtkLabel *informative; GtkWidget *top_left; GtkListView *list_view; SysprofTimeRuler *ruler; @@ -65,6 +68,8 @@ set_motion (SysprofTracksView *self, double y) { gboolean timecode_visible = FALSE; + gboolean informative_visible = FALSE; + GtkWidget *pick; int ruler_start; g_assert (SYSPROF_IS_TRACKS_VIEW (self)); @@ -76,15 +81,42 @@ set_motion (SysprofTracksView *self, self->motion_y = y; ruler_start = gtk_widget_get_width (self->top_left); + timecode_visible = x >= ruler_start; - if (x >= ruler_start) + if (timecode_visible) { g_autofree char *str = sysprof_time_ruler_get_label_at_point (self->ruler, x - ruler_start); gtk_label_set_label (self->timecode, str); - timecode_visible = TRUE; + } + + pick = gtk_widget_pick (GTK_WIDGET (self), x, y, 0); + + if (pick != NULL) + { + SysprofChartLayer *layer = SYSPROF_CHART_LAYER (gtk_widget_get_ancestor (pick, SYSPROF_TYPE_CHART_LAYER)); + + if (layer != NULL) + { + g_autoptr(GObject) item = NULL; + g_autofree char *text = NULL; + double layer_x; + double layer_y; + + gtk_widget_translate_coordinates (GTK_WIDGET (self), + GTK_WIDGET (layer), + x, y, &layer_x, &layer_y); + + if ((item = sysprof_chart_layer_lookup_item (layer, layer_x, layer_y))) + text = _sysprof_session_describe (self->session, item); + + gtk_label_set_label (self->informative, text); + + informative_visible = text != NULL; + } } gtk_widget_set_visible (GTK_WIDGET (self->timecode), timecode_visible); + gtk_widget_set_visible (GTK_WIDGET (self->informative), informative_visible); gtk_widget_queue_draw (GTK_WIDGET (self)); } @@ -357,6 +389,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS if (gtk_widget_get_visible (GTK_WIDGET (self->timecode))) gtk_widget_snapshot_child (GTK_WIDGET (self), GTK_WIDGET (self->timecode), snapshot); + + if (gtk_widget_get_visible (GTK_WIDGET (self->informative))) + gtk_widget_snapshot_child (GTK_WIDGET (self), GTK_WIDGET (self->informative), snapshot); } static void @@ -448,6 +483,27 @@ sysprof_tracks_view_size_allocate (GtkWidget *widget, min_req.width, min_req.height }, -1); } + + if (gtk_widget_get_visible (GTK_WIDGET (self->informative))) + { + GtkRequisition min_req; + GtkRequisition nat_req; + + gtk_widget_get_preferred_size (GTK_WIDGET (self->informative), &min_req, &nat_req); + + if (self->motion_x + min_req.width < gtk_widget_get_width (GTK_WIDGET (self))) + gtk_widget_size_allocate (GTK_WIDGET (self->informative), + &(GtkAllocation) { + self->motion_x, self->motion_y, + min_req.width, min_req.height + }, -1); + else + gtk_widget_size_allocate (GTK_WIDGET (self->informative), + &(GtkAllocation) { + self->motion_x - min_req.width, self->motion_y, + min_req.width, min_req.height + }, -1); + } } static void @@ -529,6 +585,7 @@ sysprof_tracks_view_class_init (SysprofTracksViewClass *klass) gtk_widget_class_set_css_name (widget_class, "tracks"); gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, box); + gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, informative); gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, list_view); gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, ruler); gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, timecode); diff --git a/src/libsysprof-gtk/sysprof-tracks-view.ui b/src/libsysprof-gtk/sysprof-tracks-view.ui index 6e8c3bcf..5e4a0240 100644 --- a/src/libsysprof-gtk/sysprof-tracks-view.ui +++ b/src/libsysprof-gtk/sysprof-tracks-view.ui @@ -165,9 +165,16 @@ true 10 10 - + + + + + informative + false + false + false + 0 + true