diff --git a/src/libsysprof-ui/libsysprof-ui.gresource.xml b/src/libsysprof-ui/libsysprof-ui.gresource.xml index 46ac5f86..849b877a 100644 --- a/src/libsysprof-ui/libsysprof-ui.gresource.xml +++ b/src/libsysprof-ui/libsysprof-ui.gresource.xml @@ -11,6 +11,7 @@ ui/sysprof-callgraph-view.ui ui/sysprof-capture-view.ui + ui/sysprof-display.ui ui/sysprof-details-view.ui ui/sysprof-empty-state-view.ui ui/sysprof-failed-state-view.ui @@ -18,6 +19,7 @@ ui/sysprof-process-model-row.ui ui/sysprof-profiler-menu-button.ui ui/sysprof-recording-state-view.ui + ui/sysprof-tab.ui ui/sysprof-visualizer-view.ui diff --git a/src/libsysprof-ui/meson.build b/src/libsysprof-ui/meson.build index e7c46453..29972b7e 100644 --- a/src/libsysprof-ui/meson.build +++ b/src/libsysprof-ui/meson.build @@ -3,6 +3,7 @@ libsysprof_ui_public_sources = [ 'sysprof-callgraph-view.c', 'sysprof-color-cycle.c', 'sysprof-cpu-visualizer-row.c', + 'sysprof-display.c', 'sysprof-empty-state-view.c', 'sysprof-failed-state-view.c', 'sysprof-line-visualizer-row.c', @@ -11,6 +12,7 @@ libsysprof_ui_public_sources = [ 'sysprof-mark-visualizer-row.c', 'sysprof-model-filter.c', 'sysprof-multi-paned.c', + 'sysprof-notebook.c', 'sysprof-process-model-row.c', 'sysprof-profiler-menu-button.c', 'sysprof-recording-state-view.c', @@ -27,6 +29,7 @@ libsysprof_ui_private_sources = [ 'sysprof-details-view.c', 'sysprof-cell-renderer-duration.c', 'sysprof-cell-renderer-percent.c', + 'sysprof-tab.c', 'sysprof-theme-manager.c', '../stackstash.c', ] @@ -36,6 +39,7 @@ libsysprof_ui_public_headers = [ 'sysprof-callgraph-view.h', 'sysprof-cell-renderer-percent.h', 'sysprof-cpu-visualizer-row.h', + 'sysprof-display.h', 'sysprof-empty-state-view.h', 'sysprof-failed-state-view.h', 'sysprof-line-visualizer-row.h', @@ -44,6 +48,7 @@ libsysprof_ui_public_headers = [ 'sysprof-mark-visualizer-row.h', 'sysprof-model-filter.h', 'sysprof-multi-paned.h', + 'sysprof-notebook.h', 'sysprof-process-model-row.h', 'sysprof-profiler-menu-button.h', 'sysprof-recording-state-view.h', diff --git a/src/libsysprof-ui/sysprof-capture-view.c b/src/libsysprof-ui/sysprof-capture-view.c index 39a447a1..0322fd89 100644 --- a/src/libsysprof-ui/sysprof-capture-view.c +++ b/src/libsysprof-ui/sysprof-capture-view.c @@ -226,7 +226,7 @@ sysprof_capture_view_scan_worker (GTask *task, SysprofCaptureReader *reader = task_data; SysprofCaptureFeatures features = {0}; SysprofCaptureFrame frame; - SysprofCaptureStat st_buf = {0}; + SysprofCaptureStat st_buf = {{0}}; g_assert (SYSPROF_IS_CAPTURE_VIEW (self)); g_assert (G_IS_TASK (task)); @@ -775,3 +775,22 @@ sysprof_capture_view_fit_to_width (SysprofCaptureView *self) zoom = sysprof_zoom_manager_fit_zoom_for_duration (priv->zoom_manager, duration, width); sysprof_zoom_manager_set_zoom (priv->zoom_manager, zoom); } + +/** + * sysprof_capture_view_get_reader: + * + * Gets the reader for the view, if any. + * + * Returns: (transfer none): a #SysprofCaptureReader or %NULL + * + * Since: 3.34 + */ +SysprofCaptureReader * +sysprof_capture_view_get_reader (SysprofCaptureView *self) +{ + SysprofCaptureViewPrivate *priv = sysprof_capture_view_get_instance_private (self); + + g_return_val_if_fail (SYSPROF_IS_CAPTURE_VIEW (self), NULL); + + return priv->reader; +} diff --git a/src/libsysprof-ui/sysprof-display.c b/src/libsysprof-ui/sysprof-display.c new file mode 100644 index 00000000..1a90c861 --- /dev/null +++ b/src/libsysprof-ui/sysprof-display.c @@ -0,0 +1,159 @@ +/* sysprof-display.c + * + * Copyright 2019 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 + */ + +#define G_LOG_DOMAIN "sysprof-display" + +#include "config.h" + +#include + +#include +#include +#include + +#include "sysprof-capture-view.h" +#include "sysprof-display.h" +#include "sysprof-empty-state-view.h" +#include "sysprof-recording-state-view.h" + +typedef struct +{ + SysprofCaptureView *capture_view; + SysprofEmptyStateView *empty_view; + SysprofRecordingStateView *recording_view; +} SysprofDisplayPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (SysprofDisplay, sysprof_display, GTK_TYPE_BIN) + +enum { + PROP_0, + PROP_TITLE, + N_PROPS +}; + +static GParamSpec *properties [N_PROPS]; + +/** + * sysprof_display_new: + * + * Create a new #SysprofDisplay. + * + * Returns: (transfer full): a newly created #SysprofDisplay + * + * Since: 3.34 + */ +GtkWidget * +sysprof_display_new (void) +{ + return g_object_new (SYSPROF_TYPE_DISPLAY, NULL); +} + +static gchar * +sysprof_display_dup_title (SysprofDisplay *self) +{ + SysprofDisplayPrivate *priv = sysprof_display_get_instance_private (self); + SysprofCaptureReader *reader; + + g_return_val_if_fail (SYSPROF_IS_DISPLAY (self), NULL); + + if ((reader = sysprof_capture_view_get_reader (priv->capture_view))) + { + const gchar *filename; + + if ((filename = sysprof_capture_reader_get_filename (reader))) + return g_strdup (filename); + + } + + return g_strdup (_("Unsaved Session")); +} + +static void +sysprof_display_finalize (GObject *object) +{ + G_OBJECT_CLASS (sysprof_display_parent_class)->finalize (object); +} + +static void +sysprof_display_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofDisplay *self = (SysprofDisplay *)object; + + switch (prop_id) + { + case PROP_TITLE: + g_value_take_string (value, sysprof_display_dup_title (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_display_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_display_class_init (SysprofDisplayClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = sysprof_display_finalize; + object_class->get_property = sysprof_display_get_property; + object_class->set_property = sysprof_display_set_property; + + properties [PROP_TITLE] = + g_param_spec_string ("title", + "Title", + "The title of the display", + NULL, + (G_PARAM_READABLE | 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/ui/sysprof-display.ui"); + gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay , empty_view); + gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay , recording_view); + gtk_widget_class_bind_template_child_private (widget_class, SysprofDisplay , capture_view); + + g_type_ensure (SYSPROF_TYPE_CAPTURE_VIEW); + g_type_ensure (SYSPROF_TYPE_EMPTY_STATE_VIEW); + g_type_ensure (SYSPROF_TYPE_RECORDING_STATE_VIEW); +} + +static void +sysprof_display_init (SysprofDisplay *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} diff --git a/src/libsysprof-ui/sysprof-display.h b/src/libsysprof-ui/sysprof-display.h new file mode 100644 index 00000000..0b6c735a --- /dev/null +++ b/src/libsysprof-ui/sysprof-display.h @@ -0,0 +1,45 @@ +/* sysprof-display.h + * + * Copyright 2019 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_DISPLAY (sysprof_display_get_type()) + +SYSPROF_AVAILABLE_IN_ALL +G_DECLARE_DERIVABLE_TYPE (SysprofDisplay, sysprof_display, SYSPROF, DISPLAY, GtkBin) + +struct _SysprofDisplayClass +{ + GtkBinClass parent_class; + + /*< private >*/ + gpointer _reserved[16]; +} __attribute__((aligned(8))); + +SYSPROF_AVAILABLE_IN_ALL +GtkWidget *sysprof_display_new (void); + +G_END_DECLS diff --git a/src/libsysprof-ui/sysprof-notebook.c b/src/libsysprof-ui/sysprof-notebook.c new file mode 100644 index 00000000..0be49776 --- /dev/null +++ b/src/libsysprof-ui/sysprof-notebook.c @@ -0,0 +1,167 @@ +/* sysprof-notebook.c + * + * Copyright 2019 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 + */ + +#define G_LOG_DOMAIN "sysprof-notebook" + +#include "config.h" + +#include "sysprof-display.h" +#include "sysprof-notebook.h" +#include "sysprof-tab.h" + +typedef struct +{ + void *dummy; +} SysprofNotebookPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (SysprofNotebook, sysprof_notebook, GTK_TYPE_NOTEBOOK) + +enum { + PROP_0, + N_PROPS +}; + +static GParamSpec *properties [N_PROPS]; + +/** + * sysprof_notebook_new: + * + * Create a new #SysprofNotebook. + * + * Returns: (transfer full): a newly created #SysprofNotebook + * + * Since: 3.34 + */ +GtkWidget * +sysprof_notebook_new (void) +{ + return g_object_new (SYSPROF_TYPE_NOTEBOOK, NULL); +} + +static void +sysprof_notebook_page_added (GtkNotebook *notebook, + GtkWidget *child, + guint page_num) +{ + g_assert (SYSPROF_IS_NOTEBOOK (notebook)); + g_assert (GTK_IS_WIDGET (child)); + + if (SYSPROF_IS_DISPLAY (child)) + { + GtkWidget *tab = sysprof_tab_new (SYSPROF_DISPLAY (child)); + + gtk_notebook_set_tab_label (notebook, child, tab); + gtk_notebook_set_tab_reorderable (notebook, child, TRUE); + } + + gtk_notebook_set_show_tabs (notebook, + gtk_notebook_get_n_pages (notebook) > 1); +} + +static void +sysprof_notebook_page_removed (GtkNotebook *notebook, + GtkWidget *child, + guint page_num) +{ + g_assert (SYSPROF_IS_NOTEBOOK (notebook)); + g_assert (GTK_IS_WIDGET (child)); + + if (gtk_notebook_get_n_pages (notebook) == 0) + { + child = sysprof_display_new (); + gtk_container_add (GTK_CONTAINER (notebook), child); + gtk_widget_show (child); + } + + gtk_notebook_set_show_tabs (notebook, + gtk_notebook_get_n_pages (notebook) > 1); +} + +static void +sysprof_notebook_finalize (GObject *object) +{ + SysprofNotebook *self = (SysprofNotebook *)object; + SysprofNotebookPrivate *priv = sysprof_notebook_get_instance_private (self); + + G_OBJECT_CLASS (sysprof_notebook_parent_class)->finalize (object); +} + +static void +sysprof_notebook_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofNotebook *self = SYSPROF_NOTEBOOK (object); + + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_notebook_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofNotebook *self = SYSPROF_NOTEBOOK (object); + + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_notebook_class_init (SysprofNotebookClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass); + + object_class->finalize = sysprof_notebook_finalize; + object_class->get_property = sysprof_notebook_get_property; + object_class->set_property = sysprof_notebook_set_property; + + notebook_class->page_added = sysprof_notebook_page_added; + notebook_class->page_removed = sysprof_notebook_page_removed; +} + +static void +sysprof_notebook_init (SysprofNotebook *self) +{ + gtk_notebook_set_show_border (GTK_NOTEBOOK (self), FALSE); + gtk_notebook_set_scrollable (GTK_NOTEBOOK (self), TRUE); + gtk_notebook_popup_enable (GTK_NOTEBOOK (self)); +} + +void +sysprof_notebook_close_current (SysprofNotebook *self) +{ + gint page; + + g_return_if_fail (SYSPROF_IS_NOTEBOOK (self)); + + if ((page = gtk_notebook_get_current_page (GTK_NOTEBOOK (self))) >= 0) + gtk_widget_destroy (gtk_notebook_get_nth_page (GTK_NOTEBOOK (self), page)); +} diff --git a/src/libsysprof-ui/sysprof-notebook.h b/src/libsysprof-ui/sysprof-notebook.h new file mode 100644 index 00000000..7a064399 --- /dev/null +++ b/src/libsysprof-ui/sysprof-notebook.h @@ -0,0 +1,47 @@ +/* sysprof-notebook.h + * + * Copyright 2019 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_NOTEBOOK (sysprof_notebook_get_type()) + +SYSPROF_AVAILABLE_IN_ALL +G_DECLARE_DERIVABLE_TYPE (SysprofNotebook, sysprof_notebook, SYSPROF, NOTEBOOK, GtkNotebook) + +struct _SysprofNotebookClass +{ + GtkNotebookClass parent_class; + + /*< private >*/ + gpointer _reserved[16]; +}; + +SYSPROF_AVAILABLE_IN_ALL +GtkWidget *sysprof_notebook_new (void); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_notebook_close_current (SysprofNotebook *self); + +G_END_DECLS diff --git a/src/libsysprof-ui/sysprof-tab.c b/src/libsysprof-ui/sysprof-tab.c new file mode 100644 index 00000000..45c9254f --- /dev/null +++ b/src/libsysprof-ui/sysprof-tab.c @@ -0,0 +1,152 @@ +/* sysprof-tab.c + * + * Copyright 2019 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 + */ + +#define G_LOG_DOMAIN "sysprof-tab" + +#include "config.h" + +#include "sysprof-display.h" +#include "sysprof-tab.h" + +struct _SysprofTab +{ + GtkBox parent_instance; + + GtkButton *close_button; + GtkLabel *title; + + SysprofDisplay *display; +}; + +G_DEFINE_TYPE (SysprofTab, sysprof_tab, GTK_TYPE_BOX) + +enum { + PROP_0, + PROP_DISPLAY, + N_PROPS +}; + +static GParamSpec *properties [N_PROPS]; + +GtkWidget * +sysprof_tab_new (SysprofDisplay *display) +{ + return g_object_new (SYSPROF_TYPE_TAB, + "display", display, + NULL); +} + +static void +sysprof_tab_close_clicked (SysprofTab *self, + GtkButton *button) +{ + g_assert (SYSPROF_IS_TAB (self)); + g_assert (GTK_IS_BUTTON (button)); + + if (self->display != NULL) + gtk_widget_destroy (GTK_WIDGET (self->display)); +} + +static void +sysprof_tab_finalize (GObject *object) +{ + SysprofTab *self = (SysprofTab *)object; + + g_clear_weak_pointer (&self->display); + + G_OBJECT_CLASS (sysprof_tab_parent_class)->finalize (object); +} + +static void +sysprof_tab_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofTab *self = SYSPROF_TAB (object); + + switch (prop_id) + { + case PROP_DISPLAY: + g_value_set_object (value, self->display); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_tab_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofTab *self = SYSPROF_TAB (object); + + switch (prop_id) + { + case PROP_DISPLAY: + g_set_weak_pointer (&self->display, g_value_get_object (value)); + g_object_bind_property (self->display, "title", + self->title, "label", + G_BINDING_SYNC_CREATE); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_tab_class_init (SysprofTabClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = sysprof_tab_finalize; + object_class->get_property = sysprof_tab_get_property; + object_class->set_property = sysprof_tab_set_property; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-tab.ui"); + gtk_widget_class_bind_template_child (widget_class, SysprofTab, close_button); + gtk_widget_class_bind_template_child (widget_class, SysprofTab, title); + + properties [PROP_DISPLAY] = + g_param_spec_object ("display", + "Display", + "The display widget for the tab", + SYSPROF_TYPE_DISPLAY, + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_tab_init (SysprofTab *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + g_signal_connect_object (self->close_button, + "clicked", + G_CALLBACK (sysprof_tab_close_clicked), + self, + G_CONNECT_SWAPPED); +} diff --git a/src/libsysprof-ui/sysprof-tab.h b/src/libsysprof-ui/sysprof-tab.h new file mode 100644 index 00000000..1762244e --- /dev/null +++ b/src/libsysprof-ui/sysprof-tab.h @@ -0,0 +1,35 @@ +/* sysprof-tab.h + * + * Copyright 2019 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-display.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_TAB (sysprof_tab_get_type()) + +G_DECLARE_FINAL_TYPE (SysprofTab, sysprof_tab, SYSPROF, TAB, GtkBox) + +GtkWidget *sysprof_tab_new (SysprofDisplay *display); + +G_END_DECLS diff --git a/src/libsysprof-ui/sysprof-ui.h b/src/libsysprof-ui/sysprof-ui.h index 52a3af80..51cbb5b3 100644 --- a/src/libsysprof-ui/sysprof-ui.h +++ b/src/libsysprof-ui/sysprof-ui.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS # include "sysprof-capture-view.h" # include "sysprof-cell-renderer-percent.h" # include "sysprof-cpu-visualizer-row.h" +# include "sysprof-display.h" # include "sysprof-empty-state-view.h" # include "sysprof-failed-state-view.h" # include "sysprof-line-visualizer-row.h" @@ -38,6 +39,7 @@ G_BEGIN_DECLS # include "sysprof-mark-visualizer-row.h" # include "sysprof-model-filter.h" # include "sysprof-multi-paned.h" +# include "sysprof-notebook.h" # include "sysprof-process-model-row.h" # include "sysprof-profiler-menu-button.h" # include "sysprof-recording-state-view.h" diff --git a/src/libsysprof-ui/ui/sysprof-display.ui b/src/libsysprof-ui/ui/sysprof-display.ui new file mode 100644 index 00000000..1392b5ab --- /dev/null +++ b/src/libsysprof-ui/ui/sysprof-display.ui @@ -0,0 +1,37 @@ + + + + diff --git a/src/libsysprof-ui/ui/sysprof-tab.ui b/src/libsysprof-ui/ui/sysprof-tab.ui new file mode 100644 index 00000000..7f63472b --- /dev/null +++ b/src/libsysprof-ui/ui/sysprof-tab.ui @@ -0,0 +1,45 @@ + + + + + + diff --git a/src/sysprof/sysprof-application.c b/src/sysprof/sysprof-application.c index 4405a6bd..24e6cd7e 100644 --- a/src/sysprof/sysprof-application.c +++ b/src/sysprof/sysprof-application.c @@ -36,9 +36,20 @@ struct { const gchar *action_name; const gchar *accels[12]; } default_accels[] = { - { "zoom.zoom-in", { "plus", "KP_Add", "equal", "ZoomIn", NULL } }, - { "zoom.zoom-out", { "minus", "KP_Subtract", "ZoomOut", NULL } }, - { "zoom.zoom-one", { "0", "KP_0", NULL } }, + { "zoom.zoom-in", { "plus", "KP_Add", "equal", "ZoomIn", NULL } }, + { "zoom.zoom-out", { "minus", "KP_Subtract", "ZoomOut", NULL } }, + { "zoom.zoom-one", { "0", "KP_0", NULL } }, + { "win.new-tab", { "t", NULL } }, + { "win.close-tab", { "w", NULL } }, + { "win.switch-tab(1)", { "1", NULL } }, + { "win.switch-tab(2)", { "2", NULL } }, + { "win.switch-tab(3)", { "3", NULL } }, + { "win.switch-tab(4)", { "4", NULL } }, + { "win.switch-tab(5)", { "5", NULL } }, + { "win.switch-tab(6)", { "6", NULL } }, + { "win.switch-tab(7)", { "7", NULL } }, + { "win.switch-tab(8)", { "8", NULL } }, + { "win.switch-tab(9)", { "9", NULL } }, { NULL } }; @@ -70,29 +81,23 @@ sysprof_application_activate (GApplication *app) static void sysprof_application_open (GApplication *app, - GFile **files, - gint n_files, - const gchar *hint) + GFile **files, + gint n_files, + const gchar *hint) { - guint opened = 0; - gint i; + GtkWidget *window; g_assert (SYSPROF_IS_APPLICATION (app)); g_assert (files != NULL || n_files == 0); - for (i = 0; i < n_files; i++) - { - SysprofWindow *window; + window = sysprof_window_new (SYSPROF_APPLICATION (app)); - window = g_object_new (SYSPROF_TYPE_WINDOW, - "application", app, - NULL); - sysprof_window_open (window, files [i]); - gtk_window_present (GTK_WINDOW (window)); - opened++; - } + for (gint i = 0; i < n_files; i++) + sysprof_window_open (SYSPROF_WINDOW (window), files[i]); - if (opened == 0) + gtk_window_present (GTK_WINDOW (window)); + + if (n_files == 0) sysprof_application_activate (app); } @@ -246,7 +251,6 @@ sysprof_open_capture (GSimpleAction *action, gpointer user_data) { GtkApplication *app = user_data; - GtkWidget *window; GList *list; g_assert (G_IS_APPLICATION (app)); @@ -257,29 +261,11 @@ sysprof_open_capture (GSimpleAction *action, for (; list != NULL; list = list->next) { - window = list->data; + GtkWindow *window = list->data; if (SYSPROF_IS_WINDOW (window)) - { - SysprofWindowState state; - - state = sysprof_window_get_state (SYSPROF_WINDOW (window)); - - if (state == SYSPROF_WINDOW_STATE_EMPTY) - { - sysprof_window_open_from_dialog (SYSPROF_WINDOW (window)); - return; - } - } + sysprof_window_open_from_dialog (SYSPROF_WINDOW (window)); } - - window = g_object_new (SYSPROF_TYPE_WINDOW, - "application", app, - NULL); - - gtk_window_present (GTK_WINDOW (window)); - - sysprof_window_open_from_dialog (SYSPROF_WINDOW (window)); } static void diff --git a/src/sysprof/sysprof-window.c b/src/sysprof/sysprof-window.c index ca950bab..249637b7 100644 --- a/src/sysprof/sysprof-window.c +++ b/src/sysprof/sysprof-window.c @@ -1,6 +1,6 @@ /* sysprof-window.c * - * Copyright 2016 Christian Hergert + * Copyright 2016-2019 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 @@ -14,791 +14,84 @@ * * 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 */ #define G_LOG_DOMAIN "sysprof-window" #include "config.h" -#include -#include -#include #include -#include "sysprof-application.h" #include "sysprof-window.h" -#include "sysprof-window-settings.h" struct _SysprofWindow { GtkApplicationWindow parent_instance; - - SysprofWindowState state; - - SysprofProfiler *profiler; - SysprofCaptureReader *reader; - - GCancellable *refilter_cancellable; - - /* Gtk widget template children */ - SysprofCallgraphView *callgraph_view; - SysprofEmptyStateView *empty_view; - GtkMenuButton *gear_menu_button; - GtkInfoBar *info_bar; - GtkLabel *info_bar_label; - GtkRevealer *info_bar_revealer; - SysprofMarksView *marks_view; - GtkPaned *paned; - SysprofProfilerMenuButton *profiler_menu_button; - SysprofRecordingStateView *recording_view; - GtkButton *record_button; - GtkLabel *subtitle; - GtkLabel *stat_label; - GtkLabel *title; - GtkStack *view_stack; - SysprofVisualizerView *visualizers; - SysprofZoomManager *zoom_manager; - GtkLabel *zoom_one_label; - - guint stats_handler; - - guint closing : 1; + SysprofNotebook *notebook; }; G_DEFINE_TYPE (SysprofWindow, sysprof_window, GTK_TYPE_APPLICATION_WINDOW) -static void sysprof_window_set_state (SysprofWindow *self, - SysprofWindowState state); - -enum { - START_RECORDING, - STOP_RECORDING, - N_SIGNALS -}; - -static guint signals [N_SIGNALS]; - -static void sysprof_window_set_profiler (SysprofWindow *self, - SysprofProfiler *profiler); - -static G_GNUC_PRINTF(3, 4) void -sysprof_window_notify_user (SysprofWindow *self, - GtkMessageType message_type, - const gchar *format, - ...) +/** + * sysprof_window_new: + * + * Create a new #SysprofWindow. + * + * Returns: (transfer full): a newly created #SysprofWindow + */ +GtkWidget * +sysprof_window_new (SysprofApplication *application) { - g_autofree gchar *str = NULL; - va_list args; - - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (format != NULL); - - va_start (args, format); - str = g_strdup_vprintf (format, args); - va_end (args); - - gtk_info_bar_set_message_type (self->info_bar, message_type); - gtk_label_set_label (self->info_bar_label, str); - gtk_revealer_set_reveal_child (self->info_bar_revealer, TRUE); + return g_object_new (SYSPROF_TYPE_WINDOW, + "application", application, + NULL); } static void -sysprof_window_action_set (SysprofWindow *self, - const gchar *action_name, - const gchar *first_property, - ...) -{ - gpointer action; - va_list args; - - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (action_name != NULL); - - action = g_action_map_lookup_action (G_ACTION_MAP (self), action_name); - - if (action == NULL) - { - g_warning ("Failed to locate action \"%s\"", action_name); - return; - } - - va_start (args, first_property); - g_object_set_valist (action, first_property, args); - va_end (args); -} - -static gboolean -sysprof_window_update_stats (gpointer data) -{ - SysprofWindow *self = data; - - g_assert (SYSPROF_IS_WINDOW (self)); - - if (self->profiler != NULL) - { - SysprofCaptureWriter *writer; - - if (NULL != (writer = sysprof_profiler_get_writer (self->profiler))) - { - g_autofree gchar *str = NULL; - SysprofCaptureStat stbuf; - guint count; - - sysprof_capture_writer_stat (writer, &stbuf); - - count = stbuf.frame_count[SYSPROF_CAPTURE_FRAME_SAMPLE]; - /* Translators: %u is the number (amount) of samples. */ - str = g_strdup_printf (_("Samples: %u"), count); - gtk_label_set_label (self->stat_label, str); - } - } - - return G_SOURCE_CONTINUE; -} - - -static void -sysprof_window_update_subtitle (SysprofWindow *self) -{ - g_autofree gchar *relative = NULL; - const gchar *filename; - const gchar *date; - GTimeVal tv; - - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (self->reader != NULL); - - if (NULL != (filename = sysprof_capture_reader_get_filename (self->reader))) - { - g_autoptr(GFile) home = NULL; - g_autoptr(GFile) file = NULL; - - file = g_file_new_for_path (filename); - home = g_file_new_for_path (g_get_home_dir ()); - - if (g_file_has_prefix (file, home)) - filename = relative = g_file_get_relative_path (home, file); - } - - if (filename == NULL) - filename = _("[Memory Capture]"); - - date = sysprof_capture_reader_get_time (self->reader); - - if (g_time_val_from_iso8601 (date, &tv)) - { - g_autoptr(GDateTime) dt = NULL; - g_autofree gchar *str = NULL; - g_autofree gchar *label = NULL; - - dt = g_date_time_new_from_timeval_local (&tv); - str = g_date_time_format (dt, "%x %X"); - - /* Translators: The first %s is a file name, the second is the date and time. */ - label = g_strdup_printf (_("%s — %s"), filename, str); - - gtk_label_set_label (self->subtitle, label); - } - else - gtk_label_set_label (self->subtitle, filename); -} - -static void -sysprof_window_build_profile_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - SysprofProfile *profile = (SysprofProfile *)object; - g_autoptr(SysprofWindow) self = user_data; - g_autoptr(GError) error = NULL; - - g_assert (SYSPROF_IS_CALLGRAPH_PROFILE (profile)); - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (G_IS_ASYNC_RESULT (result)); - - gtk_widget_set_sensitive (GTK_WIDGET (self->record_button), TRUE); - - if (!sysprof_profile_generate_finish (profile, result, &error)) - { - /* If we were cancelled while updating the selection, ignore the failure */ - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && - (self->state == SYSPROF_WINDOW_STATE_BROWSING)) - return; - sysprof_window_notify_user (self, GTK_MESSAGE_ERROR, "%s", error->message); - sysprof_window_set_state (self, SYSPROF_WINDOW_STATE_EMPTY); - return; - } - - sysprof_callgraph_view_set_profile (self->callgraph_view, SYSPROF_CALLGRAPH_PROFILE (profile)); - if (sysprof_callgraph_view_get_n_functions (self->callgraph_view) == 0) - sysprof_window_notify_user (self, - GTK_MESSAGE_WARNING, - _("Not enough samples were collected to generate a callgraph")); - - sysprof_visualizer_view_set_reader (self->visualizers, self->reader); - - sysprof_window_set_state (self, SYSPROF_WINDOW_STATE_BROWSING); -} - -static void -sysprof_window_build_profile (SysprofWindow *self) -{ - g_autoptr(SysprofProfile) profile = NULL; - SysprofSelection *selection; - - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (self->reader != NULL); - - if (self->refilter_cancellable != NULL) - { - if (!g_cancellable_is_cancelled (self->refilter_cancellable)) - g_cancellable_cancel (self->refilter_cancellable); - g_clear_object (&self->refilter_cancellable); - } - - selection = sysprof_visualizer_view_get_selection (self->visualizers); - - profile = sysprof_callgraph_profile_new_with_selection (selection); - sysprof_profile_set_reader (profile, self->reader); - - self->refilter_cancellable = g_cancellable_new (); - - gtk_widget_set_sensitive (GTK_WIDGET (self->record_button), FALSE); - - sysprof_profile_generate (profile, - self->refilter_cancellable, - sysprof_window_build_profile_cb, - g_object_ref (self)); - - sysprof_marks_view_load_async (self->marks_view, self->reader, selection, NULL, NULL, NULL); -} - -static void -add_class (gpointer widget, - const gchar *name) -{ - g_assert (GTK_IS_WIDGET (widget)); - - gtk_style_context_add_class (gtk_widget_get_style_context (widget), name); -} - -static void -remove_class (gpointer widget, - const gchar *name) -{ - g_assert (GTK_IS_WIDGET (widget)); - - gtk_style_context_remove_class (gtk_widget_get_style_context (widget), name); -} - -static void -sysprof_window_set_state (SysprofWindow *self, - SysprofWindowState state) -{ - g_autoptr(SysprofProfiler) profiler = NULL; - - g_assert (SYSPROF_IS_WINDOW (self)); - - if (self->state == state) - return; - - self->state = state; - - switch (state) - { - case SYSPROF_WINDOW_STATE_EMPTY: - case SYSPROF_WINDOW_STATE_FAILED: - /* Translators: This is a button. */ - gtk_button_set_label (self->record_button, _("Record")); - gtk_widget_set_sensitive (GTK_WIDGET (self->record_button), TRUE); - add_class (self->record_button, "suggested-action"); - remove_class (self->record_button, "destructive-action"); - if (state == SYSPROF_WINDOW_STATE_FAILED) - gtk_stack_set_visible_child_name (self->view_stack, "failed"); - else - gtk_stack_set_visible_child_name (self->view_stack, "empty"); - gtk_label_set_label (self->subtitle, _("Not running")); - sysprof_callgraph_view_set_profile (self->callgraph_view, NULL); - gtk_widget_set_visible (GTK_WIDGET (self->stat_label), FALSE); - g_clear_pointer (&self->reader, sysprof_capture_reader_unref); - sysprof_window_action_set (self, "close-capture", "enabled", FALSE, NULL); - sysprof_window_action_set (self, "save-capture", "enabled", FALSE, NULL); - sysprof_window_action_set (self, "screenshot", "enabled", FALSE, NULL); - profiler = sysprof_local_profiler_new (); - sysprof_window_set_profiler (self, profiler); - break; - - case SYSPROF_WINDOW_STATE_RECORDING: - /* Translators: This is a button. */ - gtk_button_set_label (self->record_button, _("Stop")); - gtk_widget_set_sensitive (GTK_WIDGET (self->record_button), TRUE); - remove_class (self->record_button, "suggested-action"); - add_class (self->record_button, "destructive-action"); - gtk_stack_set_visible_child_name (self->view_stack, "recording"); - gtk_label_set_label (self->subtitle, _("Recording…")); - gtk_widget_set_visible (GTK_WIDGET (self->stat_label), TRUE); - g_clear_pointer (&self->reader, sysprof_capture_reader_unref); - sysprof_callgraph_view_set_profile (self->callgraph_view, NULL); - sysprof_window_action_set (self, "close-capture", "enabled", FALSE, NULL); - sysprof_window_action_set (self, "save-capture", "enabled", FALSE, NULL); - sysprof_window_action_set (self, "screenshot", "enabled", FALSE, NULL); - break; - - case SYSPROF_WINDOW_STATE_PROCESSING: - gtk_widget_set_sensitive (GTK_WIDGET (self->record_button), FALSE); - gtk_label_set_label (self->subtitle, _("Building profile…")); - sysprof_window_action_set (self, "close-capture", "enabled", FALSE, NULL); - sysprof_window_action_set (self, "save-capture", "enabled", FALSE, NULL); - sysprof_window_action_set (self, "screenshot", "enabled", FALSE, NULL); - sysprof_window_build_profile (self); - break; - - case SYSPROF_WINDOW_STATE_BROWSING: - /* Translators: This is a button. */ - gtk_button_set_label (self->record_button, _("Record")); - gtk_widget_set_sensitive (GTK_WIDGET (self->record_button), TRUE); - add_class (self->record_button, "suggested-action"); - remove_class (self->record_button, "destructive-action"); - gtk_widget_set_visible (GTK_WIDGET (self->stat_label), TRUE); - gtk_stack_set_visible_child_name (self->view_stack, "browsing"); - sysprof_window_update_stats (self); - sysprof_window_update_subtitle (self); - sysprof_window_action_set (self, "close-capture", "enabled", TRUE, NULL); - sysprof_window_action_set (self, "save-capture", "enabled", TRUE, NULL); - sysprof_window_action_set (self, "screenshot", "enabled", TRUE, NULL); - profiler = sysprof_local_profiler_new (); - sysprof_window_set_profiler (self, profiler); - break; - - case SYSPROF_WINDOW_STATE_0: - default: - g_warning ("Unknown state: %0d", state); - break; - } -} - -static void -sysprof_window_enable_stats (SysprofWindow *self) -{ - g_assert (SYSPROF_IS_WINDOW (self)); - - if (self->stats_handler == 0) - self->stats_handler = - g_timeout_add_seconds (1, sysprof_window_update_stats, self); -} - -static void -sysprof_window_disable_stats (SysprofWindow *self) -{ - g_assert (SYSPROF_IS_WINDOW (self)); - - if (self->stats_handler != 0) - { - g_source_remove (self->stats_handler); - self->stats_handler = 0; - } -} - -static void -sysprof_window_add_sources (SysprofWindow *window, - SysprofProfiler *profiler) -{ -#ifdef __linux__ - g_autoptr(SysprofSource) host_source = NULL; - g_autoptr(SysprofSource) proc_source = NULL; - g_autoptr(SysprofSource) perf_source = NULL; - g_autoptr(SysprofSource) memory_source = NULL; - - g_assert (SYSPROF_IS_WINDOW (window)); - g_assert (SYSPROF_IS_PROFILER (profiler)); - - proc_source = sysprof_proc_source_new (); - sysprof_profiler_add_source (profiler, proc_source); - - perf_source = sysprof_perf_source_new (); - sysprof_profiler_add_source (profiler, perf_source); - - host_source = sysprof_hostinfo_source_new (); - sysprof_profiler_add_source (profiler, host_source); - - memory_source = sysprof_memory_source_new (); - sysprof_profiler_add_source (profiler, memory_source); -#endif -} - -static void -sysprof_window_start_recording (SysprofWindow *self) -{ - g_assert (SYSPROF_IS_WINDOW (self)); - - if ((self->state == SYSPROF_WINDOW_STATE_EMPTY) || - (self->state == SYSPROF_WINDOW_STATE_FAILED) || - (self->state == SYSPROF_WINDOW_STATE_BROWSING)) - { - gtk_revealer_set_reveal_child (self->info_bar_revealer, FALSE); - sysprof_window_add_sources (self, self->profiler); - sysprof_window_set_state (self, SYSPROF_WINDOW_STATE_RECORDING); - sysprof_window_enable_stats (self); - sysprof_profiler_start (self->profiler); - return; - } -} - -static void -sysprof_window_stop_recording (SysprofWindow *self) -{ - g_assert (SYSPROF_IS_WINDOW (self)); - - if (self->state == SYSPROF_WINDOW_STATE_RECORDING) - { - if (self->profiler != NULL) - { - /* SysprofProfiler::stopped will move us to generating */ - gtk_label_set_label (self->subtitle, _("Stopping…")); - /* - * In case that ::stopped takes a while to execute, - * disable record button immediately. - */ - gtk_widget_set_sensitive (GTK_WIDGET (self->record_button), FALSE); - sysprof_profiler_stop (self->profiler); - } - } -} - -static void -sysprof_window_hide_info_bar_revealer (SysprofWindow *self) -{ - g_assert (SYSPROF_IS_WINDOW (self)); - - gtk_revealer_set_reveal_child (self->info_bar_revealer, FALSE); -} - -static void -sysprof_window_profiler_stopped (SysprofWindow *self, - SysprofProfiler *profiler) -{ - g_autoptr(SysprofCaptureReader) reader = NULL; - g_autoptr(GError) error = NULL; - SysprofCaptureWriter *writer; - - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (SYSPROF_IS_PROFILER (profiler)); - - sysprof_window_disable_stats (self); - - if (self->closing) - { - gtk_window_close (GTK_WINDOW (self)); - return; - } - - if (self->state == SYSPROF_WINDOW_STATE_FAILED) - return; - - writer = sysprof_profiler_get_writer (profiler); - reader = sysprof_capture_writer_create_reader (writer, &error); - - if (reader == NULL) - { - sysprof_window_notify_user (self, GTK_MESSAGE_ERROR, "%s", error->message); - sysprof_window_set_state (self, SYSPROF_WINDOW_STATE_EMPTY); - return; - } - - g_clear_pointer (&self->reader, sysprof_capture_reader_unref); - self->reader = g_steal_pointer (&reader); - - sysprof_window_build_profile (self); -} - -static void -sysprof_window_profiler_failed (SysprofWindow *self, - const GError *reason, - SysprofProfiler *profiler) -{ - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (reason != NULL); - g_assert (SYSPROF_IS_PROFILER (profiler)); - - sysprof_window_notify_user (self, GTK_MESSAGE_ERROR, "%s", reason->message); - sysprof_window_set_state (self, SYSPROF_WINDOW_STATE_FAILED); -} - -static void -sysprof_window_set_profiler (SysprofWindow *self, - SysprofProfiler *profiler) -{ - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (SYSPROF_IS_PROFILER (profiler)); - - if (self->profiler != profiler) - { - if (self->profiler != NULL) - { - if (sysprof_profiler_get_is_running (self->profiler)) - sysprof_profiler_stop (self->profiler); - sysprof_profiler_menu_button_set_profiler (self->profiler_menu_button, NULL); - sysprof_recording_state_view_set_profiler (self->recording_view, NULL); - g_clear_object (&self->profiler); - } - - if (profiler != NULL) - { - if (!sysprof_profiler_get_is_mutable (profiler)) - { - g_warning ("Ignoring attempt to set profiler to an already running session!"); - return; - } - - self->profiler = g_object_ref (profiler); - - g_signal_connect_object (profiler, - "stopped", - G_CALLBACK (sysprof_window_profiler_stopped), - self, - G_CONNECT_SWAPPED); - - g_signal_connect_object (profiler, - "failed", - G_CALLBACK (sysprof_window_profiler_failed), - self, - G_CONNECT_SWAPPED); - - sysprof_profiler_menu_button_set_profiler (self->profiler_menu_button, profiler); - sysprof_recording_state_view_set_profiler (self->recording_view, profiler); - } - } -} - -static void -sysprof_window_open_capture (GSimpleAction *action, - GVariant *variant, - gpointer user_data) +new_tab_cb (GSimpleAction *action, + GVariant *param, + gpointer user_data) { SysprofWindow *self = user_data; - g_assert (G_IS_SIMPLE_ACTION (action)); - g_assert (variant == NULL); - g_assert (SYSPROF_IS_WINDOW (self)); + g_return_if_fail (SYSPROF_IS_WINDOW (self)); - sysprof_window_open_from_dialog (self); + sysprof_window_new_tab (self); } static void -sysprof_window_save_capture (GSimpleAction *action, - GVariant *variant, - gpointer user_data) +switch_tab_cb (GSimpleAction *action, + GVariant *param, + gpointer user_data) { - g_autoptr(SysprofCaptureReader) reader = NULL; SysprofWindow *self = user_data; - GtkFileChooserNative *dialog; - gint response; + gint page; - g_assert (G_IS_SIMPLE_ACTION (action)); - g_assert (variant == NULL); - g_assert (SYSPROF_IS_WINDOW (self)); + g_return_if_fail (SYSPROF_IS_WINDOW (self)); + g_return_if_fail (g_variant_is_of_type (param, G_VARIANT_TYPE_INT32)); - if (self->reader == NULL) - { - g_warning ("Save called without a capture open, ignoring"); - return; - } - - reader = sysprof_capture_reader_ref (self->reader); - - /* Translators: This is a window title. */ - dialog = gtk_file_chooser_native_new (_("Save Capture As…"), - GTK_WINDOW (self), - GTK_FILE_CHOOSER_ACTION_SAVE, - /* Translators: This is a button. */ - _("Save"), - /* Translators: This is a button. */ - _("Cancel")); - - gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE); - - response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog)); - - if (response == GTK_RESPONSE_ACCEPT) - { - g_autofree gchar *filename = NULL; - g_autoptr(GError) error = NULL; - - filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); - - if (filename == NULL) - goto failure; - - if (!g_str_has_suffix (filename, ".syscap")) - { - gchar *tmp; - - tmp = g_strdup_printf ("%s.syscap", filename); - g_free (filename); - filename = tmp; - } - - /* this should really be done outside the main loop. */ - if (!sysprof_capture_reader_save_as (reader, filename, &error)) - { - sysprof_window_notify_user (self, - GTK_MESSAGE_ERROR, - /* Translators: %s is the error message. */ - _("An error occurred while attempting to save your capture: %s"), - error->message); - goto failure; - } - } - -failure: - gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (dialog)); + page = g_variant_get_int32 (param); + gtk_notebook_set_current_page (GTK_NOTEBOOK (self->notebook), page - 1); } static void -sysprof_window_close_capture (GSimpleAction *action, - GVariant *variant, - gpointer user_data) +close_tab_cb (GSimpleAction *action, + GVariant *param, + gpointer user_data) { SysprofWindow *self = user_data; - g_assert (G_IS_SIMPLE_ACTION (action)); - g_assert (variant == NULL); - g_assert (SYSPROF_IS_WINDOW (self)); + g_return_if_fail (SYSPROF_IS_WINDOW (self)); - sysprof_window_set_state (self, SYSPROF_WINDOW_STATE_EMPTY); + sysprof_notebook_close_current (self->notebook); } static void -sysprof_window_record_button_clicked (SysprofWindow *self, - GtkButton *button) +sysprof_window_finalize (GObject *object) { - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (GTK_IS_BUTTON (button)); - - if (self->state == SYSPROF_WINDOW_STATE_RECORDING) - sysprof_window_stop_recording (self); - else - sysprof_window_start_recording (self); -} - -static void -sysprof_window_screenshot (GSimpleAction *action, - GVariant *variant, - gpointer user_data) -{ - SysprofWindow *self = user_data; - g_autofree gchar *str = NULL; - GtkWindow *window; - GtkScrolledWindow *scroller; - GtkTextView *text_view; - - g_assert (G_IS_SIMPLE_ACTION (action)); - g_assert (SYSPROF_IS_WINDOW (self)); - - if (NULL == (str = sysprof_callgraph_view_screenshot (self->callgraph_view))) - return; - - window = g_object_new (GTK_TYPE_WINDOW, - "title", "Sysprof", - "default-width", 800, - "default-height", 600, - "transient-for", self, - NULL); - - scroller = g_object_new (GTK_TYPE_SCROLLED_WINDOW, - "visible", TRUE, - NULL); - gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (scroller)); - - text_view = g_object_new (GTK_TYPE_TEXT_VIEW, - "editable", FALSE, - "monospace", TRUE, - "visible", TRUE, - NULL); - gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (text_view)); - - gtk_text_buffer_set_text (gtk_text_view_get_buffer (text_view), str, -1); - - gtk_window_present (window); -} - -static gboolean -sysprof_window_delete_event (GtkWidget *widget, - GdkEventAny *event) -{ - SysprofWindow *self = (SysprofWindow *)widget; - - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (event != NULL); - - if (self->state == SYSPROF_WINDOW_STATE_RECORDING) - { - if (self->profiler != NULL) - { - if (self->closing == FALSE) - { - self->closing = TRUE; - sysprof_profiler_stop (self->profiler); - return GDK_EVENT_STOP; - } - } - } - - return GDK_EVENT_PROPAGATE; -} - -static gboolean -zoom_level_to_string (GBinding *binding, - const GValue *from_value, - GValue *to_value, - gpointer user_data) -{ - gdouble percent = 100.0 * g_value_get_double (from_value); - g_value_take_string (to_value, g_strdup_printf ("%u%%", (guint)floor (percent))); - return TRUE; -} - -static void -sysprof_window_visualizers_selection_changed (SysprofWindow *self, - SysprofSelection *selection) -{ - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (SYSPROF_IS_SELECTION (selection)); - - sysprof_window_build_profile (self); -} - -static void -sysprof_window_destroy (GtkWidget *widget) -{ - SysprofWindow *self = (SysprofWindow *)widget; - - if (self->refilter_cancellable != NULL) - { - if (!g_cancellable_is_cancelled (self->refilter_cancellable)) - g_cancellable_cancel (self->refilter_cancellable); - g_clear_object (&self->refilter_cancellable); - } - - g_clear_object (&self->profiler); - g_clear_pointer (&self->reader, sysprof_capture_reader_unref); - sysprof_window_disable_stats (self); - - GTK_WIDGET_CLASS (sysprof_window_parent_class)->destroy (widget); -} - -static void -sysprof_window_constructed (GObject *object) -{ - SysprofWindow *self = (SysprofWindow *)object; - g_autoptr(SysprofProfiler) profiler = NULL; - - G_OBJECT_CLASS (sysprof_window_parent_class)->constructed (object); - - profiler = sysprof_local_profiler_new (); - sysprof_window_set_profiler (self, profiler); - - sysprof_window_set_state (self, SYSPROF_WINDOW_STATE_EMPTY); + G_OBJECT_CLASS (sysprof_window_parent_class)->finalize (object); } static void @@ -806,255 +99,61 @@ sysprof_window_class_init (SysprofWindowClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - GtkBindingSet *binding_set; - object_class->constructed = sysprof_window_constructed; - - widget_class->delete_event = sysprof_window_delete_event; - widget_class->destroy = sysprof_window_destroy; - - signals [START_RECORDING] = - g_signal_new_class_handler ("start-recording", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_CALLBACK (sysprof_window_start_recording), - NULL, NULL, NULL, G_TYPE_NONE, 0); - - signals [STOP_RECORDING] = - g_signal_new_class_handler ("stop-recording", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_CALLBACK (sysprof_window_stop_recording), - NULL, NULL, NULL, G_TYPE_NONE, 0); - - binding_set = gtk_binding_set_by_class (klass); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "stop-recording", 0); + object_class->finalize = sysprof_window_finalize; gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-window.ui"); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, callgraph_view); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, empty_view); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, gear_menu_button); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, info_bar); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, info_bar_label); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, info_bar_revealer); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, marks_view); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, paned); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, profiler_menu_button); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, record_button); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, recording_view); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, stat_label); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, subtitle); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, title); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, view_stack); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, visualizers); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, zoom_manager); - gtk_widget_class_bind_template_child (widget_class, SysprofWindow, zoom_one_label); + gtk_widget_class_bind_template_child (widget_class, SysprofWindow , notebook); - g_type_ensure (SYSPROF_TYPE_MARKS_VIEW); + g_type_ensure (SYSPROF_TYPE_PROFILER_MENU_BUTTON); + g_type_ensure (SYSPROF_TYPE_NOTEBOOK); + g_type_ensure (SYSPROF_TYPE_DISPLAY); } static void sysprof_window_init (SysprofWindow *self) { - static GActionEntry action_entries[] = { - { "close-capture", sysprof_window_close_capture }, - { "open-capture", sysprof_window_open_capture }, - { "save-capture", sysprof_window_save_capture }, - { "screenshot", sysprof_window_screenshot }, + static GActionEntry actions[] = { + { "close-tab", close_tab_cb }, + { "new-tab", new_tab_cb }, + { "switch-tab", switch_tab_cb, "i" }, }; - SysprofSelection *selection; - g_autoptr(GtkWindowGroup) window_group = NULL; gtk_widget_init_template (GTK_WIDGET (self)); -#ifdef DEVELOPMENT_BUILD - gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (self)), "development-version"); -#endif - - /* - * Hookup widget signals. - */ - - g_signal_connect_object (self->info_bar, - "response", - G_CALLBACK (sysprof_window_hide_info_bar_revealer), - self, - G_CONNECT_SWAPPED); - - g_signal_connect_object (self->info_bar, - "close", - G_CALLBACK (sysprof_window_hide_info_bar_revealer), - self, - G_CONNECT_SWAPPED); - - g_signal_connect_object (self->record_button, - "clicked", - G_CALLBACK (sysprof_window_record_button_clicked), - self, - G_CONNECT_SWAPPED); - - g_object_bind_property_full (self->zoom_manager, "zoom", self->zoom_one_label, "label", - G_BINDING_SYNC_CREATE, - zoom_level_to_string, NULL, NULL, NULL); - - /* - * Wire up selections for visualizers to update callgraph. - */ - - selection = sysprof_visualizer_view_get_selection (self->visualizers); - - g_signal_connect_object (selection, - "changed", - G_CALLBACK (sysprof_window_visualizers_selection_changed), - self, - G_CONNECT_SWAPPED); - - /* - * Setup actions for the window. - */ g_action_map_add_action_entries (G_ACTION_MAP (self), - action_entries, - G_N_ELEMENTS (action_entries), + actions, + G_N_ELEMENTS (actions), self); - gtk_widget_insert_action_group (GTK_WIDGET (self), "zoom", G_ACTION_GROUP (self->zoom_manager)); - - /* - * Restore previous window settings. - */ - sysprof_window_settings_register (GTK_WINDOW (self)); - - /* - * Set default focus to the record button for quick workflow of - * launch, enter, escape, view. - */ - gtk_window_set_focus (GTK_WINDOW (self), GTK_WIDGET (self->record_button)); - - /* - * Prevent grabs (e.g. modal dialogs) from affecting multiple windows. - */ - window_group = gtk_window_group_new (); - gtk_window_group_add_window (window_group, GTK_WINDOW (self)); -} - -static void -sysprof_window_open_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - SysprofWindow *self = (SysprofWindow *)object; - g_autoptr(SysprofCaptureReader) reader = NULL; - g_autoptr(GError) error = NULL; - - g_assert (SYSPROF_IS_WINDOW (self)); - g_assert (G_IS_TASK (result)); - - if (!(reader = g_task_propagate_pointer (G_TASK (result), &error))) - { - sysprof_window_notify_user (self, - GTK_MESSAGE_ERROR, - "%s", error->message); - return; - } - - g_clear_pointer (&self->reader, sysprof_capture_reader_unref); - self->reader = g_steal_pointer (&reader); - - sysprof_window_set_state (self, SYSPROF_WINDOW_STATE_PROCESSING); -} - -static void -sysprof_window_open_worker (GTask *task, - gpointer source_object, - gpointer task_data, - GCancellable *cancellable) -{ - g_autofree gchar *path = NULL; - g_autoptr(GError) error = NULL; - SysprofCaptureReader *reader; - GFile *file = task_data; - - g_assert (G_IS_TASK (task)); - g_assert (SYSPROF_IS_WINDOW (source_object)); - g_assert (G_IS_FILE (file)); - - path = g_file_get_path (file); - - if (!(reader = sysprof_capture_reader_new (path, &error))) - g_task_return_error (task, g_steal_pointer (&error)); - else - g_task_return_pointer (task, - g_steal_pointer (&reader), - (GDestroyNotify)sysprof_capture_reader_unref); } void sysprof_window_open (SysprofWindow *self, GFile *file) { - g_autoptr(GTask) task = NULL; - g_return_if_fail (SYSPROF_IS_WINDOW (self)); g_return_if_fail (G_IS_FILE (file)); - if (!g_file_is_native (file)) - { - sysprof_window_notify_user (self, - GTK_MESSAGE_ERROR, - _("The file “%s” could not be opened. Only local files are supported."), - g_file_get_uri (file)); - return; - } - task = g_task_new (self, NULL, sysprof_window_open_cb, NULL); - g_task_set_task_data (task, g_object_ref (file), g_object_unref); - g_task_run_in_thread (task, sysprof_window_open_worker); -} - -SysprofWindowState -sysprof_window_get_state (SysprofWindow *self) -{ - g_return_val_if_fail (SYSPROF_IS_WINDOW (self), SYSPROF_WINDOW_STATE_0); - - return self->state; } void sysprof_window_open_from_dialog (SysprofWindow *self) { - GtkFileChooserNative *dialog; - GtkFileFilter *filter; - gint response; - - g_assert (SYSPROF_IS_WINDOW (self)); - - /* Translators: This is a window title. */ - dialog = gtk_file_chooser_native_new (_("Open Capture…"), - GTK_WINDOW (self), - GTK_FILE_CHOOSER_ACTION_OPEN, - /* Translators: This is a button. */ - _("Open"), - /* Translators: This is a button. */ - _("Cancel")); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("Sysprof Captures")); - gtk_file_filter_add_pattern (filter, "*.syscap"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("All Files")); - gtk_file_filter_add_pattern (filter, "*"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); - - response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog)); - - if (response == GTK_RESPONSE_ACCEPT) - { - g_autoptr(GFile) file = NULL; - - file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); - sysprof_window_open (self, file); - } - - gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (dialog)); + g_return_if_fail (SYSPROF_IS_WINDOW (self)); +} + +void +sysprof_window_new_tab (SysprofWindow *self) +{ + GtkWidget *display; + gint page; + + g_return_if_fail (SYSPROF_IS_WINDOW (self)); + + display = sysprof_display_new (); + page = gtk_notebook_insert_page (GTK_NOTEBOOK (self->notebook), display, NULL, -1); + gtk_widget_show (display); + + gtk_notebook_set_current_page (GTK_NOTEBOOK (self->notebook), page); } diff --git a/src/sysprof/sysprof-window.h b/src/sysprof/sysprof-window.h index ca0ceb90..1b88aeaa 100644 --- a/src/sysprof/sysprof-window.h +++ b/src/sysprof/sysprof-window.h @@ -1,6 +1,6 @@ /* sysprof-window.h * - * Copyright 2016 Christian Hergert + * Copyright 2016-2019 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 @@ -14,39 +14,26 @@ * * 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 */ -#ifndef SYSPROF_WINDOW_H -#define SYSPROF_WINDOW_H +#pragma once #include +#include "sysprof-application.h" + G_BEGIN_DECLS #define SYSPROF_TYPE_WINDOW (sysprof_window_get_type()) G_DECLARE_FINAL_TYPE (SysprofWindow, sysprof_window, SYSPROF, WINDOW, GtkApplicationWindow) -typedef enum -{ - SYSPROF_WINDOW_STATE_0, - SYSPROF_WINDOW_STATE_EMPTY, - SYSPROF_WINDOW_STATE_FAILED, - SYSPROF_WINDOW_STATE_RECORDING, - SYSPROF_WINDOW_STATE_PROCESSING, - SYSPROF_WINDOW_STATE_BROWSING, -} SysprofWindowState; - -SysprofWindowState sysprof_window_get_state (SysprofWindow *self); -gboolean sysprof_window_get_recording (SysprofWindow *self); -GFile *sysprof_window_get_capture_file (SysprofWindow *self); -void sysprof_window_set_capture_file (SysprofWindow *self, - GFile *capture_file); -void sysprof_window_open (SysprofWindow *self, - GFile *file); -void sysprof_window_open_from_dialog (SysprofWindow *self); +GtkWidget *sysprof_window_new (SysprofApplication *application); +void sysprof_window_new_tab (SysprofWindow *self); +void sysprof_window_open (SysprofWindow *self, + GFile *file); +void sysprof_window_open_from_dialog (SysprofWindow *self); G_END_DECLS - -#endif /* SYSPROF_WINDOW_H */ - diff --git a/src/sysprof/ui/sysprof-window.ui b/src/sysprof/ui/sysprof-window.ui index b92247d5..a5e85dbc 100644 --- a/src/sysprof/ui/sysprof-window.ui +++ b/src/sysprof/ui/sysprof-window.ui @@ -70,296 +70,17 @@ 1 - - - gear_popover - true - - - - open-menu-symbolic - true - - - - - end - 0 - - - - vertical + true - + true - false - - - true - - - - - true - Failure - true - true - 0 - - - - - _Close - true - true - 100 - - - - - - close_info_button - - - - - - - - true - 400 - crossfade - true - - - true - - - empty - - - - - true - - - failed - - - - - true - - - recording - - - - - vertical - true - true - - - true - zoom_manager - - - - - true - true - - - true - true - - - Callgraph - - - - - true - true - - - Marks - - - - - - - browsing - - - - 0.01 - - - 12 - 225 - - - vertical - true - - - true - horizontal - true - - - - zoom.zoom-out - true - Zoom out (Ctrl+-) - true - - - - zoom-out-symbolic - true - - - - - - - zoom.zoom-one - Reset zoom level (Ctrl+0) - true - - - 5 - true - - - - - - - zoom.zoom-in - true - Zoom in (Ctrl++) - true - - - - zoom-in-symbolic - true - - - - - - - - - horizontal - 6 - true - - - - - app.new-window - New Window - true - - - - - horizontal - true - - - - - win.open-capture - Open Capture… - true - - - - - win.save-capture - Save As… - true - - - - - horizontal - true - - - - - win.screenshot - Screenshot - true - - - - - horizontal - true - - - - - win.close-capture - Close - true - - - - - horizontal - true - - - - - app.show-help-overlay - Keyboard Shortcuts - true - - - - - app.help - Help - true - - - - - app.about - About Sysprof - true - - - - -