mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
libsysprof-gtk: add informative description of events under pointer
We are not using Tooltips for these because they 1) introduce additional delay, 2) slow things down to a hault do to protocol overhead/compositor work/etc. There may be a desire to do this differently for a11y purposes at some point, but I'd want to see how that use case plays out before trying to shove text description updates every frame motion to a screen reader.
This commit is contained in:
@ -69,6 +69,7 @@ timeruler {
|
||||
color: alpha(currentColor, .8);
|
||||
}
|
||||
|
||||
tracks informative,
|
||||
tracks timecode {
|
||||
border-radius: 7px;
|
||||
background: @accent_bg_color;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -165,9 +165,16 @@
|
||||
<property name="single-line-mode">true</property>
|
||||
<property name="width-chars">10</property>
|
||||
<property name="max-width-chars">10</property>
|
||||
<style>
|
||||
<class name="pill"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="informative">
|
||||
<property name="css-name">informative</property>
|
||||
<property name="can-focus">false</property>
|
||||
<property name="can-target">false</property>
|
||||
<property name="visible">false</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="single-line-mode">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user