diff --git a/src/libsysprof-ui/meson.build b/src/libsysprof-ui/meson.build index 63247f75..dac463cd 100644 --- a/src/libsysprof-ui/meson.build +++ b/src/libsysprof-ui/meson.build @@ -23,6 +23,7 @@ libsysprof_ui_public_sources = [ libsysprof_ui_private_sources = [ 'pointcache.c', 'rectangles.c', + 'sysprof-cell-renderer-duration.c', 'sysprof-cell-renderer-percent.c', 'sysprof-theme-manager.c', '../stackstash.c', diff --git a/src/libsysprof-ui/sysprof-cell-renderer-duration.c b/src/libsysprof-ui/sysprof-cell-renderer-duration.c new file mode 100644 index 00000000..fc26ffaf --- /dev/null +++ b/src/libsysprof-ui/sysprof-cell-renderer-duration.c @@ -0,0 +1,204 @@ +/* sysprof-cell-renderer-duration.c + * + * Copyright 2019 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#define G_LOG_DOMAIN "sysprof-cell-renderer-duration" + +#include "config.h" + +#include "sysprof-cell-renderer-duration.h" + +typedef struct +{ + gint64 begin_time; + gint64 end_time; + gint64 zoom_begin; + gint64 zoom_end; +} SysprofCellRendererDurationPrivate; + +enum { + PROP_0, + PROP_BEGIN_TIME, + PROP_END_TIME, + PROP_ZOOM_BEGIN, + PROP_ZOOM_END, + N_PROPS +}; + +G_DEFINE_TYPE_WITH_PRIVATE (SysprofCellRendererDuration, sysprof_cell_renderer_duration, GTK_TYPE_CELL_RENDERER) + +static GParamSpec *properties [N_PROPS]; + +static void +sysprof_cell_renderer_duration_render (GtkCellRenderer *renderer, + cairo_t *cr, + GtkWidget *widget, + const GdkRectangle *bg_area, + const GdkRectangle *cell_area, + GtkCellRendererState state) +{ + SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)renderer; + SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self); + GtkStyleContext *style_context; + gdouble zoom_range; + gdouble x1, x2; + GdkRGBA rgba; + GdkRectangle r; + + g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (self)); + g_assert (cr != NULL); + g_assert (GTK_IS_WIDGET (widget)); + + if (priv->begin_time == priv->end_time) + return; + + if (priv->end_time < priv->begin_time) + return; + + if (priv->begin_time > priv->zoom_end || priv->end_time < priv->zoom_begin) + return; + + style_context = gtk_widget_get_style_context (widget); + gtk_style_context_get_color (style_context, + gtk_style_context_get_state (style_context), + &rgba); + + zoom_range = (gdouble)priv->zoom_end - (gdouble)priv->zoom_begin; + + x1 = (priv->begin_time - priv->zoom_begin) / zoom_range * cell_area->width; + x2 = (priv->end_time - priv->zoom_begin) / zoom_range * cell_area->width; + + r.x = cell_area->x + x1; + r.y = cell_area->y; + r.width = MAX (1.0, x2 - x1); + r.height = cell_area->height; + + gdk_cairo_rectangle (cr, &r); + gdk_cairo_set_source_rgba (cr, &rgba); + cairo_fill (cr); +} + +static void +sysprof_cell_renderer_duration_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofCellRendererDuration *self = SYSPROF_CELL_RENDERER_DURATION (object); + SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self); + + switch (prop_id) + { + case PROP_BEGIN_TIME: + g_value_set_int64 (value, priv->begin_time); + break; + + case PROP_ZOOM_BEGIN: + g_value_set_int64 (value, priv->zoom_begin); + break; + + case PROP_ZOOM_END: + g_value_set_int64 (value, priv->zoom_end); + break; + + case PROP_END_TIME: + g_value_set_int64 (value, priv->end_time); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_cell_renderer_duration_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofCellRendererDuration *self = SYSPROF_CELL_RENDERER_DURATION (object); + SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self); + + switch (prop_id) + { + case PROP_BEGIN_TIME: + priv->begin_time = g_value_get_int64 (value); + break; + + case PROP_ZOOM_BEGIN: + priv->zoom_begin = g_value_get_int64 (value); + break; + + case PROP_ZOOM_END: + priv->zoom_end = g_value_get_int64 (value); + break; + + case PROP_END_TIME: + priv->end_time = g_value_get_int64 (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_cell_renderer_duration_class_init (SysprofCellRendererDurationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass); + + object_class->get_property = sysprof_cell_renderer_duration_get_property; + object_class->set_property = sysprof_cell_renderer_duration_set_property; + + cell_class->render = sysprof_cell_renderer_duration_render; + + properties [PROP_BEGIN_TIME] = + g_param_spec_int64 ("begin-time", NULL, NULL, + G_MININT64, G_MAXINT64, 0, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + properties [PROP_ZOOM_BEGIN] = + g_param_spec_int64 ("zoom-begin", NULL, NULL, + G_MININT64, G_MAXINT64, 0, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + properties [PROP_ZOOM_END] = + g_param_spec_int64 ("zoom-end", NULL, NULL, + G_MININT64, G_MAXINT64, 0, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + properties [PROP_END_TIME] = + g_param_spec_int64 ("end-time", NULL, NULL, + G_MININT64, G_MAXINT64, 0, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_cell_renderer_duration_init (SysprofCellRendererDuration *self) +{ +} + +GtkCellRenderer * +sysprof_cell_renderer_duration_new (void) +{ + return g_object_new (SYSPROF_TYPE_CELL_RENDERER_DURATION, NULL); +} diff --git a/src/libsysprof-ui/sysprof-cell-renderer-duration.h b/src/libsysprof-ui/sysprof-cell-renderer-duration.h new file mode 100644 index 00000000..243a261c --- /dev/null +++ b/src/libsysprof-ui/sysprof-cell-renderer-duration.h @@ -0,0 +1,41 @@ +/* sysprof-cell-renderer-duration.h + * + * Copyright 2019 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_CELL_RENDERER_DURATION (sysprof_cell_renderer_duration_get_type()) + +G_DECLARE_DERIVABLE_TYPE (SysprofCellRendererDuration, sysprof_cell_renderer_duration, SYSPROF, CELL_RENDERER_DURATION, GtkCellRenderer) + +struct _SysprofCellRendererDurationClass +{ + GtkCellRendererClass parent_class; + + /*< private >*/ + gpointer _reserved[8]; +}; + +GtkCellRenderer *sysprof_cell_renderer_duration_new (void); + +G_END_DECLS diff --git a/src/libsysprof-ui/sysprof-marks-model.c b/src/libsysprof-ui/sysprof-marks-model.c index bed036ee..16a675d7 100644 --- a/src/libsysprof-ui/sysprof-marks-model.c +++ b/src/libsysprof-ui/sysprof-marks-model.c @@ -29,6 +29,7 @@ struct _SysprofMarksModel GObject parent_instance; GStringChunk *chunks; GArray *items; + gint64 max_end_time; }; typedef struct @@ -276,11 +277,27 @@ cursor_foreach_cb (const SysprofCaptureFrame *frame, item.group = g_string_chunk_insert_const (self->chunks, mark->group); item.name = g_string_chunk_insert_const (self->chunks, mark->name); + if G_LIKELY (item.end_time > self->max_end_time) + self->max_end_time = item.end_time; + g_array_append_val (self->items, item); return TRUE; } +static gint +item_compare (gconstpointer a, + gconstpointer b) +{ + const Item *ia = a; + const Item *ib = b; + + if (ia->begin_time == ib->begin_time) + return ia->end_time - ib->end_time; + + return ia->begin_time - ib->begin_time; +} + static void sysprof_marks_model_new_worker (GTask *task, gpointer source_object, @@ -303,6 +320,8 @@ sysprof_marks_model_new_worker (GTask *task, sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition)); sysprof_capture_cursor_foreach (cursor, cursor_foreach_cb, self); + g_array_sort (self->items, item_compare); + g_task_return_pointer (task, g_steal_pointer (&self), g_object_unref); } @@ -333,3 +352,22 @@ sysprof_marks_model_new_finish (GAsyncResult *result, return g_task_propagate_pointer (G_TASK (result), error); } + +void +sysprof_marks_model_get_range (SysprofMarksModel *self, + gint64 *begin_time, + gint64 *end_time) +{ + g_return_if_fail (SYSPROF_IS_MARKS_MODEL (self)); + + if (begin_time != NULL) + { + *begin_time = 0; + + if (self->items->len > 0) + *begin_time = g_array_index (self->items, Item, 0).begin_time; + } + + if (end_time != NULL) + *end_time = self->max_end_time; +} diff --git a/src/libsysprof-ui/sysprof-marks-model.h b/src/libsysprof-ui/sysprof-marks-model.h index 2f606195..292afb86 100644 --- a/src/libsysprof-ui/sysprof-marks-model.h +++ b/src/libsysprof-ui/sysprof-marks-model.h @@ -46,5 +46,8 @@ void sysprof_marks_model_new_async (SysprofCaptureReader *reader gpointer user_data); SysprofMarksModel *sysprof_marks_model_new_finish (GAsyncResult *result, GError **error); +void sysprof_marks_model_get_range (SysprofMarksModel *self, + gint64 *begin_time, + gint64 *end_time); G_END_DECLS diff --git a/src/libsysprof-ui/sysprof-marks-view.c b/src/libsysprof-ui/sysprof-marks-view.c index a9dfa5da..4039eb5d 100644 --- a/src/libsysprof-ui/sysprof-marks-view.c +++ b/src/libsysprof-ui/sysprof-marks-view.c @@ -22,12 +22,14 @@ #include "config.h" +#include "sysprof-cell-renderer-duration.h" #include "sysprof-marks-model.h" #include "sysprof-marks-view.h" typedef struct { - GtkTreeView *tree_view; + GtkTreeView *tree_view; + SysprofCellRendererDuration *duration_cell; } SysprofMarksViewPrivate; G_DEFINE_TYPE_WITH_PRIVATE (SysprofMarksView, sysprof_marks_view, GTK_TYPE_BIN) @@ -39,6 +41,9 @@ sysprof_marks_view_class_init (SysprofMarksViewClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-marks-view.ui"); gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksView, tree_view); + gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksView, duration_cell); + + g_type_ensure (SYSPROF_TYPE_CELL_RENDERER_DURATION); } static void @@ -62,14 +67,24 @@ new_marks_model_cb (GObject *object, SysprofMarksViewPrivate *priv = sysprof_marks_view_get_instance_private (self); g_autoptr(SysprofMarksModel) model = NULL; g_autoptr(GError) error = NULL; + gint64 zoom_begin, zoom_end; g_assert (SYSPROF_IS_MARKS_VIEW (self)); g_assert (G_IS_ASYNC_RESULT (result)); if (!(model = sysprof_marks_model_new_finish (result, &error))) - g_warning ("Failed to load marks model: %s", error->message); - else - gtk_tree_view_set_model (priv->tree_view, GTK_TREE_MODEL (model)); + { + g_warning ("Failed to load marks model: %s", error->message); + return; + } + + sysprof_marks_model_get_range (model, &zoom_begin, &zoom_end); + g_object_set (priv->duration_cell, + "zoom-begin", zoom_begin, + "zoom-end", zoom_end, + NULL); + + gtk_tree_view_set_model (priv->tree_view, GTK_TREE_MODEL (model)); } void diff --git a/src/libsysprof-ui/ui/sysprof-marks-view.ui b/src/libsysprof-ui/ui/sysprof-marks-view.ui index 6c23fa1f..38428848 100644 --- a/src/libsysprof-ui/ui/sysprof-marks-view.ui +++ b/src/libsysprof-ui/ui/sysprof-marks-view.ui @@ -39,11 +39,12 @@ - - Duration - true + + Elapsed + true + false - + 0 @@ -52,6 +53,21 @@ + + + Duration + true + + + 0 + + + 2 + 3 + + + +