diff --git a/src/libsysprof-gtk/meson.build b/src/libsysprof-gtk/meson.build index 7b5c1163..08a40cec 100644 --- a/src/libsysprof-gtk/meson.build +++ b/src/libsysprof-gtk/meson.build @@ -1,11 +1,27 @@ libsysprof_gtk_public_sources = [ 'sysprof-callgraph-view.c', + 'sysprof-chart.c', + 'sysprof-chart-layer.c', + 'sysprof-depth-layer.c', 'sysprof-mark-chart.c', 'sysprof-mark-table.c', 'sysprof-session.c', 'sysprof-weighted-callgraph-view.c', ] +libsysprof_gtk_public_headers = [ + 'sysprof-gtk.h', + + 'sysprof-callgraph-view.h', + 'sysprof-chart.h', + 'sysprof-chart-layer.h', + 'sysprof-depth-layer.h', + 'sysprof-mark-chart.h', + 'sysprof-mark-table.h', + 'sysprof-session.h', + 'sysprof-weighted-callgraph-view.h', +] + libsysprof_gtk_private_sources = [ 'sysprof-css.c', 'sysprof-mark-chart-item.c', @@ -15,16 +31,6 @@ libsysprof_gtk_private_sources = [ 'sysprof-time-label.c', ] -libsysprof_gtk_public_headers = [ - 'sysprof-gtk.h', - - 'sysprof-callgraph-view.h', - 'sysprof-mark-chart.h', - 'sysprof-mark-table.h', - 'sysprof-session.h', - 'sysprof-weighted-callgraph-view.h', -] - libsysprof_gtk_deps = [ dependency('libadwaita-1'), dependency('libpanel-1'), diff --git a/src/libsysprof-gtk/sysprof-chart-layer.c b/src/libsysprof-gtk/sysprof-chart-layer.c new file mode 100644 index 00000000..b25b3fd9 --- /dev/null +++ b/src/libsysprof-gtk/sysprof-chart-layer.c @@ -0,0 +1,131 @@ +/* sysprof-chart-layer.c + * + * Copyright 2023 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 "config.h" + +#include "sysprof-chart-layer.h" + +typedef struct +{ + char *title; +} SysprofChartLayerPrivate; + +enum { + PROP_0, + PROP_TITLE, + N_PROPS +}; + +G_DEFINE_ABSTRACT_TYPE (SysprofChartLayer, sysprof_chart_layer, GTK_TYPE_WIDGET) + +static GParamSpec *properties [N_PROPS]; + +static void +sysprof_chart_layer_dispose (GObject *object) +{ + SysprofChartLayer *self = (SysprofChartLayer *)object; + SysprofChartLayerPrivate *priv = sysprof_chart_layer_get_instance_private (self); + + g_clear_pointer (&priv->title, g_free); + + G_OBJECT_CLASS (sysprof_chart_layer_parent_class)->dispose (object); +} + +static void +sysprof_chart_layer_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofChartLayer *self = SYSPROF_CHART_LAYER (object); + + switch (prop_id) + { + case PROP_TITLE: + g_value_set_string (value, sysprof_chart_layer_get_title (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_layer_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofChartLayer *self = SYSPROF_CHART_LAYER (object); + + switch (prop_id) + { + case PROP_TITLE: + sysprof_chart_layer_set_title (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_layer_class_init (SysprofChartLayerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = sysprof_chart_layer_dispose; + object_class->get_property = sysprof_chart_layer_get_property; + object_class->set_property = sysprof_chart_layer_set_property; + + properties[PROP_TITLE] = + g_param_spec_string ("title", NULL, NULL, + NULL, + (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_chart_layer_init (SysprofChartLayer *self) +{ +} + +const char * +sysprof_chart_layer_get_title (SysprofChartLayer *self) +{ + SysprofChartLayerPrivate *priv = sysprof_chart_layer_get_instance_private (self); + + g_return_val_if_fail (SYSPROF_IS_CHART_LAYER (self), NULL); + + return priv->title; +} + +void +sysprof_chart_layer_set_title (SysprofChartLayer *self, + const char *title) +{ + SysprofChartLayerPrivate *priv = sysprof_chart_layer_get_instance_private (self); + + g_return_if_fail (SYSPROF_IS_CHART_LAYER (self)); + + if (g_set_str (&priv->title, title)) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]); +} diff --git a/src/libsysprof-gtk/sysprof-chart-layer.h b/src/libsysprof-gtk/sysprof-chart-layer.h new file mode 100644 index 00000000..b6aba5ff --- /dev/null +++ b/src/libsysprof-gtk/sysprof-chart-layer.h @@ -0,0 +1,48 @@ +/* sysprof-chart-layer.h + * + * Copyright 2023 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 + +#include + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_CHART_LAYER (sysprof_chart_layer_get_type()) + +SYSPROF_AVAILABLE_IN_ALL +G_DECLARE_DERIVABLE_TYPE (SysprofChartLayer, sysprof_chart_layer, SYSPROF, CHART_LAYER, GtkWidget) + +struct _SysprofChartLayerClass +{ + GtkWidgetClass parent_class; + + /*< private >*/ + gpointer _reserved[16]; +}; + +SYSPROF_AVAILABLE_IN_ALL +const char *sysprof_chart_layer_get_title (SysprofChartLayer *self); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_chart_layer_set_title (SysprofChartLayer *self, + const char *title); + +G_END_DECLS diff --git a/src/libsysprof-gtk/sysprof-chart.c b/src/libsysprof-gtk/sysprof-chart.c new file mode 100644 index 00000000..514d53d6 --- /dev/null +++ b/src/libsysprof-gtk/sysprof-chart.c @@ -0,0 +1,153 @@ +/* sysprof-chart.c + * + * Copyright 2023 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 "config.h" + +#include "sysprof-chart.h" + +typedef struct +{ + char *title; +} SysprofChartPrivate; + +enum { + PROP_0, + PROP_TITLE, + N_PROPS +}; + +G_DEFINE_TYPE_WITH_PRIVATE (SysprofChart, sysprof_chart, GTK_TYPE_WIDGET) + +static GParamSpec *properties [N_PROPS]; + +static void +sysprof_chart_dispose (GObject *object) +{ + SysprofChart *self = (SysprofChart *)object; + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_clear_pointer (&priv->title, g_free); + + G_OBJECT_CLASS (sysprof_chart_parent_class)->dispose (object); +} + +static void +sysprof_chart_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofChart *self = SYSPROF_CHART (object); + + switch (prop_id) + { + case PROP_TITLE: + g_value_set_string (value, sysprof_chart_get_title (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofChart *self = SYSPROF_CHART (object); + + switch (prop_id) + { + case PROP_TITLE: + sysprof_chart_set_title (self, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_class_init (SysprofChartClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = sysprof_chart_dispose; + object_class->get_property = sysprof_chart_get_property; + object_class->set_property = sysprof_chart_set_property; + + properties[PROP_TITLE] = + g_param_spec_string ("title", NULL, NULL, + NULL, + (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_chart_init (SysprofChart *self) +{ +} + +const char * +sysprof_chart_get_title (SysprofChart *self) +{ + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_return_val_if_fail (SYSPROF_IS_CHART (self), NULL); + + return priv->title; +} + +void +sysprof_chart_set_title (SysprofChart *self, + const char *title) +{ + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_return_if_fail (SYSPROF_IS_CHART (self)); + + if (g_set_str (&priv->title, title)) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]); +} + +void +sysprof_chart_add_layer (SysprofChart *self, + SysprofChartLayer *layer) +{ + g_return_if_fail (SYSPROF_IS_CHART (self)); + g_return_if_fail (SYSPROF_IS_CHART_LAYER (layer)); + g_return_if_fail (gtk_widget_get_parent (GTK_WIDGET (layer)) == NULL); + + gtk_widget_set_parent (GTK_WIDGET (layer), GTK_WIDGET (self)); +} + +void +sysprof_chart_remove_layer (SysprofChart *self, + SysprofChartLayer *layer) +{ + g_return_if_fail (SYSPROF_IS_CHART (self)); + g_return_if_fail (SYSPROF_IS_CHART_LAYER (layer)); + g_return_if_fail (gtk_widget_get_parent (GTK_WIDGET (layer)) == GTK_WIDGET (self)); + + gtk_widget_unparent (GTK_WIDGET (layer)); +} diff --git a/src/libsysprof-gtk/sysprof-chart.h b/src/libsysprof-gtk/sysprof-chart.h new file mode 100644 index 00000000..e3a05112 --- /dev/null +++ b/src/libsysprof-gtk/sysprof-chart.h @@ -0,0 +1,57 @@ +/* sysprof-chart.h + * + * Copyright 2023 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 + +#include + +#include "sysprof-chart-layer.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_CHART (sysprof_chart_get_type()) + +G_DECLARE_DERIVABLE_TYPE (SysprofChart, sysprof_chart, SYSPROF, CHART, GtkWidget) + +struct _SysprofChartClass +{ + GtkWidgetClass parent_class; + + /*< private >*/ + gpointer _reserved[16]; +}; + +SYSPROF_AVAILABLE_IN_ALL +GtkWidget *sysprof_chart_new (void); +SYSPROF_AVAILABLE_IN_ALL +const char *sysprof_chart_get_title (SysprofChart *self); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_chart_set_title (SysprofChart *self, + const char *title); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_chart_add_layer (SysprofChart *self, + SysprofChartLayer *layer); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_chart_remove_layer (SysprofChart *self, + SysprofChartLayer *layer); + +G_END_DECLS diff --git a/src/libsysprof-gtk/sysprof-depth-layer.c b/src/libsysprof-gtk/sysprof-depth-layer.c new file mode 100644 index 00000000..5456076d --- /dev/null +++ b/src/libsysprof-gtk/sysprof-depth-layer.c @@ -0,0 +1,234 @@ +/* sysprof-depth-layer.c + * + * Copyright 2023 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 "config.h" + +#include "sysprof-depth-layer.h" + +struct _SysprofDepthLayer +{ + SysprofChartLayer parent_instance; + SysprofXYSeries *series; + GdkRGBA color; +}; + +enum { + PROP_0, + PROP_COLOR, + PROP_SERIES, + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (SysprofDepthLayer, sysprof_depth_layer, SYSPROF_TYPE_CHART_LAYER) + +static GParamSpec *properties [N_PROPS]; + +static void +sysprof_depth_layer_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) +{ + SysprofDepthLayer *self = (SysprofDepthLayer *)widget; + const SysprofXYSeriesValue *values; + guint n_values; + float min_x, max_x; + int line_width; + int width; + int height; + + g_assert (SYSPROF_IS_DEPTH_LAYER (self)); + g_assert (GTK_IS_SNAPSHOT (snapshot)); + + if (self->series == NULL || self->color.alpha == 0) + return; + + if (!(values = sysprof_xy_series_get_values (self->series, &n_values))) + return; + + sysprof_xy_series_get_range (self->series, &min_x, NULL, &max_x, NULL); + + width = gtk_widget_get_width (widget); + height = gtk_widget_get_width (widget); + + line_width = MAX (1, (max_x - min_x) / width); + + for (guint i = 0; i < n_values; i++) + { + const SysprofXYSeriesValue *v = &values[i]; + + gtk_snapshot_append_color (snapshot, + &self->color, + &GRAPHENE_RECT_INIT (v->x * width, + height, + line_width, + height - (v->y * height))); + } +} + +static void +sysprof_depth_layer_dispose (GObject *object) +{ + SysprofDepthLayer *self = (SysprofDepthLayer *)object; + + g_clear_pointer (&self->series, sysprof_xy_series_unref); + + G_OBJECT_CLASS (sysprof_depth_layer_parent_class)->dispose (object); +} + +static void +sysprof_depth_layer_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofDepthLayer *self = SYSPROF_DEPTH_LAYER (object); + + switch (prop_id) + { + case PROP_COLOR: + g_value_set_boxed (value, &self->color); + break; + + case PROP_SERIES: + g_value_set_boxed (value, self->series); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_depth_layer_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofDepthLayer *self = SYSPROF_DEPTH_LAYER (object); + + switch (prop_id) + { + case PROP_COLOR: + sysprof_depth_layer_set_color (self, g_value_get_boxed (value)); + break; + + case PROP_SERIES: + sysprof_depth_layer_set_series (self, g_value_get_boxed (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_depth_layer_class_init (SysprofDepthLayerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->dispose = sysprof_depth_layer_dispose; + object_class->get_property = sysprof_depth_layer_get_property; + object_class->set_property = sysprof_depth_layer_set_property; + + widget_class->snapshot = sysprof_depth_layer_snapshot; + + properties[PROP_COLOR] = + g_param_spec_boxed ("color", NULL, NULL, + GDK_TYPE_RGBA, + (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + + properties[PROP_SERIES] = + g_param_spec_boxed ("series", NULL, NULL, + SYSPROF_TYPE_XY_SERIES, + (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_depth_layer_init (SysprofDepthLayer *self) +{ + self->color.alpha = 1; +} + +SysprofChartLayer * +sysprof_depth_layer_new (void) +{ + return g_object_new (SYSPROF_TYPE_DEPTH_LAYER, NULL); +} + +const GdkRGBA * +sysprof_depth_layer_get_color (SysprofDepthLayer *self) +{ + return &self->color; +} + +void +sysprof_depth_layer_set_color (SysprofDepthLayer *self, + const GdkRGBA *color) +{ + static const GdkRGBA black = {0,0,0,1}; + + g_return_if_fail (SYSPROF_IS_DEPTH_LAYER (self)); + + if (color == NULL) + color = &black; + + if (!gdk_rgba_equal (&self->color, color)) + { + self->color = *color; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR]); + } +} + +/** + * sysprof_depth_layer_get_series: + * @self: a #SysprofDepthLayer + * + * Gets the data series to be drawn. + * + * Returns: (transfer none) (nullable): a #SysprofXYSeries or %NULL + */ +SysprofXYSeries * +sysprof_depth_layer_get_series (SysprofDepthLayer *self) +{ + g_return_val_if_fail (SYSPROF_IS_DEPTH_LAYER (self), NULL); + + return self->series; +} + +void +sysprof_depth_layer_set_series (SysprofDepthLayer *self, + SysprofXYSeries *series) +{ + g_return_if_fail (SYSPROF_IS_DEPTH_LAYER (self)); + + if (series == self->series) + return; + + g_clear_pointer (&self->series, sysprof_xy_series_unref); + + if (series) + self->series = sysprof_xy_series_ref (series); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SERIES]); + + gtk_widget_queue_draw (GTK_WIDGET (self)); +} diff --git a/src/libsysprof-gtk/sysprof-depth-layer.h b/src/libsysprof-gtk/sysprof-depth-layer.h new file mode 100644 index 00000000..e83d7899 --- /dev/null +++ b/src/libsysprof-gtk/sysprof-depth-layer.h @@ -0,0 +1,49 @@ +/* sysprof-depth-layer.h + * + * Copyright 2023 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 + +#include + +#include "sysprof-chart-layer.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_DEPTH_LAYER (sysprof_depth_layer_get_type()) + +SYSPROF_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (SysprofDepthLayer, sysprof_depth_layer, SYSPROF, DEPTH_LAYER, SysprofChartLayer) + +SYSPROF_AVAILABLE_IN_ALL +SysprofChartLayer *sysprof_depth_layer_new (void); +SYSPROF_AVAILABLE_IN_ALL +const GdkRGBA *sysprof_depth_layer_get_color (SysprofDepthLayer *self); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_depth_layer_set_color (SysprofDepthLayer *self, + const GdkRGBA *color); +SYSPROF_AVAILABLE_IN_ALL +SysprofXYSeries *sysprof_depth_layer_get_series (SysprofDepthLayer *self); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_depth_layer_set_series (SysprofDepthLayer *self, + SysprofXYSeries *series); + +G_END_DECLS