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.
This commit is contained in:
Georges Basile Stavracas Neto
2025-03-26 13:18:43 -03:00
parent d80188f019
commit 1612707d21
10 changed files with 429 additions and 0 deletions

View File

@ -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

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><g fill="#222222"><path d="m 1.042969 0 c -0.8125 0 -1.285157 0.917969 -0.8125 1.582031 l 4.769531 6.738281 v 6.636719 c 0 0.742188 0.78125 1.226563 1.449219 0.894531 l 4 -2 c 0.335937 -0.171874 0.550781 -0.515624 0.550781 -0.894531 v -4.636719 l 4.8125 -6.738281 c 0.476562 -0.664062 0 -1.582031 -0.8125 -1.582031 z m 1.902343 2 h 10.109376 l -3.867188 5.417969 c -0.121094 0.167969 -0.1875 0.375 -0.1875 0.582031 v 4.339844 l -2 1 v -5.339844 c 0 -0.207031 -0.066406 -0.414062 -0.1875 -0.582031 z m 0 0"/><path d="m 3.859375 5 l 2.140625 3 v 7 l 4 -2 v -5 l 2.144531 -3 z m 0 0" fill-opacity="0.34902"/></g></svg>

After

Width:  |  Height:  |  Size: 742 B

View File

@ -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',

View File

@ -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;
}

View File

@ -0,0 +1,225 @@
/*
* sysprof-session-filters-widget.c
*
* Copyright 2025 Georges Basile Stavracas Neto <feaneron@igalia.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
*/
#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));
}

View File

@ -0,0 +1,32 @@
/*
* sysprof-session-filters-widget.c
*
* Copyright 2025 Georges Basile Stavracas Neto <feaneron@igalia.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
*/
#pragma once
#include <gtk/gtk.h>
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

View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SysprofSessionFiltersWidget" parent="GtkWidget">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="max-content-height">400</property>
<property name="propagate-natural-height">true</property>
<child>
<object class="GtkListView">
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="margin-top">6</property>
<property name="model">
<object class="GtkNoSelection">
<binding name="model">
<lookup name="filter">
<lookup name="session">SysprofSessionFiltersWidget</lookup>
</lookup>
</binding>
</object>
</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="activatable">false</property>
<property name="child">
<object class="GtkBox">
<child>
<object class="GtkImage">
<property name="pixel-size">12</property>
<binding name="icon-name">
<closure type="gchararray" function="filter_to_icon_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="hexpand">true</property>
<binding name="label">
<closure type="gchararray" function="filter_to_string">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">window-close-symbolic</property>
<property name="action-name">sessionfilters.remove-filter</property>
<binding name="action-target">
<closure type="GVariant" function="item_to_action_target">
<lookup name="item">GtkListItem</lookup>
<lookup name="position">GtkListItem</lookup>
</closure>
</binding>
<style>
<class name="flat" />
<class name="circular" />
</style>
</object>
</child>
</object>
</property>
</template>
</interface>
]]>
</property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator" />
</child>
<child>
<object class="GtkButton">
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="margin-bottom">6</property>
<property name="label" translatable="yes">Clear All Filters</property>
<signal name="clicked" handler="clear_all_filters" swapped="yes" />
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@ -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);

View File

@ -126,6 +126,36 @@
<property name="tooltip-text" translatable="yes">Toggle Left Panel</property>
</object>
</child>
<child type="start">
<object class="GtkMenuButton">
<property name="visible">false</property>
<property name="icon-name">funnel-outline-symbolic</property>
<property name="tooltip-text" translatable="yes">View Filters</property>
<property name="popover">
<object class="GtkPopover">
<style>
<class name="menu" />
</style>
<property name="child">
<object class="SysprofSessionFiltersWidget">
<binding name="session">
<lookup name="session">SysprofWindow</lookup>
</binding>
</object>
</property>
</object>
</property>
<binding name="visible">
<closure type="gboolean" function="n_filters_to_button_visibility">
<lookup name="n-items" type="GtkMultiFilter">
<lookup name="filter" type="SysprofSession">
<lookup name="session">SysprofWindow</lookup>
</lookup>
</lookup>
</closure>
</binding>
</object>
</child>
<child type="start">
<object class="GtkBox">
<property name="margin-start">6</property>

View File

@ -8,6 +8,7 @@
<file preprocess="xml-stripblanks">icons/scalable/actions/empty-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/energy-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/flamegraph-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/funnel-outline-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/graphics-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/mark-chart-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/mark-table-symbolic.svg</file>
@ -50,6 +51,7 @@
<file preprocess="xml-stripblanks">sysprof-processes-section.ui</file>
<file preprocess="xml-stripblanks">sysprof-recording-pad.ui</file>
<file preprocess="xml-stripblanks">sysprof-samples-section.ui</file>
<file preprocess="xml-stripblanks">sysprof-session-filters-widget.ui</file>
<file preprocess="xml-stripblanks">sysprof-sidebar.ui</file>
<file preprocess="xml-stripblanks">sysprof-storage-section.ui</file>
<file preprocess="xml-stripblanks">sysprof-task-row.ui</file>