From 1140e80efc12e78cbc567dd699b47f168df32a31 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Wed, 16 May 2018 12:43:35 +0100 Subject: [PATCH] rectangles: start on helper to generate rectangle data This is meant to be used by marks visualizer to show rectangles. --- lib/util/meson.build | 4 +- lib/util/rectangles.c | 196 ++++++++++++++++++++++++++++++++++++++++++ lib/util/rectangles.h | 43 +++++++++ 3 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 lib/util/rectangles.c create mode 100644 lib/util/rectangles.h diff --git a/lib/util/meson.build b/lib/util/meson.build index 4b3f18b2..0b9ebbd3 100644 --- a/lib/util/meson.build +++ b/lib/util/meson.build @@ -39,6 +39,8 @@ util_ui_headers = [ util_ui_sources = [ 'pointcache.c', 'pointcache.h', + 'rectangles.c', + 'rectangles.h', 'sp-color-cycle.c', 'sp-color-cycle.h', 'sp-model-filter.c', @@ -57,4 +59,4 @@ libsysprof_ui_sources += files(util_ui_sources) install_headers(util_ui_headers, subdir: join_paths(libsysprof_header_subdir, 'util')) -endif +endif \ No newline at end of file diff --git a/lib/util/rectangles.c b/lib/util/rectangles.c new file mode 100644 index 00000000..6d5b1140 --- /dev/null +++ b/lib/util/rectangles.c @@ -0,0 +1,196 @@ +/* rectangles.c + * + * Copyright 2018 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 + */ + +#include "util/rectangles.h" +#include "visualizers/sp-visualizer-row.h" + +typedef struct +{ + const gchar *name; + const gchar *message; + gint64 begin; + gint64 end; + GdkRectangle area; +} Rectangle; + +struct _Rectangles +{ + GStringChunk *strings; + GArray *rectangles; + GHashTable *y_indexes; + gint64 begin_time; + gint64 end_time; + guint sorted : 1; +}; + +Rectangles * +rectangles_new (gint64 begin_time, + gint64 end_time) +{ + Rectangles *self; + + self = g_slice_new0 (Rectangles); + self->strings = g_string_chunk_new (4096); + self->rectangles = g_array_new (FALSE, FALSE, sizeof (Rectangle)); + self->y_indexes = g_hash_table_new (g_str_hash, g_str_equal); + self->begin_time = begin_time; + self->end_time = end_time; + self->sorted = FALSE; + + return self; +} + +void +rectangles_add (Rectangles *self, + gint64 begin_time, + gint64 end_time, + const gchar *name, + const gchar *message) +{ + Rectangle rect = {0}; + + g_assert (self != NULL); + + if (message != NULL) + rect.message = g_string_chunk_insert_const (self->strings, message); + + if (name != NULL) + rect.name = g_string_chunk_insert_const (self->strings, name); + + rect.begin = begin_time; + rect.end = end_time; + + if (rect.end == rect.begin) + rect.area.width = 1; + + g_array_append_val (self->rectangles, rect); + + self->sorted = FALSE; +} + +void +rectangles_free (Rectangles *self) +{ + g_string_chunk_free (self->strings); + g_array_unref (self->rectangles); + g_slice_free (Rectangles, self); +} + +static gint +sort_rectangles (gconstpointer a, + gconstpointer b) +{ + const Rectangle *r1 = a; + const Rectangle *r2 = b; + gint64 r = r1->begin - r2->begin; + if (r == 0) + r = r1->end - r2->end; + if (r > 0) return 1; + else if (r < 0) return -1; + else return 0; +} + +static void +rectangles_sort (Rectangles *self) +{ + guint sequence = 0; + + g_assert (self != NULL); + + if (self->sorted) + return; + + g_array_sort (self->rectangles, sort_rectangles); + + g_hash_table_remove_all (self->y_indexes); + + for (guint i = 0; i < self->rectangles->len; i++) + { + const Rectangle *rect = &g_array_index (self->rectangles, Rectangle, i); + + if (!g_hash_table_contains (self->y_indexes, rect->name)) + g_hash_table_insert (self->y_indexes, (gchar *)rect->name, GUINT_TO_POINTER (++sequence)); + } + + self->sorted = TRUE; +} + +void +rectangles_draw (Rectangles *self, + GtkWidget *row, + cairo_t *cr) +{ + GtkAllocation alloc; + gdouble range; + guint n_rows; + + g_assert (self != NULL); + g_assert (SP_IS_VISUALIZER_ROW (row)); + g_assert (cr != NULL); + + if (!self->sorted) + rectangles_sort (self); + + gtk_widget_get_allocation (row, &alloc); + n_rows = g_hash_table_size (self->y_indexes); + if (n_rows == 0 || alloc.height == 0) + return; + + range = self->end_time - self->begin_time; + + for (guint i = 0; i < self->rectangles->len; i++) + { + const Rectangle *rect = &g_array_index (self->rectangles, Rectangle, i); + guint y_index = GPOINTER_TO_UINT (g_hash_table_lookup (self->y_indexes, rect->name)); + SpVisualizerRowRelativePoint in_points[2]; + SpVisualizerRowAbsolutePoint out_points[2]; + GdkRectangle r; + + in_points[0].x = (rect->begin - self->begin_time) / range; + in_points[0].y = y_index / (gfloat)n_rows; + in_points[1].x = (rect->end - self->begin_time) / range; + in_points[1].y = y_index / (gfloat)n_rows + 1; + + sp_visualizer_row_translate_points (SP_VISUALIZER_ROW (row), + in_points, G_N_ELEMENTS (in_points), + out_points, G_N_ELEMENTS (out_points)); + + r.x = out_points[0].x; + r.y = out_points[0].y; + r.height = out_points[1].y - out_points[0].y; + + if (rect->end == rect->begin) + r.width = 1; + else + r.width = MAX (1, out_points[1].x - out_points[0].x); + + gdk_cairo_rectangle (cr, &r); + } + + cairo_fill (cr); +} + +void +rectangles_set_end_time (Rectangles *self, + gint64 end_time) +{ + /* We might not know the real end time until we've exhausted the stream */ + self->end_time = end_time; +} diff --git a/lib/util/rectangles.h b/lib/util/rectangles.h new file mode 100644 index 00000000..944b7a1c --- /dev/null +++ b/lib/util/rectangles.h @@ -0,0 +1,43 @@ +/* rectangles.h + * + * Copyright 2018 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 + +typedef struct _Rectangles Rectangles; + +Rectangles *rectangles_new (gint64 begin_time, + gint64 end_time); +void rectangles_free (Rectangles *self); +void rectangles_draw (Rectangles *self, + GtkWidget *widget, + cairo_t *cr); +void rectangles_add (Rectangles *self, + gint64 begin_time, + gint64 end_time, + const gchar *name, + const gchar *message); +void rectangles_set_end_time (Rectangles *self, + gint64 end_time); + +G_END_DECLS