From 1612707d21fe6932b335349601dc9a23ba63ed85 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Wed, 26 Mar 2025 13:18:43 -0300 Subject: [PATCH] sysprof: Add filters popover This allows visualizing currently applied filters, and remove individual and all filters applied. Currently the only filter that can show up is the mark filter, but in the future new filters may be applied. --- po/POTFILES.in | 1 + .../actions/funnel-outline-symbolic.svg | 2 + src/sysprof/meson.build | 1 + src/sysprof/style.css | 14 ++ src/sysprof/sysprof-session-filters-widget.c | 225 ++++++++++++++++++ src/sysprof/sysprof-session-filters-widget.h | 32 +++ src/sysprof/sysprof-session-filters-widget.ui | 112 +++++++++ src/sysprof/sysprof-window.c | 10 + src/sysprof/sysprof-window.ui | 30 +++ src/sysprof/sysprof.gresource.xml | 2 + 10 files changed, 429 insertions(+) create mode 100644 src/sysprof/icons/scalable/actions/funnel-outline-symbolic.svg create mode 100644 src/sysprof/sysprof-session-filters-widget.c create mode 100644 src/sysprof/sysprof-session-filters-widget.h create mode 100644 src/sysprof/sysprof-session-filters-widget.ui diff --git a/po/POTFILES.in b/po/POTFILES.in index 0cb3fa09..fdae6bda 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -46,6 +46,7 @@ src/sysprof/sysprof-processes-section.ui src/sysprof/sysprof-recording-pad.c src/sysprof/sysprof-recording-pad.ui src/sysprof/sysprof-samples-section.ui +src/sysprof/sysprof-session-filters-widget.ui src/sysprof/sysprof-sidebar.ui src/sysprof/sysprof-storage-section.ui src/sysprof/sysprof-traceables-utility.ui diff --git a/src/sysprof/icons/scalable/actions/funnel-outline-symbolic.svg b/src/sysprof/icons/scalable/actions/funnel-outline-symbolic.svg new file mode 100644 index 00000000..10b32288 --- /dev/null +++ b/src/sysprof/icons/scalable/actions/funnel-outline-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/src/sysprof/meson.build b/src/sysprof/meson.build index 6a7ccf77..038f58f9 100644 --- a/src/sysprof/meson.build +++ b/src/sysprof/meson.build @@ -52,6 +52,7 @@ sysprof_sources = [ 'sysprof-scheduler.c', 'sysprof-section.c', 'sysprof-series.c', + 'sysprof-session-filters-widget.c', 'sysprof-session-model-item.c', 'sysprof-session-model.c', 'sysprof-session.c', diff --git a/src/sysprof/style.css b/src/sysprof/style.css index d5d7b5e2..750ffdf0 100644 --- a/src/sysprof/style.css +++ b/src/sysprof/style.css @@ -96,3 +96,17 @@ popover.tasks listview row { popover.tasks listview row label.heading { padding-bottom: 3px; } + +sessionfilters row { + padding: 3px 0; +} + +sessionfilters row:hover { + background: none; +} + +sessionfilters row button { + min-width: 0; + min-height: 0; + padding: 3px; +} diff --git a/src/sysprof/sysprof-session-filters-widget.c b/src/sysprof/sysprof-session-filters-widget.c new file mode 100644 index 00000000..96b2cb2e --- /dev/null +++ b/src/sysprof/sysprof-session-filters-widget.c @@ -0,0 +1,225 @@ +/* + * sysprof-session-filters-widget.c + * + * Copyright 2025 Georges Basile Stavracas Neto + * + * 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 "sysprof-mark-filter.h" +#include "sysprof-session-filters-widget.h" +#include "sysprof-session.h" + +struct _SysprofSessionFiltersWidget +{ + GtkWidget parent_instance; + + SysprofSession *session; +}; + +G_DEFINE_FINAL_TYPE (SysprofSessionFiltersWidget, sysprof_session_filters_widget, GTK_TYPE_WIDGET) + +enum { + PROP_0, + PROP_SESSION, + N_PROPS, +}; + +static GParamSpec *properties [N_PROPS]; + +static void +sysprof_session_filters_widget_remove_filter (GtkWidget *widget, + const char *action_name, + GVariant *param) +{ + SysprofSessionFiltersWidget *self = (SysprofSessionFiltersWidget *) widget; + GtkFilter *filter; + unsigned int position; + + g_assert (SYSPROF_IS_SESSION_FILTERS_WIDGET (widget)); + g_assert (SYSPROF_IS_SESSION (self->session)); + + filter = sysprof_session_get_filter (self->session); + g_assert (GTK_IS_MULTI_FILTER (filter)); + + position = g_variant_get_uint32 (param); + + gtk_multi_filter_remove (GTK_MULTI_FILTER (filter), position); +} + +static GVariant * +item_to_action_target (gpointer unused, + GtkFilter *filter, + unsigned int position) +{ + if (filter) + return g_variant_new_uint32 (position); + + return NULL; +} + +static char * +filter_to_icon_name (gpointer unused, + GtkFilter *filter) +{ + if (!filter) + return g_strdup (""); + + if (SYSPROF_IS_MARK_FILTER (filter)) + return g_strdup ("mark-chart-symbolic"); + + return g_strdup ("funnel-outline-symbolic"); +} + +static char * +filter_to_string (gpointer unused, + GtkFilter *filter) +{ + if (!filter) + return g_strdup (""); + + if (SYSPROF_IS_MARK_FILTER (filter)) + { + SysprofMarkFilter *mark_filter = (SysprofMarkFilter *) filter; + SysprofMarkCatalog *catalog = sysprof_mark_filter_get_catalog (mark_filter); + + return g_strdup_printf ("%s / %s", + sysprof_mark_catalog_get_group (catalog), + sysprof_mark_catalog_get_name (catalog)); + } + + return g_strdup (G_OBJECT_TYPE_NAME (filter)); +} + +static void +clear_all_filters (SysprofSessionFiltersWidget *self, + GtkButton *button) +{ + GtkFilter *filter; + + g_assert (SYSPROF_IS_SESSION_FILTERS_WIDGET (self)); + g_assert (SYSPROF_IS_SESSION (self->session)); + g_assert (GTK_IS_BUTTON (button)); + + filter = sysprof_session_get_filter (self->session); + g_assert (GTK_IS_MULTI_FILTER (filter)); + + while (g_list_model_get_n_items (G_LIST_MODEL (filter)) > 0) + gtk_multi_filter_remove (GTK_MULTI_FILTER (filter), 0); +} + +static void +sysprof_session_filters_widget_set_session (SysprofSessionFiltersWidget *self, + SysprofSession *session) +{ + if (g_set_object (&self->session, session)) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SESSION]); +} + +static void +sysprof_session_filters_widget_finalize (GObject *object) +{ + SysprofSessionFiltersWidget *self = (SysprofSessionFiltersWidget *)object; + + g_clear_object (&self->session); + + G_OBJECT_CLASS (sysprof_session_filters_widget_parent_class)->finalize (object); +} + +static void +sysprof_session_filters_widget_dispose (GObject *object) +{ + SysprofSessionFiltersWidget *self = (SysprofSessionFiltersWidget *)object; + + gtk_widget_dispose_template (GTK_WIDGET (self), SYSPROF_TYPE_SESSION_FILTERS_WIDGET); + + G_OBJECT_CLASS (sysprof_session_filters_widget_parent_class)->dispose (object); +} + +static void +sysprof_session_filters_widget_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofSessionFiltersWidget *self = SYSPROF_SESSION_FILTERS_WIDGET (object); + + switch (prop_id) + { + case PROP_SESSION: + g_value_set_object (value, self->session); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_session_filters_widget_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofSessionFiltersWidget *self = SYSPROF_SESSION_FILTERS_WIDGET (object); + + switch (prop_id) + { + case PROP_SESSION: + sysprof_session_filters_widget_set_session (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_session_filters_widget_class_init (SysprofSessionFiltersWidgetClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = sysprof_session_filters_widget_finalize; + object_class->dispose = sysprof_session_filters_widget_dispose; + object_class->get_property = sysprof_session_filters_widget_get_property; + object_class->set_property = sysprof_session_filters_widget_set_property; + + properties[PROP_SESSION] = + g_param_spec_object ("session", NULL, NULL, + SYSPROF_TYPE_SESSION, + (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/sysprof-session-filters-widget.ui"); + + gtk_widget_class_set_css_name (widget_class, "sessionfilters"); + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); + + gtk_widget_class_bind_template_callback (widget_class, clear_all_filters); + gtk_widget_class_bind_template_callback (widget_class, filter_to_icon_name); + gtk_widget_class_bind_template_callback (widget_class, filter_to_string); + gtk_widget_class_bind_template_callback (widget_class, item_to_action_target); + + gtk_widget_class_install_action (widget_class, "sessionfilters.remove-filter", "u", sysprof_session_filters_widget_remove_filter); +} + +static void +sysprof_session_filters_widget_init (SysprofSessionFiltersWidget *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} diff --git a/src/sysprof/sysprof-session-filters-widget.h b/src/sysprof/sysprof-session-filters-widget.h new file mode 100644 index 00000000..22a2c892 --- /dev/null +++ b/src/sysprof/sysprof-session-filters-widget.h @@ -0,0 +1,32 @@ +/* + * sysprof-session-filters-widget.c + * + * Copyright 2025 Georges Basile Stavracas Neto + * + * 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_SESSION_FILTERS_WIDGET (sysprof_session_filters_widget_get_type()) + +G_DECLARE_FINAL_TYPE (SysprofSessionFiltersWidget, sysprof_session_filters_widget, SYSPROF, SESSION_FILTERS_WIDGET, GtkWidget) + +G_END_DECLS diff --git a/src/sysprof/sysprof-session-filters-widget.ui b/src/sysprof/sysprof-session-filters-widget.ui new file mode 100644 index 00000000..ebad1025 --- /dev/null +++ b/src/sysprof/sysprof-session-filters-widget.ui @@ -0,0 +1,112 @@ + + + + diff --git a/src/sysprof/sysprof-window.c b/src/sysprof/sysprof-window.c index e81e264b..cc351836 100644 --- a/src/sysprof/sysprof-window.c +++ b/src/sysprof/sysprof-window.c @@ -41,6 +41,7 @@ #include "sysprof-pair.h" #include "sysprof-processes-section.h" #include "sysprof-samples-section.h" +#include "sysprof-session-filters-widget.h" #include "sysprof-sidebar.h" #include "sysprof-storage-section.h" #include "sysprof-task-row.h" @@ -328,6 +329,13 @@ main_view_notify_sidebar (SysprofWindow *self, gtk_widget_set_sensitive (GTK_WIDGET (self->show_right_sidebar), sidebar != NULL); } +static gboolean +n_filters_to_button_visibility (SysprofWindow *self, + unsigned int n_filters) +{ + return n_filters > 0; +} + static void sysprof_window_session_seek_backward (GtkWidget *widget, const char *action_name, @@ -617,6 +625,7 @@ sysprof_window_class_init (SysprofWindowClass *klass) gtk_widget_class_bind_template_child (widget_class, SysprofWindow, stack_title); gtk_widget_class_bind_template_callback (widget_class, main_view_notify_sidebar); + gtk_widget_class_bind_template_callback (widget_class, n_filters_to_button_visibility); gtk_widget_class_install_action (widget_class, "win.open-capture", NULL, sysprof_window_open_capture_action); gtk_widget_class_install_action (widget_class, "win.record-capture", NULL, sysprof_window_record_capture_action); @@ -649,6 +658,7 @@ sysprof_window_class_init (SysprofWindowClass *klass) g_type_ensure (SYSPROF_TYPE_NETWORK_SECTION); g_type_ensure (SYSPROF_TYPE_PROCESSES_SECTION); g_type_ensure (SYSPROF_TYPE_SAMPLES_SECTION); + g_type_ensure (SYSPROF_TYPE_SESSION_FILTERS_WIDGET); g_type_ensure (SYSPROF_TYPE_STORAGE_SECTION); g_type_ensure (SYSPROF_TYPE_SESSION); g_type_ensure (SYSPROF_TYPE_SYMBOL); diff --git a/src/sysprof/sysprof-window.ui b/src/sysprof/sysprof-window.ui index f4e1e7cb..c18b4a47 100644 --- a/src/sysprof/sysprof-window.ui +++ b/src/sysprof/sysprof-window.ui @@ -126,6 +126,36 @@ Toggle Left Panel + + + false + funnel-outline-symbolic + View Filters + + + + + + + SysprofWindow + + + + + + + + + + SysprofWindow + + + + + + 6 diff --git a/src/sysprof/sysprof.gresource.xml b/src/sysprof/sysprof.gresource.xml index 3903b5a5..eb5d9307 100644 --- a/src/sysprof/sysprof.gresource.xml +++ b/src/sysprof/sysprof.gresource.xml @@ -8,6 +8,7 @@ icons/scalable/actions/empty-symbolic.svg icons/scalable/actions/energy-symbolic.svg icons/scalable/actions/flamegraph-symbolic.svg + icons/scalable/actions/funnel-outline-symbolic.svg icons/scalable/actions/graphics-symbolic.svg icons/scalable/actions/mark-chart-symbolic.svg icons/scalable/actions/mark-table-symbolic.svg @@ -50,6 +51,7 @@ sysprof-processes-section.ui sysprof-recording-pad.ui sysprof-samples-section.ui + sysprof-session-filters-widget.ui sysprof-sidebar.ui sysprof-storage-section.ui sysprof-task-row.ui