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
-
+
+
+
+