mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
This gets it out of the callgrpah view so that it can live in the sidebar area of a AdwOverlayNavigationView. We allow the utility area to control the entire view (including the toolbarview) so that we don't have to bind extra properties for titles, and other random things.
742 lines
27 KiB
C
742 lines
27 KiB
C
/* sysprof-callgraph-view.c
|
|
*
|
|
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <libpanel.h>
|
|
|
|
#include "libsysprof-gtk-resources.h"
|
|
|
|
#include "sysprof-callgraph-view-private.h"
|
|
#include "sysprof-symbol-label-private.h"
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_CALLGRAPH,
|
|
PROP_DOCUMENT,
|
|
PROP_HIDE_SYSTEM_LIBRARIES,
|
|
PROP_INCLUDE_THREADS,
|
|
PROP_TRACEABLES,
|
|
PROP_UTILITY_TRACEABLES,
|
|
N_PROPS
|
|
};
|
|
|
|
static void buildable_iface_init (GtkBuildableIface *iface);
|
|
static GListModel *sysprof_callgraph_view_create_model_func (gpointer item,
|
|
gpointer user_data);
|
|
static void descendants_selection_changed_cb (SysprofCallgraphView *self,
|
|
guint position,
|
|
guint n_items,
|
|
GtkSingleSelection *single);
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (SysprofCallgraphView, sysprof_callgraph_view, GTK_TYPE_WIDGET,
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
|
|
|
|
static GParamSpec *properties [N_PROPS];
|
|
|
|
static void
|
|
sysprof_callgraph_view_set_utility_traceables (SysprofCallgraphView *self,
|
|
GListModel *model)
|
|
{
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
g_assert (!model || G_IS_LIST_MODEL (model));
|
|
|
|
if (g_set_object (&self->utility_traceables, model))
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UTILITY_TRACEABLES]);
|
|
}
|
|
|
|
static void
|
|
sysprof_callgraph_view_set_descendants (SysprofCallgraphView *self,
|
|
GListModel *model)
|
|
{
|
|
g_autoptr(GtkTreeListRowSorter) descendants_sorter = NULL;
|
|
g_autoptr(GtkSingleSelection) descendants_selection = NULL;
|
|
g_autoptr(GtkSortListModel) descendants_sort_model = NULL;
|
|
g_autoptr(GtkTreeListModel) descendants_tree = NULL;
|
|
g_autoptr(GtkTreeListRow) descendants_first = NULL;
|
|
GtkSorter *column_sorter;
|
|
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
g_assert (G_IS_LIST_MODEL (model));
|
|
|
|
column_sorter = gtk_column_view_get_sorter (self->descendants_column_view);
|
|
descendants_tree = gtk_tree_list_model_new (g_object_ref (model),
|
|
FALSE, FALSE,
|
|
sysprof_callgraph_view_create_model_func,
|
|
NULL, NULL);
|
|
descendants_sorter = gtk_tree_list_row_sorter_new (g_object_ref (column_sorter));
|
|
descendants_sort_model = gtk_sort_list_model_new (g_object_ref (G_LIST_MODEL (descendants_tree)),
|
|
g_object_ref (GTK_SORTER (descendants_sorter)));
|
|
descendants_selection = gtk_single_selection_new (g_object_ref (G_LIST_MODEL (descendants_sort_model)));
|
|
g_signal_connect_object (descendants_selection,
|
|
"selection-changed",
|
|
G_CALLBACK (descendants_selection_changed_cb),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
gtk_column_view_set_model (self->descendants_column_view,
|
|
GTK_SELECTION_MODEL (descendants_selection));
|
|
|
|
if ((descendants_first = gtk_tree_list_model_get_row (descendants_tree, 0)))
|
|
gtk_tree_list_row_set_expanded (descendants_first, TRUE);
|
|
|
|
}
|
|
|
|
static void
|
|
sysprof_callgraph_view_descendants_cb (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
SysprofCallgraph *callgraph = (SysprofCallgraph *)object;
|
|
g_autoptr(SysprofCallgraphView) self = user_data;
|
|
g_autoptr(GListModel) model = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
g_assert (SYSPROF_IS_CALLGRAPH (callgraph));
|
|
g_assert (G_IS_ASYNC_RESULT (result));
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
|
|
if ((model = sysprof_callgraph_descendants_finish (callgraph, result, &error)))
|
|
sysprof_callgraph_view_set_descendants (self, model);
|
|
}
|
|
|
|
static void
|
|
callers_selection_changed_cb (SysprofCallgraphView *self,
|
|
guint position,
|
|
guint n_items,
|
|
GtkSingleSelection *single)
|
|
{
|
|
GObject *object;
|
|
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
g_assert (GTK_IS_SINGLE_SELECTION (single));
|
|
|
|
if ((object = gtk_single_selection_get_selected_item (single)))
|
|
{
|
|
SysprofCallgraphSymbol *sym = SYSPROF_CALLGRAPH_SYMBOL (object);
|
|
SysprofSymbol *symbol = sysprof_callgraph_symbol_get_symbol (sym);
|
|
|
|
g_debug ("Select %s as root callgraph node",
|
|
sysprof_symbol_get_name (symbol));
|
|
|
|
sysprof_callgraph_descendants_async (self->callgraph,
|
|
symbol,
|
|
NULL,
|
|
sysprof_callgraph_view_descendants_cb,
|
|
g_object_ref (self));
|
|
}
|
|
}
|
|
|
|
static void
|
|
sysprof_callgraph_view_list_traceables_cb (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
SysprofCallgraphFrame *frame = (SysprofCallgraphFrame *)object;
|
|
g_autoptr(SysprofCallgraphView) self = user_data;
|
|
g_autoptr(GListModel) model = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
g_assert (SYSPROF_IS_CALLGRAPH_FRAME (frame));
|
|
g_assert (G_IS_ASYNC_RESULT (result));
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
|
|
model = sysprof_callgraph_frame_list_traceables_finish (frame, result, &error);
|
|
|
|
sysprof_callgraph_view_set_utility_traceables (self, model);
|
|
}
|
|
|
|
static void
|
|
descendants_selection_changed_cb (SysprofCallgraphView *self,
|
|
guint position,
|
|
guint n_items,
|
|
GtkSingleSelection *single)
|
|
{
|
|
g_autoptr(GObject) item = NULL;
|
|
GObject *object;
|
|
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
g_assert (GTK_IS_SINGLE_SELECTION (single));
|
|
|
|
sysprof_callgraph_view_set_utility_traceables (self, NULL);
|
|
|
|
if ((object = gtk_single_selection_get_selected_item (single)) &&
|
|
GTK_IS_TREE_LIST_ROW (object) &&
|
|
(item = gtk_tree_list_row_get_item (GTK_TREE_LIST_ROW (object))) &&
|
|
SYSPROF_IS_CALLGRAPH_FRAME (item))
|
|
sysprof_callgraph_frame_list_traceables_async (SYSPROF_CALLGRAPH_FRAME (item),
|
|
NULL,
|
|
sysprof_callgraph_view_list_traceables_cb,
|
|
g_object_ref (self));
|
|
}
|
|
|
|
static void
|
|
functions_selection_changed_cb (SysprofCallgraphView *self,
|
|
guint position,
|
|
guint n_items,
|
|
GtkSingleSelection *single)
|
|
{
|
|
GObject *object;
|
|
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
g_assert (GTK_IS_SINGLE_SELECTION (single));
|
|
|
|
if ((object = gtk_single_selection_get_selected_item (single)))
|
|
{
|
|
SysprofCallgraphSymbol *sym = SYSPROF_CALLGRAPH_SYMBOL (object);
|
|
SysprofSymbol *symbol = sysprof_callgraph_symbol_get_symbol (sym);
|
|
g_autoptr(GtkSortListModel) callers_sort_model = NULL;
|
|
g_autoptr(GtkSingleSelection) callers_selection = NULL;
|
|
g_autoptr(GListModel) callers = sysprof_callgraph_list_callers (self->callgraph, symbol);
|
|
GtkSorter *column_sorter;
|
|
|
|
column_sorter = gtk_column_view_get_sorter (self->callers_column_view);
|
|
callers_sort_model = gtk_sort_list_model_new (g_object_ref (callers),
|
|
g_object_ref (column_sorter));
|
|
callers_selection = gtk_single_selection_new (g_object_ref (G_LIST_MODEL (callers_sort_model)));
|
|
gtk_single_selection_set_autoselect (callers_selection, FALSE);
|
|
gtk_single_selection_set_selected (callers_selection, GTK_INVALID_LIST_POSITION);
|
|
g_signal_connect_object (callers_selection,
|
|
"selection-changed",
|
|
G_CALLBACK (callers_selection_changed_cb),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
gtk_column_view_set_model (self->callers_column_view,
|
|
GTK_SELECTION_MODEL (callers_selection));
|
|
|
|
switch (sysprof_symbol_get_kind (symbol))
|
|
{
|
|
case SYSPROF_SYMBOL_KIND_ROOT:
|
|
sysprof_callgraph_view_set_descendants (self, G_LIST_MODEL (self->callgraph));
|
|
break;
|
|
|
|
default:
|
|
case SYSPROF_SYMBOL_KIND_PROCESS:
|
|
case SYSPROF_SYMBOL_KIND_THREAD:
|
|
case SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH:
|
|
case SYSPROF_SYMBOL_KIND_UNWINDABLE:
|
|
case SYSPROF_SYMBOL_KIND_USER:
|
|
case SYSPROF_SYMBOL_KIND_KERNEL:
|
|
sysprof_callgraph_descendants_async (self->callgraph,
|
|
symbol,
|
|
NULL,
|
|
sysprof_callgraph_view_descendants_cb,
|
|
g_object_ref (self));
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gtk_column_view_set_model (self->callers_column_view, NULL);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
static void
|
|
traceable_activate_cb (SysprofCallgraphView *self,
|
|
guint position,
|
|
GtkColumnView *column_view)
|
|
{
|
|
g_autoptr(SysprofSymbol) symbol = NULL;
|
|
GtkSelectionModel *model;
|
|
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
g_assert (GTK_IS_COLUMN_VIEW (column_view));
|
|
|
|
if ((model = gtk_column_view_get_model (column_view)) &&
|
|
(symbol = g_list_model_get_item (G_LIST_MODEL (model), position)))
|
|
{
|
|
GListModel *functions = G_LIST_MODEL (gtk_column_view_get_model (self->functions_column_view));
|
|
guint n_items = g_list_model_get_n_items (functions);
|
|
|
|
for (guint i = 0; i < n_items; i++)
|
|
{
|
|
g_autoptr(SysprofCallgraphSymbol) callsym = g_list_model_get_item (functions, i);
|
|
SysprofSymbol *cur = sysprof_callgraph_symbol_get_symbol (callsym);
|
|
|
|
if (sysprof_symbol_equal (cur, symbol))
|
|
{
|
|
GtkListView *list_view = NULL;
|
|
|
|
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self->functions_column_view));
|
|
child != NULL;
|
|
child = gtk_widget_get_next_sibling (child))
|
|
{
|
|
if (GTK_IS_LIST_VIEW (child))
|
|
{
|
|
list_view = GTK_LIST_VIEW (child);
|
|
break;
|
|
}
|
|
}
|
|
|
|
gtk_selection_model_select_item (GTK_SELECTION_MODEL (functions), i, TRUE);
|
|
|
|
if (list_view != NULL)
|
|
gtk_widget_activate_action (GTK_WIDGET (list_view), "list.scroll-to-item", "u", i);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
sysprof_callgraph_view_dispose (GObject *object)
|
|
{
|
|
SysprofCallgraphView *self = (SysprofCallgraphView *)object;
|
|
|
|
g_clear_handle_id (&self->reload_source, g_source_remove);
|
|
|
|
g_clear_pointer (&self->paned, gtk_widget_unparent);
|
|
|
|
g_cancellable_cancel (self->cancellable);
|
|
g_clear_object (&self->cancellable);
|
|
|
|
g_clear_object (&self->callgraph);
|
|
g_clear_object (&self->document);
|
|
g_clear_object (&self->traceables);
|
|
g_clear_object (&self->utility_traceables);
|
|
|
|
G_OBJECT_CLASS (sysprof_callgraph_view_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
sysprof_callgraph_view_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
SysprofCallgraphView *self = SYSPROF_CALLGRAPH_VIEW (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_CALLGRAPH:
|
|
g_value_set_object (value, sysprof_callgraph_view_get_callgraph (self));
|
|
break;
|
|
|
|
case PROP_DOCUMENT:
|
|
g_value_set_object (value, sysprof_callgraph_view_get_document (self));
|
|
break;
|
|
|
|
case PROP_HIDE_SYSTEM_LIBRARIES:
|
|
g_value_set_boolean (value, sysprof_callgraph_view_get_hide_system_libraries (self));
|
|
break;
|
|
|
|
case PROP_INCLUDE_THREADS:
|
|
g_value_set_boolean (value, sysprof_callgraph_view_get_include_threads (self));
|
|
break;
|
|
|
|
case PROP_TRACEABLES:
|
|
g_value_set_object (value, sysprof_callgraph_view_get_traceables (self));
|
|
break;
|
|
|
|
case PROP_UTILITY_TRACEABLES:
|
|
g_value_set_object (value, self->utility_traceables);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
sysprof_callgraph_view_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
SysprofCallgraphView *self = SYSPROF_CALLGRAPH_VIEW (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_DOCUMENT:
|
|
sysprof_callgraph_view_set_document (self, g_value_get_object (value));
|
|
break;
|
|
|
|
case PROP_HIDE_SYSTEM_LIBRARIES:
|
|
sysprof_callgraph_view_set_hide_system_libraries (self, g_value_get_boolean (value));
|
|
break;
|
|
|
|
case PROP_INCLUDE_THREADS:
|
|
sysprof_callgraph_view_set_include_threads (self, g_value_get_boolean (value));
|
|
break;
|
|
|
|
case PROP_TRACEABLES:
|
|
sysprof_callgraph_view_set_traceables (self, g_value_get_object (value));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
sysprof_callgraph_view_class_init (SysprofCallgraphViewClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
object_class->dispose = sysprof_callgraph_view_dispose;
|
|
object_class->get_property = sysprof_callgraph_view_get_property;
|
|
object_class->set_property = sysprof_callgraph_view_set_property;
|
|
|
|
properties[PROP_CALLGRAPH] =
|
|
g_param_spec_object ("callgraph", NULL, NULL,
|
|
SYSPROF_TYPE_CALLGRAPH,
|
|
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties[PROP_DOCUMENT] =
|
|
g_param_spec_object ("document", NULL, NULL,
|
|
SYSPROF_TYPE_DOCUMENT,
|
|
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties[PROP_HIDE_SYSTEM_LIBRARIES] =
|
|
g_param_spec_boolean ("hide-system-libraries", NULL, NULL,
|
|
FALSE,
|
|
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties[PROP_INCLUDE_THREADS] =
|
|
g_param_spec_boolean ("include-threads", NULL, NULL,
|
|
FALSE,
|
|
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties[PROP_TRACEABLES] =
|
|
g_param_spec_object ("traceables", NULL, NULL,
|
|
G_TYPE_LIST_MODEL,
|
|
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties[PROP_UTILITY_TRACEABLES] =
|
|
g_param_spec_object ("utility-traceables", NULL, NULL,
|
|
G_TYPE_LIST_MODEL,
|
|
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
|
|
|
gtk_widget_class_set_template_from_resource (widget_class, "/libsysprof-gtk/sysprof-callgraph-view.ui");
|
|
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
|
gtk_widget_class_set_css_name (widget_class, "callgraphview");
|
|
gtk_widget_class_bind_template_child (widget_class, SysprofCallgraphView, callers_column_view);
|
|
gtk_widget_class_bind_template_child (widget_class, SysprofCallgraphView, descendants_column_view);
|
|
gtk_widget_class_bind_template_child (widget_class, SysprofCallgraphView, descendants_name_sorter);
|
|
gtk_widget_class_bind_template_child (widget_class, SysprofCallgraphView, functions_column_view);
|
|
gtk_widget_class_bind_template_child (widget_class, SysprofCallgraphView, functions_name_sorter);
|
|
gtk_widget_class_bind_template_child (widget_class, SysprofCallgraphView, paned);
|
|
|
|
klass->augment_size = GLIB_SIZEOF_VOID_P;
|
|
|
|
g_resources_register (libsysprof_gtk_get_resource ());
|
|
|
|
g_type_ensure (PANEL_TYPE_PANED);
|
|
g_type_ensure (SYSPROF_TYPE_SYMBOL_LABEL);
|
|
}
|
|
|
|
static void
|
|
sysprof_callgraph_view_init (SysprofCallgraphView *self)
|
|
{
|
|
gtk_widget_init_template (GTK_WIDGET (self));
|
|
}
|
|
|
|
static int
|
|
descendants_name_compare (gconstpointer a,
|
|
gconstpointer b,
|
|
gpointer user_data)
|
|
{
|
|
SysprofCallgraphFrame *frame_a = (SysprofCallgraphFrame *)a;
|
|
SysprofCallgraphFrame *frame_b = (SysprofCallgraphFrame *)b;
|
|
|
|
return g_strcmp0 (sysprof_symbol_get_name (sysprof_callgraph_frame_get_symbol (frame_a)),
|
|
sysprof_symbol_get_name (sysprof_callgraph_frame_get_symbol (frame_b)));
|
|
}
|
|
|
|
static int
|
|
functions_name_compare (gconstpointer a,
|
|
gconstpointer b,
|
|
gpointer user_data)
|
|
{
|
|
SysprofCallgraphSymbol *sym_a = (SysprofCallgraphSymbol *)a;
|
|
SysprofCallgraphSymbol *sym_b = (SysprofCallgraphSymbol *)b;
|
|
|
|
return g_strcmp0 (sysprof_symbol_get_name (sysprof_callgraph_symbol_get_symbol (sym_a)),
|
|
sysprof_symbol_get_name (sysprof_callgraph_symbol_get_symbol (sym_b)));
|
|
}
|
|
|
|
static GListModel *
|
|
sysprof_callgraph_view_create_model_func (gpointer item,
|
|
gpointer user_data)
|
|
{
|
|
if (g_list_model_get_n_items (G_LIST_MODEL (item)) > 0)
|
|
return g_object_ref (G_LIST_MODEL (item));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
sysprof_callgraph_view_reload_cb (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
SysprofDocument *document = (SysprofDocument *)object;
|
|
g_autoptr(SysprofCallgraphView) self = user_data;
|
|
g_autoptr(SysprofCallgraph) callgraph = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
GtkSorter *column_sorter;
|
|
|
|
g_autoptr(GtkSingleSelection) functions_selection = NULL;
|
|
g_autoptr(GtkSortListModel) functions_sort_model = NULL;
|
|
g_autoptr(GListModel) functions_model = NULL;
|
|
|
|
g_assert (SYSPROF_IS_DOCUMENT (document));
|
|
g_assert (G_IS_ASYNC_RESULT (result));
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
|
|
if (!(callgraph = sysprof_document_callgraph_finish (document, result, &error)))
|
|
{
|
|
g_debug ("Failed to generate callgraph: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
g_set_object (&self->callgraph, callgraph);
|
|
|
|
sysprof_callgraph_view_set_descendants (self, G_LIST_MODEL (callgraph));
|
|
|
|
column_sorter = gtk_column_view_get_sorter (self->functions_column_view);
|
|
functions_model = sysprof_callgraph_list_symbols (callgraph);
|
|
functions_sort_model = gtk_sort_list_model_new (g_object_ref (functions_model),
|
|
g_object_ref (column_sorter));
|
|
functions_selection = gtk_single_selection_new (g_object_ref (G_LIST_MODEL (functions_sort_model)));
|
|
gtk_single_selection_set_autoselect (functions_selection, FALSE);
|
|
gtk_single_selection_set_can_unselect (functions_selection, TRUE);
|
|
gtk_single_selection_set_selected (functions_selection, GTK_INVALID_LIST_POSITION);
|
|
g_signal_connect_object (functions_selection,
|
|
"selection-changed",
|
|
G_CALLBACK (functions_selection_changed_cb),
|
|
self,
|
|
G_CONNECT_SWAPPED);
|
|
gtk_column_view_set_model (self->functions_column_view,
|
|
GTK_SELECTION_MODEL (functions_selection));
|
|
|
|
gtk_custom_sorter_set_sort_func (self->descendants_name_sorter,
|
|
descendants_name_compare, NULL, NULL);
|
|
gtk_custom_sorter_set_sort_func (self->functions_name_sorter,
|
|
functions_name_compare, NULL, NULL);
|
|
|
|
if (SYSPROF_CALLGRAPH_VIEW_GET_CLASS (self)->load)
|
|
SYSPROF_CALLGRAPH_VIEW_GET_CLASS (self)->load (self, callgraph);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CALLGRAPH]);
|
|
}
|
|
|
|
static gboolean
|
|
sysprof_callgraph_view_reload (SysprofCallgraphView *self)
|
|
{
|
|
SysprofCallgraphFlags flags = 0;
|
|
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
|
|
g_clear_handle_id (&self->reload_source, g_source_remove);
|
|
|
|
if (self->include_threads)
|
|
flags |= SYSPROF_CALLGRAPH_FLAGS_INCLUDE_THREADS;
|
|
|
|
if (self->hide_system_libraries)
|
|
flags |= SYSPROF_CALLGRAPH_FLAGS_HIDE_SYSTEM_LIBRARIES;
|
|
|
|
sysprof_document_callgraph_async (self->document,
|
|
flags,
|
|
self->traceables,
|
|
SYSPROF_CALLGRAPH_VIEW_GET_CLASS (self)->augment_size,
|
|
SYSPROF_CALLGRAPH_VIEW_GET_CLASS (self)->augment_func,
|
|
NULL,
|
|
NULL,
|
|
self->cancellable,
|
|
sysprof_callgraph_view_reload_cb,
|
|
g_object_ref (self));
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
sysprof_callgraph_view_queue_reload (SysprofCallgraphView *self)
|
|
{
|
|
g_assert (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
|
|
sysprof_callgraph_view_set_utility_traceables (self, NULL);
|
|
|
|
gtk_column_view_set_model (self->descendants_column_view, NULL);
|
|
gtk_column_view_set_model (self->functions_column_view, NULL);
|
|
gtk_column_view_set_model (self->callers_column_view, NULL);
|
|
|
|
g_clear_handle_id (&self->reload_source, g_source_remove);
|
|
g_cancellable_cancel (self->cancellable);
|
|
|
|
g_clear_object (&self->cancellable);
|
|
self->cancellable = g_cancellable_new ();
|
|
|
|
if (self->document != NULL && self->traceables != NULL)
|
|
self->reload_source = g_idle_add_full (G_PRIORITY_LOW,
|
|
(GSourceFunc)sysprof_callgraph_view_reload,
|
|
g_object_ref (self),
|
|
g_object_unref);
|
|
}
|
|
|
|
/**
|
|
* sysprof_callgraph_view_get_document:
|
|
* @self: a #SysprofCallgraphView
|
|
*
|
|
* Gets the document for the callgraph.
|
|
*
|
|
* Returns: (transfer none) (nullable): a #SysprofDocument or %NULL
|
|
*/
|
|
SysprofDocument *
|
|
sysprof_callgraph_view_get_document (SysprofCallgraphView *self)
|
|
{
|
|
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self), NULL);
|
|
|
|
return self->document;
|
|
}
|
|
|
|
void
|
|
sysprof_callgraph_view_set_document (SysprofCallgraphView *self,
|
|
SysprofDocument *document)
|
|
{
|
|
g_return_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
|
|
if (g_set_object (&self->document, document))
|
|
{
|
|
sysprof_callgraph_view_queue_reload (self);
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DOCUMENT]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* sysprof_callgraph_view_get_traceables:
|
|
* @self: a #SysprofCallgraphView
|
|
*
|
|
* Gets the list of traceables to be displayed.
|
|
*
|
|
* Returns: (transfer none) (nullable): a #GListModel or %NULL
|
|
*/
|
|
GListModel *
|
|
sysprof_callgraph_view_get_traceables (SysprofCallgraphView *self)
|
|
{
|
|
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self), NULL);
|
|
|
|
return self->traceables;
|
|
}
|
|
|
|
void
|
|
sysprof_callgraph_view_set_traceables (SysprofCallgraphView *self,
|
|
GListModel *traceables)
|
|
{
|
|
g_return_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
g_return_if_fail (!traceables || G_IS_LIST_MODEL (traceables));
|
|
|
|
if (g_set_object (&self->traceables, traceables))
|
|
{
|
|
sysprof_callgraph_view_queue_reload (self);
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TRACEABLES]);
|
|
}
|
|
}
|
|
|
|
static GObject *
|
|
sysprof_callgraph_view_get_internal_child (GtkBuildable *buildable,
|
|
GtkBuilder *builder,
|
|
const char *name)
|
|
{
|
|
if (g_strcmp0 (name, "callers_column_view") == 0)
|
|
return G_OBJECT (SYSPROF_CALLGRAPH_VIEW (buildable)->callers_column_view);
|
|
else if (g_strcmp0 (name, "descendants_column_view") == 0)
|
|
return G_OBJECT (SYSPROF_CALLGRAPH_VIEW (buildable)->descendants_column_view);
|
|
else if (g_strcmp0 (name, "functions_column_view") == 0)
|
|
return G_OBJECT (SYSPROF_CALLGRAPH_VIEW (buildable)->functions_column_view);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
buildable_iface_init (GtkBuildableIface *iface)
|
|
{
|
|
iface->get_internal_child = sysprof_callgraph_view_get_internal_child;
|
|
}
|
|
|
|
/**
|
|
* sysprof_callgraph_view_get_callgraph:
|
|
* @self: a #SysprofCallgraphView
|
|
*
|
|
* Gets the callgraph being displayed.
|
|
*
|
|
* Returns: (transfer none) (nullable): a #SysprofCallgraph or %NULL
|
|
*/
|
|
SysprofCallgraph *
|
|
sysprof_callgraph_view_get_callgraph (SysprofCallgraphView *self)
|
|
{
|
|
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self), NULL);
|
|
|
|
return self->callgraph;
|
|
}
|
|
|
|
gboolean
|
|
sysprof_callgraph_view_get_hide_system_libraries (SysprofCallgraphView *self)
|
|
{
|
|
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self), FALSE);
|
|
|
|
return self->hide_system_libraries;
|
|
}
|
|
|
|
void
|
|
sysprof_callgraph_view_set_hide_system_libraries (SysprofCallgraphView *self,
|
|
gboolean hide_system_libraries)
|
|
{
|
|
g_return_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
|
|
hide_system_libraries = !!hide_system_libraries;
|
|
|
|
if (self->hide_system_libraries != hide_system_libraries)
|
|
{
|
|
self->hide_system_libraries = hide_system_libraries;
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HIDE_SYSTEM_LIBRARIES]);
|
|
sysprof_callgraph_view_queue_reload (self);
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
sysprof_callgraph_view_get_include_threads (SysprofCallgraphView *self)
|
|
{
|
|
g_return_val_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self), FALSE);
|
|
|
|
return self->include_threads;
|
|
}
|
|
|
|
void
|
|
sysprof_callgraph_view_set_include_threads (SysprofCallgraphView *self,
|
|
gboolean include_threads)
|
|
{
|
|
g_return_if_fail (SYSPROF_IS_CALLGRAPH_VIEW (self));
|
|
|
|
include_threads = !!include_threads;
|
|
|
|
if (self->include_threads != include_threads)
|
|
{
|
|
self->include_threads = include_threads;
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INCLUDE_THREADS]);
|
|
sysprof_callgraph_view_queue_reload (self);
|
|
}
|
|
}
|