From f1ce6229182005afe07896381a884eacda229b5c Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Thu, 10 Oct 2024 17:02:06 -0700 Subject: [PATCH 04/18] sysprof: add SysprofDocumentTask abstraction This provides a task abstraction to SysprofDocumentLoader so that we can elevate information about tasks to the user interface. It also moves the spinner to a menu button w/ popover to display those tasks. --- src/libsysprof/meson.build | 2 + .../sysprof-document-loader-private.h | 34 ++ src/libsysprof/sysprof-document-loader.c | 129 ++++++- src/libsysprof/sysprof-document-loader.h | 2 + .../sysprof-document-task-private.h | 53 +++ src/libsysprof/sysprof-document-task.c | 327 ++++++++++++++++++ src/libsysprof/sysprof-document-task.h | 46 +++ src/libsysprof/sysprof.h | 1 + src/sysprof/meson.build | 1 + src/sysprof/style.css | 9 + src/sysprof/sysprof-task-row.c | 139 ++++++++ src/sysprof/sysprof-task-row.h | 32 ++ src/sysprof/sysprof-task-row.ui | 71 ++++ src/sysprof/sysprof-window.c | 36 +- src/sysprof/sysprof-window.ui | 75 +++- src/sysprof/sysprof.gresource.xml | 1 + 16 files changed, 937 insertions(+), 21 deletions(-) create mode 100644 src/libsysprof/sysprof-document-loader-private.h create mode 100644 src/libsysprof/sysprof-document-task-private.h create mode 100644 src/libsysprof/sysprof-document-task.c create mode 100644 src/libsysprof/sysprof-document-task.h create mode 100644 src/sysprof/sysprof-task-row.c create mode 100644 src/sysprof/sysprof-task-row.h create mode 100644 src/sysprof/sysprof-task-row.ui diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build index fd53ee11..697e9665 100644 --- a/src/libsysprof/meson.build +++ b/src/libsysprof/meson.build @@ -32,6 +32,7 @@ libsysprof_public_sources = [ 'sysprof-document-overlay.c', 'sysprof-document-process.c', 'sysprof-document-sample.c', + 'sysprof-document-task.c', 'sysprof-document-traceable.c', 'sysprof-document.c', 'sysprof-elf-symbolizer.c', @@ -96,6 +97,7 @@ libsysprof_public_headers = [ 'sysprof-document-overlay.h', 'sysprof-document-process.h', 'sysprof-document-sample.h', + 'sysprof-document-task.h', 'sysprof-document-traceable.h', 'sysprof-document.h', 'sysprof-elf-symbolizer.h', diff --git a/src/libsysprof/sysprof-document-loader-private.h b/src/libsysprof/sysprof-document-loader-private.h new file mode 100644 index 00000000..f7982489 --- /dev/null +++ b/src/libsysprof/sysprof-document-loader-private.h @@ -0,0 +1,34 @@ +/* + * sysprof-document-loader-private.h + * + * Copyright 2024 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-document-loader.h" +#include "sysprof-document-task.h" + +G_BEGIN_DECLS + +void _sysprof_document_loader_add_task (SysprofDocumentLoader *self, + SysprofDocumentTask *task); +void _sysprof_document_loader_remove_task (SysprofDocumentLoader *self, + SysprofDocumentTask *task); + +G_END_DECLS diff --git a/src/libsysprof/sysprof-document-loader.c b/src/libsysprof/sysprof-document-loader.c index 6622f325..3cd408c4 100644 --- a/src/libsysprof/sysprof-document-loader.c +++ b/src/libsysprof/sysprof-document-loader.c @@ -27,18 +27,21 @@ #include #include "sysprof-bundled-symbolizer.h" +#include "sysprof-debuginfod-symbolizer.h" #include "sysprof-document-bitset-index-private.h" -#include "sysprof-document-loader.h" +#include "sysprof-document-loader-private.h" #include "sysprof-document-private.h" #include "sysprof-elf-symbolizer.h" #include "sysprof-jitmap-symbolizer.h" #include "sysprof-kallsyms-symbolizer.h" #include "sysprof-multi-symbolizer.h" +#include "sysprof-symbolizer-private.h" struct _SysprofDocumentLoader { GObject parent_instance; GMutex mutex; + GListStore *tasks; SysprofSymbolizer *symbolizer; char *filename; char *message; @@ -53,6 +56,7 @@ enum { PROP_FRACTION, PROP_MESSAGE, PROP_SYMBOLIZER, + PROP_TASKS, N_PROPS }; @@ -192,6 +196,8 @@ static void set_default_symbolizer (SysprofDocumentLoader *self) { g_autoptr(SysprofMultiSymbolizer) multi = NULL; + g_autoptr(SysprofSymbolizer) debuginfod = NULL; + g_autoptr(GError) error = NULL; g_assert (SYSPROF_IS_DOCUMENT_LOADER (self)); @@ -202,9 +208,25 @@ set_default_symbolizer (SysprofDocumentLoader *self) sysprof_multi_symbolizer_take (multi, sysprof_kallsyms_symbolizer_new ()); sysprof_multi_symbolizer_take (multi, sysprof_elf_symbolizer_new ()); sysprof_multi_symbolizer_take (multi, sysprof_jitmap_symbolizer_new ()); + + if (!(debuginfod = sysprof_debuginfod_symbolizer_new (&error))) + g_warning ("Failed to create debuginfod symbolizer: %s", error->message); + else + sysprof_multi_symbolizer_take (multi, g_steal_pointer (&debuginfod)); + self->symbolizer = SYSPROF_SYMBOLIZER (g_steal_pointer (&multi)); } +static void +sysprof_document_loader_dispose (GObject *object) +{ + SysprofDocumentLoader *self = (SysprofDocumentLoader *)object; + + g_list_store_remove_all (self->tasks); + + G_OBJECT_CLASS (sysprof_document_loader_parent_class)->dispose (object); +} + static void sysprof_document_loader_finalize (GObject *object) { @@ -212,6 +234,7 @@ sysprof_document_loader_finalize (GObject *object) g_clear_handle_id (&self->notify_source, g_source_remove); g_clear_object (&self->symbolizer); + g_clear_object (&self->tasks); g_clear_pointer (&self->filename, g_free); g_clear_pointer (&self->message, g_free); g_clear_fd (&self->fd, NULL); @@ -242,6 +265,10 @@ sysprof_document_loader_get_property (GObject *object, g_value_set_object (value, sysprof_document_loader_get_symbolizer (self)); break; + case PROP_TASKS: + g_value_take_object (value, sysprof_document_loader_list_tasks (self)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -271,6 +298,7 @@ sysprof_document_loader_class_init (SysprofDocumentLoaderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->dispose = sysprof_document_loader_dispose; object_class->finalize = sysprof_document_loader_finalize; object_class->get_property = sysprof_document_loader_get_property; object_class->set_property = sysprof_document_loader_set_property; @@ -290,6 +318,11 @@ sysprof_document_loader_class_init (SysprofDocumentLoaderClass *klass) SYSPROF_TYPE_SYMBOLIZER, (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + properties[PROP_TASKS] = + g_param_spec_object ("tasks", NULL, NULL, + G_TYPE_LIST_MODEL, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_properties (object_class, N_PROPS, properties); g_type_ensure (SYSPROF_TYPE_DOCUMENT); @@ -302,6 +335,7 @@ sysprof_document_loader_init (SysprofDocumentLoader *self) g_mutex_init (&self->mutex); self->fd = -1; + self->tasks = g_list_store_new (SYSPROF_TYPE_DOCUMENT_TASK); set_default_symbolizer (self); } @@ -546,6 +580,8 @@ sysprof_document_loader_load_async (SysprofDocumentLoader *self, set_progress (0., _("Loading document"), self); + _sysprof_symbolizer_setup (self->symbolizer, self); + if (self->fd != -1) mapped_file_new_from_fd_async (self->fd, cancellable, @@ -657,3 +693,94 @@ sysprof_document_loader_load (SysprofDocumentLoader *self, return state.document; } + +typedef struct _TaskOp +{ + SysprofDocumentLoader *loader; + SysprofDocumentTask *task; + guint remove : 1; +} TaskOp; + +static void +_g_list_store_remove (GListStore *store, + gpointer instance) +{ + GListModel *model = G_LIST_MODEL (store); + guint n_items = g_list_model_get_n_items (model); + + for (guint i = 0; i < n_items; i++) + { + g_autoptr(GObject) element = g_list_model_get_item (model, i); + + if (element == instance) + { + g_list_store_remove (store, i); + return; + } + } +} + +static gboolean +task_op_run (gpointer data) +{ + TaskOp *op = data; + + if (op->remove) + _g_list_store_remove (op->loader->tasks, op->task); + else + g_list_store_append (op->loader->tasks, op->task); + + g_clear_object (&op->loader); + g_clear_object (&op->task); + g_free (op); + + return G_SOURCE_REMOVE; +} + +static TaskOp * +task_op_new (SysprofDocumentLoader *loader, + SysprofDocumentTask *task, + gboolean remove) +{ + TaskOp op = { + g_object_ref (loader), + g_object_ref (task), + !!remove + }; + + return g_memdup2 (&op, sizeof op); +} + +void +_sysprof_document_loader_add_task (SysprofDocumentLoader *self, + SysprofDocumentTask *task) +{ + g_return_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self)); + g_return_if_fail (SYSPROF_IS_DOCUMENT_TASK (task)); + + g_idle_add (task_op_run, task_op_new (self, task, FALSE)); +} + +void +_sysprof_document_loader_remove_task (SysprofDocumentLoader *self, + SysprofDocumentTask *task) +{ + g_return_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self)); + g_return_if_fail (SYSPROF_IS_DOCUMENT_TASK (task)); + + g_idle_add (task_op_run, task_op_new (self, task, TRUE)); +} + +/** + * sysprof_document_loader_list_tasks: + * @self: a #SysprofDocumentLoader + * + * Returns: (transfer full): a #GListModel of #SysprofDocumentTask. + */ +GListModel * +sysprof_document_loader_list_tasks (SysprofDocumentLoader *self) +{ + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOADER (self), NULL); + + return g_object_ref (G_LIST_MODEL (self->tasks)); +} diff --git a/src/libsysprof/sysprof-document-loader.h b/src/libsysprof/sysprof-document-loader.h index 289dae30..1a1ea7da 100644 --- a/src/libsysprof/sysprof-document-loader.h +++ b/src/libsysprof/sysprof-document-loader.h @@ -48,6 +48,8 @@ SYSPROF_AVAILABLE_IN_ALL double sysprof_document_loader_get_fraction (SysprofDocumentLoader *self); SYSPROF_AVAILABLE_IN_ALL const char *sysprof_document_loader_get_message (SysprofDocumentLoader *self); +SYSPROF_AVAILABLE_IN_ALL +GListModel *sysprof_document_loader_list_tasks (SysprofDocumentLoader *self); SYSPROF_AVAILABLE_IN_ALL SysprofDocument *sysprof_document_loader_load (SysprofDocumentLoader *self, GCancellable *cancellable, diff --git a/src/libsysprof/sysprof-document-task-private.h b/src/libsysprof/sysprof-document-task-private.h new file mode 100644 index 00000000..3590b234 --- /dev/null +++ b/src/libsysprof/sysprof-document-task-private.h @@ -0,0 +1,53 @@ +/* + * sysprof-document-task-private.h + * + * Copyright 2024 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 "sysprof-document-loader.h" +#include "sysprof-document-task.h" + +G_BEGIN_DECLS + +typedef struct _SysprofDocumentTask SysprofDocumentTaskScope; + +struct _SysprofDocumentTaskClass +{ + GObjectClass parent_class; + + void (*cancel) (SysprofDocumentTask *self); +}; + +GCancellable *_sysprof_document_task_get_cancellable (SysprofDocumentTask *self); +void _sysprof_document_task_set_title (SysprofDocumentTask *self, + const char *title); +void _sysprof_document_task_take_message (SysprofDocumentTask *self, + char *message); +void _sysprof_document_task_set_progress (SysprofDocumentTask *self, + double progress); +SysprofDocumentTaskScope *_sysprof_document_task_register (SysprofDocumentTask *self, + SysprofDocumentLoader *loader); +void _sysprof_document_task_unregister (SysprofDocumentTask *self); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofDocumentTaskScope, _sysprof_document_task_unregister) + +G_END_DECLS diff --git a/src/libsysprof/sysprof-document-task.c b/src/libsysprof/sysprof-document-task.c new file mode 100644 index 00000000..a8bfb30a --- /dev/null +++ b/src/libsysprof/sysprof-document-task.c @@ -0,0 +1,327 @@ +/* + * sysprof-document-task.c + * + * Copyright 2024 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-document-loader-private.h" +#include "sysprof-document-task-private.h" + +typedef struct +{ + GMutex mutex; + char *message; + char *title; + double progress; + GCancellable *cancellable; + guint notify_source; + GWeakRef loader_wr; +} SysprofDocumentTaskPrivate; + +enum { + PROP_0, + PROP_CANCELLED, + PROP_MESSAGE, + PROP_PROGRESS, + PROP_TITLE, + N_PROPS +}; + +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (SysprofDocumentTask, sysprof_document_task, G_TYPE_OBJECT) + +static GParamSpec *properties[N_PROPS]; + +static void +sysprof_document_task_finalize (GObject *object) +{ + SysprofDocumentTask *self = (SysprofDocumentTask *)object; + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_mutex_clear (&priv->mutex); + g_clear_handle_id (&priv->notify_source, g_source_remove); + g_clear_pointer (&priv->message, g_free); + g_clear_pointer (&priv->title, g_free); + g_clear_object (&priv->cancellable); + g_weak_ref_clear (&priv->loader_wr); + + G_OBJECT_CLASS (sysprof_document_task_parent_class)->finalize (object); +} + +static void +sysprof_document_task_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofDocumentTask *self = SYSPROF_DOCUMENT_TASK (object); + + switch (prop_id) + { + case PROP_CANCELLED: + g_value_set_boolean (value, sysprof_document_task_is_cancelled (self)); + break; + + case PROP_MESSAGE: + g_value_take_string (value, sysprof_document_task_dup_message (self)); + break; + + case PROP_PROGRESS: + g_value_set_double (value, sysprof_document_task_get_progress (self)); + break; + + case PROP_TITLE: + g_value_take_string (value, sysprof_document_task_dup_title (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_document_task_class_init (SysprofDocumentTaskClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = sysprof_document_task_finalize; + object_class->get_property = sysprof_document_task_get_property; + + properties[PROP_CANCELLED] = + g_param_spec_boolean ("cancelled", NULL, NULL, + FALSE, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + properties[PROP_MESSAGE] = + g_param_spec_string ("message", NULL, NULL, + NULL, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + properties[PROP_PROGRESS] = + g_param_spec_double ("progress", NULL, NULL, + 0., 1., 0., + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + properties[PROP_TITLE] = + g_param_spec_string ("title", NULL, NULL, + NULL, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_document_task_init (SysprofDocumentTask *self) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_weak_ref_init (&priv->loader_wr, NULL); + + priv->cancellable = g_cancellable_new (); +} + +static gboolean +notify_in_idle_cb (gpointer data) +{ + SysprofDocumentTask *self = data; + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_assert (SYSPROF_IS_DOCUMENT_TASK (self)); + + g_mutex_lock (&priv->mutex); + priv->notify_source = 0; + g_mutex_unlock (&priv->mutex); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CANCELLED]); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MESSAGE]); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PROGRESS]); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TITLE]); + + return G_SOURCE_REMOVE; +} + +static void +notify_in_idle_locked (SysprofDocumentTask *self) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_assert (SYSPROF_IS_DOCUMENT_TASK (self)); + + if (priv->notify_source == 0) + priv->notify_source = g_idle_add_full (G_PRIORITY_LOW, + notify_in_idle_cb, + g_object_ref (self), + g_object_unref); +} + +char * +sysprof_document_task_dup_message (SysprofDocumentTask *self) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + char *ret; + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_TASK (self), NULL); + + g_mutex_lock (&priv->mutex); + ret = g_strdup (priv->message); + g_mutex_unlock (&priv->mutex); + + return ret; +} + +char * +sysprof_document_task_dup_title (SysprofDocumentTask *self) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + char *ret; + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_TASK (self), NULL); + + g_mutex_lock (&priv->mutex); + ret = g_strdup (priv->title); + g_mutex_unlock (&priv->mutex); + + return ret; +} + +void +_sysprof_document_task_take_message (SysprofDocumentTask *self, + char *message) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_return_if_fail (SYSPROF_IS_DOCUMENT_TASK (self)); + + g_mutex_lock (&priv->mutex); + g_free (priv->message); + priv->message = message; + notify_in_idle_locked (self); + g_mutex_unlock (&priv->mutex); +} + +double +sysprof_document_task_get_progress (SysprofDocumentTask *self) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + double ret; + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_TASK (self), 0); + + g_mutex_lock (&priv->mutex); + ret = priv->progress; + g_mutex_unlock (&priv->mutex); + + return ret; +} + +void +_sysprof_document_task_set_progress (SysprofDocumentTask *self, + double progress) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_return_if_fail (SYSPROF_IS_DOCUMENT_TASK (self)); + + progress = CLAMP (progress, 0., 1.); + + g_mutex_lock (&priv->mutex); + priv->progress = progress; + notify_in_idle_locked (self); + g_mutex_unlock (&priv->mutex); +} + +void +_sysprof_document_task_set_title (SysprofDocumentTask *self, + const char *title) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_return_if_fail (SYSPROF_IS_DOCUMENT_TASK (self)); + + g_mutex_lock (&priv->mutex); + if (g_set_str (&priv->title, title)) + notify_in_idle_locked (self); + g_mutex_unlock (&priv->mutex); +} + +gboolean +sysprof_document_task_is_cancelled (SysprofDocumentTask *self) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + gboolean ret; + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_TASK (self), FALSE); + + g_mutex_lock (&priv->mutex); + ret = g_cancellable_is_cancelled (priv->cancellable); + g_mutex_unlock (&priv->mutex); + + return ret; +} + +GCancellable * +_sysprof_document_task_get_cancellable (SysprofDocumentTask *self) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_TASK (self), NULL); + + return priv->cancellable; +} + +SysprofDocumentTaskScope * +_sysprof_document_task_register (SysprofDocumentTask *self, + SysprofDocumentLoader *loader) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_TASK (self), NULL); + g_return_val_if_fail (SYSPROF_IS_DOCUMENT_LOADER (loader), NULL); + + g_weak_ref_set (&priv->loader_wr, loader); + + _sysprof_document_loader_add_task (loader, self); + + return self; +} + +void +_sysprof_document_task_unregister (SysprofDocumentTask *self) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + g_autoptr(SysprofDocumentLoader) loader = NULL; + + g_return_if_fail (SYSPROF_IS_DOCUMENT_TASK (self)); + + if ((loader = g_weak_ref_get (&priv->loader_wr))) + _sysprof_document_loader_remove_task (loader, self); +} + +void +sysprof_document_task_cancel (SysprofDocumentTask *self) +{ + SysprofDocumentTaskPrivate *priv = sysprof_document_task_get_instance_private (self); + + g_return_if_fail (SYSPROF_IS_DOCUMENT_TASK (self)); + + g_cancellable_cancel (priv->cancellable); + + if (SYSPROF_DOCUMENT_TASK_GET_CLASS (self)->cancel) + SYSPROF_DOCUMENT_TASK_GET_CLASS (self)->cancel (self); +} diff --git a/src/libsysprof/sysprof-document-task.h b/src/libsysprof/sysprof-document-task.h new file mode 100644 index 00000000..1f0be928 --- /dev/null +++ b/src/libsysprof/sysprof-document-task.h @@ -0,0 +1,46 @@ +/* + * sysprof-document-task.h + * + * Copyright 2024 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 "sysprof-version-macros.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_DOCUMENT_TASK (sysprof_document_task_get_type()) + +SYSPROF_AVAILABLE_IN_ALL +G_DECLARE_DERIVABLE_TYPE (SysprofDocumentTask, sysprof_document_task, SYSPROF, DOCUMENT_TASK, GObject) + +SYSPROF_AVAILABLE_IN_ALL +double sysprof_document_task_get_progress (SysprofDocumentTask *self); +SYSPROF_AVAILABLE_IN_ALL +char *sysprof_document_task_dup_message (SysprofDocumentTask *self); +SYSPROF_AVAILABLE_IN_ALL +char *sysprof_document_task_dup_title (SysprofDocumentTask *self); +SYSPROF_AVAILABLE_IN_ALL +gboolean sysprof_document_task_is_cancelled (SysprofDocumentTask *self); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_document_task_cancel (SysprofDocumentTask *self); + +G_END_DECLS diff --git a/src/libsysprof/sysprof.h b/src/libsysprof/sysprof.h index 529386c8..c2176619 100644 --- a/src/libsysprof/sysprof.h +++ b/src/libsysprof/sysprof.h @@ -56,6 +56,7 @@ G_BEGIN_DECLS # include "sysprof-document-overlay.h" # include "sysprof-document-process.h" # include "sysprof-document-sample.h" +# include "sysprof-document-task.h" # include "sysprof-document-traceable.h" # include "sysprof-document.h" # include "sysprof-elf-symbolizer.h" diff --git a/src/sysprof/meson.build b/src/sysprof/meson.build index 989bbd11..ca42ead3 100644 --- a/src/sysprof/meson.build +++ b/src/sysprof/meson.build @@ -59,6 +59,7 @@ sysprof_sources = [ 'sysprof-split-layer.c', 'sysprof-storage-section.c', 'sysprof-symbol-label.c', + 'sysprof-task-row.c', 'sysprof-time-filter-model.c', 'sysprof-time-label.c', 'sysprof-time-ruler.c', diff --git a/src/sysprof/style.css b/src/sysprof/style.css index 946ab248..d5d7b5e2 100644 --- a/src/sysprof/style.css +++ b/src/sysprof/style.css @@ -87,3 +87,12 @@ flamegraph { timespanlayer { font-size: 10px; } + +popover.tasks listview row { + background: transparent; + padding: 6px; +} + +popover.tasks listview row label.heading { + padding-bottom: 3px; +} diff --git a/src/sysprof/sysprof-task-row.c b/src/sysprof/sysprof-task-row.c new file mode 100644 index 00000000..a8e51754 --- /dev/null +++ b/src/sysprof/sysprof-task-row.c @@ -0,0 +1,139 @@ +/* + * sysprof-task-row.c + * + * Copyright 2024 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 + +#include "sysprof-task-row.h" + +struct _SysprofTaskRow +{ + GtkWidget parent_instance; + SysprofDocumentTask *task; +}; + +enum { + PROP_0, + PROP_TASK, + N_PROPS +}; + +G_DEFINE_FINAL_TYPE (SysprofTaskRow, sysprof_task_row, GTK_TYPE_WIDGET) + +static GParamSpec *properties[N_PROPS]; + +static void +sysprof_task_row_cancel (GtkWidget *widget, + const char *action, + GVariant *param) +{ + SysprofTaskRow *self = SYSPROF_TASK_ROW (widget); + + if (self->task) + sysprof_document_task_cancel (self->task); +} + +static void +sysprof_task_row_dispose (GObject *object) +{ + SysprofTaskRow *self = (SysprofTaskRow *)object; + GtkWidget *child; + + gtk_widget_dispose_template (GTK_WIDGET (self), SYSPROF_TYPE_TASK_ROW); + + while ((child = gtk_widget_get_first_child (GTK_WIDGET (self)))) + gtk_widget_unparent (child); + + g_clear_object (&self->task); + + G_OBJECT_CLASS (sysprof_task_row_parent_class)->dispose (object); +} + +static void +sysprof_task_row_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofTaskRow *self = SYSPROF_TASK_ROW (object); + + switch (prop_id) + { + case PROP_TASK: + g_value_set_object (value, self->task); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_task_row_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofTaskRow *self = SYSPROF_TASK_ROW (object); + + switch (prop_id) + { + case PROP_TASK: + if (g_set_object (&self->task, g_value_get_object (value))) + g_object_notify_by_pspec (object, pspec); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_task_row_class_init (SysprofTaskRowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->dispose = sysprof_task_row_dispose; + object_class->get_property = sysprof_task_row_get_property; + object_class->set_property = sysprof_task_row_set_property; + + properties[PROP_TASK] = + g_param_spec_object ("task", NULL, NULL, + SYSPROF_TYPE_DOCUMENT_TASK, + (G_PARAM_READWRITE | + G_PARAM_EXPLICIT_NOTIFY | + 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-task-row.ui"); + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); + + gtk_widget_class_install_action (widget_class, "task.cancel", NULL, sysprof_task_row_cancel); +} + +static void +sysprof_task_row_init (SysprofTaskRow *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} diff --git a/src/sysprof/sysprof-task-row.h b/src/sysprof/sysprof-task-row.h new file mode 100644 index 00000000..39bc3606 --- /dev/null +++ b/src/sysprof/sysprof-task-row.h @@ -0,0 +1,32 @@ +/* + * sysprof-task-row.h + * + * Copyright 2024 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 + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_TASK_ROW (sysprof_task_row_get_type()) + +G_DECLARE_FINAL_TYPE (SysprofTaskRow, sysprof_task_row, SYSPROF, TASK_ROW, GtkWidget) + +G_END_DECLS diff --git a/src/sysprof/sysprof-task-row.ui b/src/sysprof/sysprof-task-row.ui new file mode 100644 index 00000000..ac91d79f --- /dev/null +++ b/src/sysprof/sysprof-task-row.ui @@ -0,0 +1,71 @@ + + + + diff --git a/src/sysprof/sysprof-window.c b/src/sysprof/sysprof-window.c index 869d6916..5fd6e9a1 100644 --- a/src/sysprof/sysprof-window.c +++ b/src/sysprof/sysprof-window.c @@ -38,29 +38,32 @@ #include "sysprof-samples-section.h" #include "sysprof-sidebar.h" #include "sysprof-storage-section.h" +#include "sysprof-task-row.h" #include "sysprof-util.h" #include "sysprof-window.h" struct _SysprofWindow { - AdwApplicationWindow parent_instance; + AdwApplicationWindow parent_instance; - SysprofDocument *document; - SysprofSession *session; + SysprofDocument *document; + SysprofDocumentLoader *loader; + SysprofSession *session; - GtkToggleButton *show_right_sidebar; - GtkWidget *left_split_overlay; - GtkWidget *right_split_overlay; - GtkProgressBar *progress_bar; - AdwWindowTitle *stack_title; + GtkToggleButton *show_right_sidebar; + GtkWidget *left_split_overlay; + GtkWidget *right_split_overlay; + GtkProgressBar *progress_bar; + AdwWindowTitle *stack_title; - guint disposed : 1; + guint disposed : 1; }; enum { PROP_0, PROP_DOCUMENT, PROP_IS_LOADED, + PROP_LOADER, PROP_SESSION, N_PROPS }; @@ -513,6 +516,10 @@ sysprof_window_get_property (GObject *object, g_value_set_object (value, sysprof_window_get_document (self)); break; + case PROP_LOADER: + g_value_set_object (value, self->loader); + break; + case PROP_IS_LOADED: g_value_set_boolean (value, !!sysprof_window_get_document (self)); break; @@ -560,6 +567,11 @@ sysprof_window_class_init (SysprofWindowClass *klass) SYSPROF_TYPE_DOCUMENT, (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + properties[PROP_LOADER] = + g_param_spec_object ("loader", NULL, NULL, + SYSPROF_TYPE_DOCUMENT_LOADER, + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + properties [PROP_IS_LOADED] = g_param_spec_boolean ("is-loaded", NULL, NULL, FALSE, @@ -617,6 +629,7 @@ sysprof_window_class_init (SysprofWindowClass *klass) g_type_ensure (SYSPROF_TYPE_SESSION); g_type_ensure (SYSPROF_TYPE_SYMBOL); g_type_ensure (SYSPROF_TYPE_SIDEBAR); + g_type_ensure (SYSPROF_TYPE_TASK_ROW); } static void @@ -711,6 +724,9 @@ sysprof_window_load_cb (GObject *object, g_binding_unbind (g_object_get_data (G_OBJECT (loader), "message-binding")); g_object_set_data (G_OBJECT (loader), "message-binding", NULL); + if (g_set_object (&self->loader, NULL)) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADER]); + if (!(document = sysprof_document_loader_load_finish (loader, result, &error))) { GtkWidget *dialog; @@ -750,6 +766,8 @@ sysprof_window_create (SysprofApplication *app, self = g_object_new (SYSPROF_TYPE_WINDOW, "application", app, NULL); + self->loader = g_object_ref (loader); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADER]); g_object_bind_property (loader, "fraction", self->progress_bar, "fraction", G_BINDING_SYNC_CREATE); diff --git a/src/sysprof/sysprof-window.ui b/src/sysprof/sysprof-window.ui index 1b361e37..f4e1e7cb 100644 --- a/src/sysprof/sysprof-window.ui +++ b/src/sysprof/sysprof-window.ui @@ -108,17 +108,6 @@ - - - - - - SysprofWindow - - - - - @@ -215,6 +204,70 @@ Toggle Right Panel + + + true + false + + + + + + + + SysprofWindow + + + + + + + 300 + + + never + true + 600 + + + + + + + SysprofWindow + + + + + + + + + + +]]> + + + + + + + + + + + diff --git a/src/sysprof/sysprof.gresource.xml b/src/sysprof/sysprof.gresource.xml index aefb57a9..70040947 100644 --- a/src/sysprof/sysprof.gresource.xml +++ b/src/sysprof/sysprof.gresource.xml @@ -53,6 +53,7 @@ sysprof-samples-section.ui sysprof-sidebar.ui sysprof-storage-section.ui + sysprof-task-row.ui sysprof-time-scrubber.ui sysprof-traceables-utility.ui sysprof-weighted-callgraph-view.ui -- 2.45.2