diff --git a/src/sysprof/meson.build b/src/sysprof/meson.build index 8a575110..368fdd67 100644 --- a/src/sysprof/meson.build +++ b/src/sysprof/meson.build @@ -5,6 +5,9 @@ sysprof_sources = [ 'sysprof-callgraph-view.c', 'sysprof-category-icon.c', 'sysprof-chart-layer.c', + 'sysprof-chart-layer-factory.c', + 'sysprof-chart-layer-item.c', + 'sysprof-chart-layer-item-widget.c', 'sysprof-chart.c', 'sysprof-color-iter.c', 'sysprof-column-layer.c', diff --git a/src/sysprof/sysprof-chart-layer-factory-private.h b/src/sysprof/sysprof-chart-layer-factory-private.h new file mode 100644 index 00000000..a8add5e6 --- /dev/null +++ b/src/sysprof/sysprof-chart-layer-factory-private.h @@ -0,0 +1,31 @@ +/* sysprof-chart-layer-factory-private.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 "sysprof-chart-layer-factory.h" +#include "sysprof-chart-layer-item.h" + +G_BEGIN_DECLS + +void _sysprof_chart_layer_factory_setup (SysprofChartLayerFactory *self, + SysprofChartLayerItem *item); + +G_END_DECLS diff --git a/src/sysprof/sysprof-chart-layer-factory.c b/src/sysprof/sysprof-chart-layer-factory.c new file mode 100644 index 00000000..5244bc00 --- /dev/null +++ b/src/sysprof/sysprof-chart-layer-factory.c @@ -0,0 +1,217 @@ +/* sysprof-chart-layer-factory.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-factory.h" +#include "sysprof-chart-layer-item.h" + +struct _SysprofChartLayerFactory +{ + GObject parent_instance; + GtkBuilderScope *scope; + char *resource; + GBytes *bytes; +}; + +enum { + PROP_0, + PROP_BYTES, + PROP_RESOURCE, + PROP_SCOPE, + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (SysprofChartLayerFactory, sysprof_chart_layer_factory, G_TYPE_OBJECT) + +static GParamSpec *properties [N_PROPS]; + +void +_sysprof_chart_layer_factory_setup (SysprofChartLayerFactory *self, + SysprofChartLayerItem *item) +{ + g_autoptr(GtkBuilder) builder = NULL; + g_autoptr(GError) error = NULL; + + g_return_if_fail (SYSPROF_IS_CHART_LAYER_FACTORY (self)); + g_return_if_fail (G_IS_OBJECT (item)); + g_return_if_fail (self->bytes != NULL); + + builder = gtk_builder_new (); + + gtk_builder_set_current_object (builder, G_OBJECT (item)); + + if (self->scope) + gtk_builder_set_scope (builder, self->scope); + + /* XXX: This is private API, we might need it + * gtk_builder_set_allow_template_parents (builder, TRUE); + */ + + if (!gtk_builder_extend_with_template (builder, G_OBJECT (item), G_OBJECT_TYPE (item), + (const char *)g_bytes_get_data (self->bytes, NULL), + g_bytes_get_size (self->bytes), + &error)) + g_critical ("Error building template for chart layer: %s", error->message); +} + +static void +sysprof_chart_layer_factory_constructed (GObject *object) +{ + SysprofChartLayerFactory *self = (SysprofChartLayerFactory *)object; + + G_OBJECT_CLASS (sysprof_chart_layer_factory_parent_class)->constructed (object); + + if (self->resource != NULL && self->bytes == NULL) + { + self->bytes = g_resources_lookup_data (self->resource, 0, NULL); + + if (self->bytes == NULL) + g_warning ("Failed to locate resource at %s", self->resource); + } + + if (self->bytes == NULL) + g_warning ("SysprofChartLayerFactory created without a template"); +} + +static void +sysprof_chart_layer_factory_finalize (GObject *object) +{ + SysprofChartLayerFactory *self = (SysprofChartLayerFactory *)object; + + g_clear_object (&self->scope); + g_clear_pointer (&self->resource, g_free); + g_clear_pointer (&self->bytes, g_bytes_unref); + + G_OBJECT_CLASS (sysprof_chart_layer_factory_parent_class)->finalize (object); +} + +static void +sysprof_chart_layer_factory_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofChartLayerFactory *self = SYSPROF_CHART_LAYER_FACTORY (object); + + switch (prop_id) + { + case PROP_SCOPE: + g_value_set_object (value, self->scope); + break; + + case PROP_RESOURCE: + g_value_set_string (value, self->resource); + break; + + case PROP_BYTES: + g_value_set_boxed (value, self->bytes); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_layer_factory_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofChartLayerFactory *self = SYSPROF_CHART_LAYER_FACTORY (object); + + switch (prop_id) + { + case PROP_BYTES: + self->bytes = g_value_dup_boxed (value); + break; + + case PROP_RESOURCE: + self->resource = g_value_dup_string (value); + break; + + case PROP_SCOPE: + self->scope = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_layer_factory_class_init (SysprofChartLayerFactoryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = sysprof_chart_layer_factory_constructed; + object_class->finalize = sysprof_chart_layer_factory_finalize; + object_class->get_property = sysprof_chart_layer_factory_get_property; + object_class->set_property = sysprof_chart_layer_factory_set_property; + + properties[PROP_SCOPE] = + g_param_spec_object ("scope", NULL, NULL, + GTK_TYPE_BUILDER_SCOPE, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + properties[PROP_RESOURCE] = + g_param_spec_string ("resource", NULL, NULL, + NULL, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + properties[PROP_BYTES] = + g_param_spec_boxed ("bytes", NULL, NULL, + G_TYPE_BYTES, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_chart_layer_factory_init (SysprofChartLayerFactory *self) +{ +} + +SysprofChartLayerFactory * +sysprof_chart_layer_factory_new_from_bytes (GtkBuilderScope *scope, + GBytes *bytes) +{ + g_return_val_if_fail (!scope || GTK_IS_BUILDER_SCOPE (scope), NULL); + g_return_val_if_fail (bytes != NULL, NULL); + + return g_object_new (SYSPROF_TYPE_CHART_LAYER_FACTORY, + "scope", scope, + "bytes", bytes, + NULL); +} + +SysprofChartLayerFactory * +sysprof_chart_layer_factory_new_from_resource (GtkBuilderScope *scope, + const char *resource) +{ + g_return_val_if_fail (!scope || GTK_IS_BUILDER_SCOPE (scope), NULL); + g_return_val_if_fail (resource != NULL, NULL); + + return g_object_new (SYSPROF_TYPE_CHART_LAYER_FACTORY, + "scope", scope, + "resource", resource, + NULL); +} diff --git a/src/sysprof/sysprof-chart-layer-factory.h b/src/sysprof/sysprof-chart-layer-factory.h new file mode 100644 index 00000000..88c9e64b --- /dev/null +++ b/src/sysprof/sysprof-chart-layer-factory.h @@ -0,0 +1,36 @@ +/* sysprof-chart-layer-factory.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 "sysprof-chart-layer.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_CHART_LAYER_FACTORY (sysprof_chart_layer_factory_get_type()) + +G_DECLARE_FINAL_TYPE (SysprofChartLayerFactory, sysprof_chart_layer_factory, SYSPROF, CHART_LAYER_FACTORY, GObject) + +SysprofChartLayerFactory *sysprof_chart_layer_factory_new_from_resource (GtkBuilderScope *scope, + const char *resource); +SysprofChartLayerFactory *sysprof_chart_layer_factory_new_from_bytes (GtkBuilderScope *scope, + GBytes *bytes); + +G_END_DECLS diff --git a/src/sysprof/sysprof-chart-layer-item-widget.c b/src/sysprof/sysprof-chart-layer-item-widget.c new file mode 100644 index 00000000..f2fee192 --- /dev/null +++ b/src/sysprof/sysprof-chart-layer-item-widget.c @@ -0,0 +1,210 @@ +/* sysprof-chart-layer-item-widget.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-item-widget.h" + +struct _SysprofChartLayerItemWidget +{ + SysprofChartLayer parent_instance; + SysprofChartLayerItem *item; + guint disposed : 1; +}; + +enum { + PROP_0, + PROP_ITEM, + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (SysprofChartLayerItemWidget, sysprof_chart_layer_item_widget, SYSPROF_TYPE_CHART_LAYER) + +static GParamSpec *properties [N_PROPS]; + +static SysprofChartLayer * +get_layer (SysprofChartLayer *self) +{ + GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self)); + + return SYSPROF_CHART_LAYER (child); +} + + +static gpointer +sysprof_chart_layer_item_widget_lookup_item (SysprofChartLayer *self, + double x, + double y) +{ + SysprofChartLayer *layer; + + if (!(layer = get_layer (self))) + return NULL; + + return sysprof_chart_layer_lookup_item (layer, x, y); +} + +static void +sysprof_chart_layer_item_widget_snapshot_motion (SysprofChartLayer *self, + GtkSnapshot *snapshot, + double x, + double y) +{ + SysprofChartLayer *layer; + + if (!(layer = get_layer (self))) + return; + + sysprof_chart_layer_snapshot_motion (layer, snapshot, x, y); +} + +static void +sysprof_chart_layer_item_widget_notify_layer_cb (SysprofChartLayerItemWidget *self, + GParamSpec *pspec, + SysprofChartLayerItem *item) +{ + GtkWidget *child; + + g_assert (SYSPROF_IS_CHART_LAYER_ITEM_WIDGET (self)); + g_assert (SYSPROF_IS_CHART_LAYER_ITEM (item)); + + if (self->disposed) + return; + + while ((child = gtk_widget_get_first_child (GTK_WIDGET (self)))) + gtk_widget_unparent (child); + + if ((child = GTK_WIDGET (sysprof_chart_layer_item_get_layer (item)))) + gtk_widget_set_parent (child, GTK_WIDGET (self)); +} + +static void +sysprof_chart_layer_item_widget_constructed (GObject *object) +{ + SysprofChartLayerItemWidget *self = (SysprofChartLayerItemWidget *)object; + SysprofChartLayer *layer; + + G_OBJECT_CLASS (sysprof_chart_layer_item_widget_parent_class)->constructed (object); + + g_return_if_fail (self->item != NULL); + + if ((layer = sysprof_chart_layer_item_get_layer (self->item))) + gtk_widget_set_parent (GTK_WIDGET (layer), GTK_WIDGET (self)); + + g_signal_connect_object (self->item, + "notify::layer", + G_CALLBACK (sysprof_chart_layer_item_widget_notify_layer_cb), + self, + G_CONNECT_SWAPPED); +} + +static void +sysprof_chart_layer_item_widget_dispose (GObject *object) +{ + SysprofChartLayerItemWidget *self = (SysprofChartLayerItemWidget *)object; + GtkWidget *child; + + self->disposed = TRUE; + + while ((child = gtk_widget_get_first_child (GTK_WIDGET (self)))) + gtk_widget_unparent (child); + + g_clear_object (&self->item); + + G_OBJECT_CLASS (sysprof_chart_layer_item_widget_parent_class)->dispose (object); +} + +static void +sysprof_chart_layer_item_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofChartLayerItemWidget *self = SYSPROF_CHART_LAYER_ITEM_WIDGET (object); + + switch (prop_id) + { + case PROP_ITEM: + g_value_set_object (value, self->item); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_layer_item_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofChartLayerItemWidget *self = SYSPROF_CHART_LAYER_ITEM_WIDGET (object); + + switch (prop_id) + { + case PROP_ITEM: + self->item = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_layer_item_widget_class_init (SysprofChartLayerItemWidgetClass *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->constructed = sysprof_chart_layer_item_widget_constructed; + object_class->dispose = sysprof_chart_layer_item_widget_dispose; + object_class->get_property = sysprof_chart_layer_item_widget_get_property; + object_class->set_property = sysprof_chart_layer_item_widget_set_property; + + chart_layer_class->lookup_item = sysprof_chart_layer_item_widget_lookup_item; + chart_layer_class->snapshot_motion = sysprof_chart_layer_item_widget_snapshot_motion; + + properties[PROP_ITEM] = + g_param_spec_object ("item", NULL, NULL, + SYSPROF_TYPE_CHART_LAYER_ITEM, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); + + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); +} + +static void +sysprof_chart_layer_item_widget_init (SysprofChartLayerItemWidget *self) +{ +} + +SysprofChartLayerItemWidget * +sysprof_chart_layer_item_widget_new (SysprofChartLayerItem *item) +{ + g_return_val_if_fail (SYSPROF_IS_CHART_LAYER_ITEM (item), NULL); + + return g_object_new (SYSPROF_TYPE_CHART_LAYER_ITEM_WIDGET, + "item", item, + NULL); +} diff --git a/src/sysprof/sysprof-chart-layer-item-widget.h b/src/sysprof/sysprof-chart-layer-item-widget.h new file mode 100644 index 00000000..3a30eca0 --- /dev/null +++ b/src/sysprof/sysprof-chart-layer-item-widget.h @@ -0,0 +1,34 @@ +/* sysprof-chart-layer-item-widget.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 "sysprof-chart-layer.h" +#include "sysprof-chart-layer-item.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_CHART_LAYER_ITEM_WIDGET (sysprof_chart_layer_item_widget_get_type()) + +G_DECLARE_FINAL_TYPE (SysprofChartLayerItemWidget, sysprof_chart_layer_item_widget, SYSPROF, CHART_LAYER_ITEM_WIDGET, SysprofChartLayer) + +SysprofChartLayerItemWidget *sysprof_chart_layer_item_widget_new (SysprofChartLayerItem *item); + +G_END_DECLS diff --git a/src/sysprof/sysprof-chart-layer-item.c b/src/sysprof/sysprof-chart-layer-item.c new file mode 100644 index 00000000..fb46b590 --- /dev/null +++ b/src/sysprof/sysprof-chart-layer-item.c @@ -0,0 +1,152 @@ +/* sysprof-chart-layer-item.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-item.h" + +struct _SysprofChartLayerItem +{ + GObject parent_instance; + GObject *item; + SysprofChartLayer *layer; +}; + +enum { + PROP_0, + PROP_ITEM, + PROP_LAYER, + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (SysprofChartLayerItem, sysprof_chart_layer_item, G_TYPE_OBJECT) + +static GParamSpec *properties [N_PROPS]; + +static void +sysprof_chart_layer_item_dispose (GObject *object) +{ + SysprofChartLayerItem *self = (SysprofChartLayerItem *)object; + + g_clear_object (&self->layer); + g_clear_object (&self->item); + + G_OBJECT_CLASS (sysprof_chart_layer_item_parent_class)->dispose (object); +} + +static void +sysprof_chart_layer_item_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofChartLayerItem *self = SYSPROF_CHART_LAYER_ITEM (object); + + switch (prop_id) + { + case PROP_LAYER: + g_value_set_object (value, sysprof_chart_layer_item_get_layer (self)); + break; + + case PROP_ITEM: + g_value_set_object (value, sysprof_chart_layer_item_get_item (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_layer_item_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofChartLayerItem *self = SYSPROF_CHART_LAYER_ITEM (object); + + switch (prop_id) + { + case PROP_LAYER: + sysprof_chart_layer_item_set_layer (self, g_value_get_object (value)); + break; + + case PROP_ITEM: + self->item = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_chart_layer_item_class_init (SysprofChartLayerItemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = sysprof_chart_layer_item_dispose; + object_class->get_property = sysprof_chart_layer_item_get_property; + object_class->set_property = sysprof_chart_layer_item_set_property; + + properties[PROP_LAYER] = + g_param_spec_object ("layer", NULL, NULL, + SYSPROF_TYPE_CHART_LAYER, + (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + + properties[PROP_ITEM] = + g_param_spec_object ("item", NULL, NULL, + G_TYPE_OBJECT, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_chart_layer_item_init (SysprofChartLayerItem *self) +{ +} + +SysprofChartLayer * +sysprof_chart_layer_item_get_layer (SysprofChartLayerItem *self) +{ + g_return_val_if_fail (SYSPROF_IS_CHART_LAYER_ITEM (self), NULL); + + return self->layer; +} + +void +sysprof_chart_layer_item_set_layer (SysprofChartLayerItem *self, + SysprofChartLayer *layer) +{ + g_return_if_fail (SYSPROF_IS_CHART_LAYER_ITEM (self)); + g_return_if_fail (!layer || SYSPROF_IS_CHART_LAYER (layer)); + + if (g_set_object (&self->layer, layer)) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LAYER]); +} + +gpointer +sysprof_chart_layer_item_get_item (SysprofChartLayerItem *self) +{ + g_return_val_if_fail (SYSPROF_IS_CHART_LAYER_ITEM (self), NULL); + + return self->item; +} diff --git a/src/sysprof/sysprof-chart-layer-item.h b/src/sysprof/sysprof-chart-layer-item.h new file mode 100644 index 00000000..d0200ae2 --- /dev/null +++ b/src/sysprof/sysprof-chart-layer-item.h @@ -0,0 +1,36 @@ +/* sysprof-chart-layer-item.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 "sysprof-chart-layer.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_CHART_LAYER_ITEM (sysprof_chart_layer_item_get_type()) + +G_DECLARE_FINAL_TYPE (SysprofChartLayerItem, sysprof_chart_layer_item, SYSPROF, CHART_LAYER_ITEM, GObject) + +gpointer sysprof_chart_layer_item_get_item (SysprofChartLayerItem *self); +SysprofChartLayer *sysprof_chart_layer_item_get_layer (SysprofChartLayerItem *self); +void sysprof_chart_layer_item_set_layer (SysprofChartLayerItem *self, + SysprofChartLayer *layer); + +G_END_DECLS diff --git a/src/sysprof/sysprof-chart-layer.c b/src/sysprof/sysprof-chart-layer.c index 7481975c..9e54ec5f 100644 --- a/src/sysprof/sysprof-chart-layer.c +++ b/src/sysprof/sysprof-chart-layer.c @@ -20,6 +20,7 @@ #include "config.h" +#include "sysprof-chart.h" #include "sysprof-chart-layer-private.h" typedef struct @@ -29,6 +30,7 @@ typedef struct enum { PROP_0, + PROP_CHART, PROP_TITLE, N_PROPS }; @@ -76,6 +78,10 @@ sysprof_chart_layer_get_property (GObject *object, switch (prop_id) { + case PROP_CHART: + g_value_set_object (value, gtk_widget_get_ancestor (GTK_WIDGET (self), SYSPROF_TYPE_CHART)); + break; + case PROP_TITLE: g_value_set_string (value, sysprof_chart_layer_get_title (self)); break; @@ -104,6 +110,14 @@ sysprof_chart_layer_set_property (GObject *object, } } +static void +sysprof_chart_layer_root (GtkWidget *widget) +{ + GTK_WIDGET_CLASS (sysprof_chart_layer_parent_class)->root (widget); + + g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_CHART]); +} + static void sysprof_chart_layer_class_init (SysprofChartLayerClass *klass) { @@ -115,6 +129,12 @@ sysprof_chart_layer_class_init (SysprofChartLayerClass *klass) object_class->set_property = sysprof_chart_layer_set_property; widget_class->css_changed = sysprof_chart_layer_css_changed; + widget_class->root = sysprof_chart_layer_root; + + properties[PROP_CHART] = + g_param_spec_object ("chart", NULL, NULL, + SYSPROF_TYPE_CHART, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); properties[PROP_TITLE] = g_param_spec_string ("title", NULL, NULL, diff --git a/src/sysprof/sysprof-chart-layer.h b/src/sysprof/sysprof-chart-layer.h index d7d10215..0eb4427f 100644 --- a/src/sysprof/sysprof-chart-layer.h +++ b/src/sysprof/sysprof-chart-layer.h @@ -41,9 +41,6 @@ struct _SysprofChartLayerClass GtkSnapshot *snapshot, double x, double y); - - /*< private >*/ - gpointer _reserved[16]; }; const char *sysprof_chart_layer_get_title (SysprofChartLayer *self); diff --git a/src/sysprof/sysprof-chart.c b/src/sysprof/sysprof-chart.c index 87eee44b..ea2ba09d 100644 --- a/src/sysprof/sysprof-chart.c +++ b/src/sysprof/sysprof-chart.c @@ -22,12 +22,18 @@ #include "sysprof-css-private.h" #include "sysprof-chart.h" +#include "sysprof-chart-layer-factory-private.h" +#include "sysprof-chart-layer-item.h" +#include "sysprof-chart-layer-item-widget.h" typedef struct { SysprofSession *session; char *title; + SysprofChartLayerFactory *factory; + GListModel *model; + double motion_x; double motion_y; @@ -36,6 +42,8 @@ typedef struct enum { PROP_0, + PROP_FACTORY, + PROP_MODEL, PROP_SESSION, PROP_TITLE, N_PROPS @@ -209,6 +217,8 @@ sysprof_chart_dispose (GObject *object) SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); GtkWidget *child; + sysprof_chart_set_model (self, NULL); + while ((child = gtk_widget_get_first_child (GTK_WIDGET (self)))) gtk_widget_unparent (child); @@ -225,9 +235,18 @@ sysprof_chart_get_property (GObject *object, GParamSpec *pspec) { SysprofChart *self = SYSPROF_CHART (object); + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); switch (prop_id) { + case PROP_FACTORY: + g_value_set_object (value, priv->factory); + break; + + case PROP_MODEL: + g_value_set_object (value, sysprof_chart_get_model (self)); + break; + case PROP_SESSION: g_value_set_object (value, sysprof_chart_get_session (self)); break; @@ -248,9 +267,18 @@ sysprof_chart_set_property (GObject *object, GParamSpec *pspec) { SysprofChart *self = SYSPROF_CHART (object); + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); switch (prop_id) { + case PROP_FACTORY: + priv->factory = g_value_dup_object (value); + break; + + case PROP_MODEL: + sysprof_chart_set_model (self, g_value_get_object (value)); + break; + case PROP_SESSION: sysprof_chart_set_session (self, g_value_get_object (value)); break; @@ -278,6 +306,16 @@ sysprof_chart_class_init (SysprofChartClass *klass) widget_class->size_allocate = sysprof_chart_size_allocate; widget_class->snapshot = sysprof_chart_snapshot; + properties [PROP_MODEL] = + g_param_spec_object ("model", NULL, NULL, + G_TYPE_LIST_MODEL, + (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + + properties[PROP_FACTORY] = + g_param_spec_object ("factory", NULL, NULL, + SYSPROF_TYPE_CHART_LAYER_FACTORY, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + properties [PROP_SESSION] = g_param_spec_object ("session", NULL, NULL, G_TYPE_OBJECT, @@ -303,6 +341,10 @@ sysprof_chart_class_init (SysprofChartClass *klass) G_TYPE_OBJECT); gtk_widget_class_set_css_name (widget_class, "chart"); + + g_type_ensure (SYSPROF_TYPE_CHART_LAYER_FACTORY); + g_type_ensure (SYSPROF_TYPE_CHART_LAYER_ITEM); + g_type_ensure (SYSPROF_TYPE_CHART_LAYER_ITEM_WIDGET); } static void @@ -425,3 +467,111 @@ sysprof_chart_remove_layer (SysprofChart *self, gtk_widget_unparent (GTK_WIDGET (layer)); } + + +GListModel * +sysprof_chart_get_model (SysprofChart *self) +{ + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_return_val_if_fail (SYSPROF_IS_CHART (self), NULL); + + return priv->model; +} + +static void +sysprof_chart_items_changed_cb (SysprofChart *self, + guint position, + guint removed, + guint added, + GListModel *model) +{ + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_assert (SYSPROF_IS_CHART (self)); + g_assert (G_IS_LIST_MODEL (model)); + + if (removed > 0) + { + GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self)); + + for (guint i = 1; i <= position; i++) + child = gtk_widget_get_next_sibling (child); + + for (guint i = 0; i < removed; i++) + { + GtkWidget *target = child; + child = gtk_widget_get_next_sibling (child); + gtk_widget_unparent (target); + } + } + + if (added > 0) + { + GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self)); + + for (guint i = 1; i < position; i++) + child = gtk_widget_get_next_sibling (child); + + for (guint i = 0; i < added; i++) + { + g_autoptr(GObject) item = g_list_model_get_item (model, position + i); + g_autoptr(SysprofChartLayerItem) layer_item = NULL; + SysprofChartLayerItemWidget *widget; + + layer_item = g_object_new (SYSPROF_TYPE_CHART_LAYER_ITEM, + "item", item, + NULL); + if (priv->factory) + _sysprof_chart_layer_factory_setup (priv->factory, layer_item); + widget = sysprof_chart_layer_item_widget_new (layer_item); + gtk_widget_insert_after (GTK_WIDGET (widget), GTK_WIDGET (self), child); + child = GTK_WIDGET (widget); + } + } +} + +void +sysprof_chart_set_model (SysprofChart *self, + GListModel *model) +{ + SysprofChartPrivate *priv = sysprof_chart_get_instance_private (self); + + g_return_if_fail (SYSPROF_IS_CHART (self)); + + if (priv->model == model) + return; + + if (model) + g_object_ref (model); + + if (priv->model) + { + GtkWidget *child; + + g_signal_handlers_disconnect_by_func (priv->model, + G_CALLBACK (sysprof_chart_items_changed_cb), + self); + + while ((child = gtk_widget_get_first_child (GTK_WIDGET (self)))) + gtk_widget_unparent (child); + + g_clear_object (&priv->model); + } + + priv->model = model; + + if (model) + { + guint n_items = g_list_model_get_n_items (model); + g_signal_connect_object (priv->model, + "items-changed", + G_CALLBACK (sysprof_chart_items_changed_cb), + self, + G_CONNECT_SWAPPED); + if (n_items) + sysprof_chart_items_changed_cb (self, 0, 0, n_items, model); + } + + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MODEL]); +} diff --git a/src/sysprof/sysprof-chart.h b/src/sysprof/sysprof-chart.h index 808bc4d0..33dc1f18 100644 --- a/src/sysprof/sysprof-chart.h +++ b/src/sysprof/sysprof-chart.h @@ -40,9 +40,6 @@ struct _SysprofChartClass gboolean (*activate_layer_item) (SysprofChart *self, SysprofChartLayer *layer, gpointer item); - - /*< private >*/ - gpointer _reserved[16]; }; GtkWidget *sysprof_chart_new (void); @@ -56,5 +53,8 @@ void sysprof_chart_add_layer (SysprofChart *self, SysprofChartLayer *layer); void sysprof_chart_remove_layer (SysprofChart *self, SysprofChartLayer *layer); +GListModel *sysprof_chart_get_model (SysprofChart *self); +void sysprof_chart_set_model (SysprofChart *self, + GListModel *model); G_END_DECLS