mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
277 lines
8.3 KiB
C
277 lines
8.3 KiB
C
/* sysprof-mark-visualizer.c
|
|
*
|
|
* Copyright 2018-2019 Christian Hergert <chergert@redhat.com>
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#define G_LOG_DOMAIN "sysprof-mark-visualizer"
|
|
|
|
#include "config.h"
|
|
|
|
#include "sysprof-mark-visualizer.h"
|
|
|
|
#define RECT_HEIGHT (4)
|
|
#define RECT_MIN_WIDTH (3)
|
|
#define RECT_OVERLAP (-1)
|
|
|
|
struct _SysprofMarkVisualizer
|
|
{
|
|
SysprofVisualizer parent_instance;
|
|
GHashTable *spans_by_group;
|
|
GHashTable *rgba_by_group;
|
|
GHashTable *rgba_by_kind;
|
|
GHashTable *row_by_kind;
|
|
guint x_is_dirty : 1;
|
|
};
|
|
|
|
G_DEFINE_TYPE (SysprofMarkVisualizer, sysprof_mark_visualizer, SYSPROF_TYPE_VISUALIZER)
|
|
|
|
static void
|
|
reset_positions (SysprofMarkVisualizer *self)
|
|
{
|
|
g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
|
|
|
|
self->x_is_dirty = TRUE;
|
|
gtk_widget_queue_draw (GTK_WIDGET (self));
|
|
}
|
|
|
|
SysprofVisualizer *
|
|
sysprof_mark_visualizer_new (GHashTable *groups)
|
|
{
|
|
SysprofMarkVisualizer *self;
|
|
guint n_items;
|
|
gint height;
|
|
|
|
g_return_val_if_fail (groups != NULL, NULL);
|
|
|
|
self = g_object_new (SYSPROF_TYPE_MARK_VISUALIZER, NULL);
|
|
self->spans_by_group = g_hash_table_ref (groups);
|
|
|
|
reset_positions (self);
|
|
|
|
n_items = g_hash_table_size (groups);
|
|
height = MAX (35, n_items * (RECT_HEIGHT - RECT_OVERLAP));
|
|
gtk_widget_set_size_request (GTK_WIDGET (self), -1, height);
|
|
|
|
return SYSPROF_VISUALIZER (g_steal_pointer (&self));
|
|
}
|
|
|
|
static void
|
|
sysprof_mark_visualizer_snapshot (GtkWidget *widget,
|
|
GtkSnapshot *snapshot)
|
|
{
|
|
SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)widget;
|
|
SysprofVisualizer *vis = (SysprofVisualizer *)widget;
|
|
static const GdkRGBA black = {0,0,0,1};
|
|
const GdkRGBA *rgba = &black;
|
|
GHashTableIter iter;
|
|
GtkAllocation alloc;
|
|
gpointer k, v;
|
|
int n_groups = 0;
|
|
int y = 0;
|
|
|
|
g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
|
|
g_assert (snapshot != NULL);
|
|
|
|
GTK_WIDGET_CLASS (sysprof_mark_visualizer_parent_class)->snapshot (widget, snapshot);
|
|
|
|
if (self->spans_by_group == NULL)
|
|
return;
|
|
|
|
gtk_widget_get_allocation (widget, &alloc);
|
|
|
|
/* Pre-calculate all time slots so we can join later */
|
|
if (self->x_is_dirty)
|
|
{
|
|
g_hash_table_iter_init (&iter, self->spans_by_group);
|
|
while (g_hash_table_iter_next (&iter, &k, &v))
|
|
{
|
|
const GArray *spans = v;
|
|
|
|
for (guint i = 0; i < spans->len; i++)
|
|
{
|
|
SysprofMarkTimeSpan *span = &g_array_index (spans, SysprofMarkTimeSpan, i);
|
|
|
|
span->x = sysprof_visualizer_get_x_for_time (vis, span->begin);
|
|
span->x2 = sysprof_visualizer_get_x_for_time (vis, span->end);
|
|
}
|
|
}
|
|
|
|
self->x_is_dirty = FALSE;
|
|
}
|
|
|
|
n_groups = g_hash_table_size (self->spans_by_group);
|
|
|
|
g_hash_table_iter_init (&iter, self->spans_by_group);
|
|
while (g_hash_table_iter_next (&iter, &k, &v))
|
|
{
|
|
SysprofMarkTimeSpan *span;
|
|
const gchar *group = k;
|
|
const GArray *spans = v;
|
|
const GdkRGBA *kindrgba;
|
|
const GdkRGBA *grouprgba;
|
|
|
|
if ((grouprgba = g_hash_table_lookup (self->rgba_by_group, group)))
|
|
rgba = grouprgba;
|
|
|
|
for (guint i = 0; i < spans->len; i++)
|
|
{
|
|
gint x1, x2;
|
|
|
|
span = &g_array_index (spans, SysprofMarkTimeSpan, i);
|
|
|
|
if (n_groups == 1)
|
|
{
|
|
rgba = &black;
|
|
if ((kindrgba = g_hash_table_lookup (self->rgba_by_kind, GUINT_TO_POINTER (span->kind))))
|
|
rgba = kindrgba;
|
|
else if ((grouprgba = g_hash_table_lookup (self->rgba_by_group, group)))
|
|
rgba = grouprgba;
|
|
}
|
|
|
|
x1 = span->x;
|
|
x2 = x1 + RECT_MIN_WIDTH;
|
|
|
|
if (span->x2 > x2)
|
|
x2 = span->x2;
|
|
|
|
/* If we are limited to one group, we might need to get the row
|
|
* height for the kind of span this is.
|
|
*/
|
|
if (n_groups == 1)
|
|
{
|
|
gint row = GPOINTER_TO_INT (g_hash_table_lookup (self->row_by_kind, GUINT_TO_POINTER (span->kind)));
|
|
y = row * (RECT_HEIGHT - RECT_OVERLAP);
|
|
}
|
|
|
|
for (guint j = i + 1; j < spans->len; j++)
|
|
{
|
|
const SysprofMarkTimeSpan *next = &g_array_index (spans, SysprofMarkTimeSpan, j);
|
|
|
|
/* Don't join this if we are about to draw a different kind */
|
|
if (n_groups == 1 && next->kind != span->kind)
|
|
break;
|
|
|
|
if (next->x <= x2)
|
|
{
|
|
x2 = MAX (x2, next->x2);
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
gtk_snapshot_append_color (snapshot, rgba, &GRAPHENE_RECT_INIT (x1, y, x2 - x1, RECT_HEIGHT));
|
|
}
|
|
|
|
y += RECT_HEIGHT + RECT_OVERLAP;
|
|
}
|
|
}
|
|
|
|
static void
|
|
sysprof_mark_visualizer_size_allocate (GtkWidget *widget,
|
|
int width,
|
|
int height,
|
|
int baseline)
|
|
{
|
|
SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)widget;
|
|
|
|
g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
|
|
|
|
GTK_WIDGET_CLASS (sysprof_mark_visualizer_parent_class)->size_allocate (widget, width, height, baseline);
|
|
|
|
reset_positions (self);
|
|
}
|
|
|
|
static void
|
|
sysprof_mark_visualizer_finalize (GObject *object)
|
|
{
|
|
SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)object;
|
|
|
|
g_clear_pointer (&self->spans_by_group, g_hash_table_unref);
|
|
g_clear_pointer (&self->rgba_by_group, g_hash_table_unref);
|
|
g_clear_pointer (&self->rgba_by_kind, g_hash_table_unref);
|
|
g_clear_pointer (&self->row_by_kind, g_hash_table_unref);
|
|
|
|
G_OBJECT_CLASS (sysprof_mark_visualizer_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
sysprof_mark_visualizer_class_init (SysprofMarkVisualizerClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
object_class->finalize = sysprof_mark_visualizer_finalize;
|
|
|
|
widget_class->snapshot = sysprof_mark_visualizer_snapshot;
|
|
widget_class->size_allocate = sysprof_mark_visualizer_size_allocate;
|
|
}
|
|
|
|
static void
|
|
sysprof_mark_visualizer_init (SysprofMarkVisualizer *self)
|
|
{
|
|
self->rgba_by_kind = g_hash_table_new_full (NULL, NULL, NULL, g_free);
|
|
self->row_by_kind = g_hash_table_new (NULL, NULL);
|
|
self->rgba_by_group = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
}
|
|
|
|
void
|
|
sysprof_mark_visualizer_set_group_rgba (SysprofMarkVisualizer *self,
|
|
const gchar *group,
|
|
const GdkRGBA *rgba)
|
|
{
|
|
g_return_if_fail (SYSPROF_IS_MARK_VISUALIZER (self));
|
|
g_return_if_fail (group != NULL);
|
|
|
|
g_hash_table_insert (self->rgba_by_group,
|
|
g_strdup (group),
|
|
g_memdup2 (rgba, sizeof *rgba));
|
|
}
|
|
|
|
void
|
|
sysprof_mark_visualizer_set_kind_rgba (SysprofMarkVisualizer *self,
|
|
GHashTable *rgba_by_kind)
|
|
{
|
|
g_return_if_fail (SYSPROF_IS_MARK_VISUALIZER (self));
|
|
|
|
if (rgba_by_kind != self->rgba_by_kind)
|
|
{
|
|
g_hash_table_remove_all (self->row_by_kind);
|
|
|
|
g_clear_pointer (&self->rgba_by_kind, g_hash_table_unref);
|
|
|
|
if (rgba_by_kind)
|
|
{
|
|
GHashTableIter iter;
|
|
guint row = 0;
|
|
gpointer k;
|
|
|
|
self->rgba_by_kind = g_hash_table_ref (rgba_by_kind);
|
|
|
|
g_hash_table_iter_init (&iter, rgba_by_kind);
|
|
while (g_hash_table_iter_next (&iter, &k, NULL))
|
|
g_hash_table_insert (self->row_by_kind, k, GUINT_TO_POINTER (row++));
|
|
|
|
gtk_widget_set_size_request (GTK_WIDGET (self),
|
|
-1,
|
|
MAX (35, row * (RECT_HEIGHT - RECT_OVERLAP)));
|
|
}
|
|
}
|
|
}
|