mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
libsysprof-ui: remove legacy libsysprof-ui library
This is libsysprof-gtk now, but that too will be absorbed by sysprof app directly rather than having a UI library.
This commit is contained in:
@ -1,86 +0,0 @@
|
||||
SysprofVisualizer {
|
||||
background: @content_view_bg;
|
||||
}
|
||||
SysprofVisualizer:not(:last-child) {
|
||||
border-bottom: 1px solid alpha(@borders, 0.3);
|
||||
}
|
||||
|
||||
SysprofVisualizerGroup {
|
||||
border-bottom: 1px solid @borders;
|
||||
}
|
||||
SysprofVisualizerGroup:last-child {
|
||||
box-shadow: 0 20px 15px 15px alpha(@borders, 0.3);
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame box.horizontal.inline-toolbar {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame viewport.visualizers {
|
||||
border-right: 1px solid @borders;
|
||||
box-shadow: 1px 1px 3px alpha(@borders, 0.5);
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame scrollbar.horizontal {
|
||||
color: mix(@theme_fg_color, @theme_selected_bg_color, 0.5);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame scrollbar.horizontal range trough {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame scrollbar.horizontal range trough slider {
|
||||
margin-left: 1px;
|
||||
margin-right: 1px;
|
||||
padding: 6px;
|
||||
min-height: 14px;
|
||||
background: alpha(@content_view_bg, 0.2);
|
||||
border-radius: 3px;
|
||||
border: 2px solid @theme_selected_bg_color;
|
||||
box-shadow: inset 0 10px 5px alpha(@content_view_bg,.3),
|
||||
inset 0 -15px 5px alpha(@content_view_bg,.1),
|
||||
0px 2px 4px @borders;
|
||||
}
|
||||
|
||||
SysprofVisualizerTicks {
|
||||
color: mix(@theme_fg_color, @borders, 0.5);
|
||||
background-color: @content_view_bg;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame list {
|
||||
background-color: @theme_bg_color;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame list.visualizer-groups row {
|
||||
padding: 0;
|
||||
border-bottom: 1px solid @borders;
|
||||
}
|
||||
SysprofVisualizersFrame list.visualizer-groups row:not(:selected) {
|
||||
background-color: @theme_bg_color;
|
||||
}
|
||||
SysprofVisualizersFrame list.visualizer-groups row:last-child {
|
||||
box-shadow: 0 20px 15px 15px alpha(@borders, 0.3);
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame .left-column .small-button.flat {
|
||||
border-color: transparent;
|
||||
min-height: 8px;
|
||||
min-width: 8px;
|
||||
}
|
||||
SysprofVisualizersFrame .left-column .small-button.flat:checked,
|
||||
SysprofVisualizersFrame .left-column .small-button.flat:hover {
|
||||
border-color: @borders;
|
||||
}
|
||||
|
||||
SysprofVisualizersFrame .selection {
|
||||
border-radius: 3px;
|
||||
background-color: alpha(@theme_selected_bg_color, 0.35);
|
||||
box-shadow: inset 0 10px 5px alpha(@content_view_bg,.3),
|
||||
inset 0 -15px 5px alpha(@content_view_bg,.1),
|
||||
inset 0 0 1px 1px @theme_selected_bg_color;
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
list.environ-editor row button.flat:last-child {
|
||||
min-height: 16px;
|
||||
min-width: 16px;
|
||||
padding: 0;
|
||||
margin: 3px;
|
||||
}
|
||||
list.environ-editor row button.flat:not(:hover) {
|
||||
border-color: transparent;
|
||||
}
|
||||
list.environ-editor row button.flat image {
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
sysprofaidicon image.right.top {
|
||||
border-radius: 9999px;
|
||||
background-color: @theme_selected_bg_color;
|
||||
color: @theme_selected_fg_color;
|
||||
padding: 2px;
|
||||
margin: 0px;
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
/* egg-handle.h
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EGG_TYPE_HANDLE (egg_handle_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (EggHandle, egg_handle, EGG, HANDLE, GtkWidget)
|
||||
|
||||
GtkWidget *egg_handle_new (GtkPositionType position);
|
||||
void egg_handle_set_position (EggHandle *self,
|
||||
GtkPositionType position);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,145 +0,0 @@
|
||||
/* egg-handle.c
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "egg-handle-private.h"
|
||||
|
||||
#define EXTRA_SIZE 8
|
||||
|
||||
struct _EggHandle
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
GtkWidget *separator;
|
||||
GtkPositionType position : 3;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (EggHandle, egg_handle, GTK_TYPE_WIDGET)
|
||||
|
||||
static gboolean
|
||||
egg_handle_contains (GtkWidget *widget,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
EggHandle *self = (EggHandle *)widget;
|
||||
graphene_rect_t area;
|
||||
|
||||
g_assert (EGG_IS_HANDLE (self));
|
||||
|
||||
if (!gtk_widget_compute_bounds (GTK_WIDGET (self->separator),
|
||||
GTK_WIDGET (self),
|
||||
&area))
|
||||
return FALSE;
|
||||
|
||||
switch (self->position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
area.origin.x -= EXTRA_SIZE;
|
||||
area.size.width = EXTRA_SIZE;
|
||||
break;
|
||||
|
||||
case GTK_POS_RIGHT:
|
||||
area.size.width = EXTRA_SIZE;
|
||||
break;
|
||||
|
||||
case GTK_POS_TOP:
|
||||
area.origin.y -= EXTRA_SIZE;
|
||||
area.size.height = EXTRA_SIZE;
|
||||
break;
|
||||
|
||||
case GTK_POS_BOTTOM:
|
||||
area.size.height = EXTRA_SIZE;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return graphene_rect_contains_point (&area, &GRAPHENE_POINT_INIT (x, y));
|
||||
}
|
||||
|
||||
static void
|
||||
egg_handle_dispose (GObject *object)
|
||||
{
|
||||
EggHandle *self = (EggHandle *)object;
|
||||
|
||||
g_clear_pointer (&self->separator, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (egg_handle_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_handle_class_init (EggHandleClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = egg_handle_dispose;
|
||||
|
||||
widget_class->contains = egg_handle_contains;
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_handle_init (EggHandle *self)
|
||||
{
|
||||
self->separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_widget_set_parent (GTK_WIDGET (self->separator), GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
egg_handle_set_position (EggHandle *self,
|
||||
GtkPositionType position)
|
||||
{
|
||||
g_return_if_fail (EGG_IS_HANDLE (self));
|
||||
|
||||
self->position = position;
|
||||
|
||||
switch (position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
case GTK_POS_RIGHT:
|
||||
gtk_widget_set_cursor_from_name (GTK_WIDGET (self), "col-resize");
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (self->separator), GTK_ORIENTATION_VERTICAL);
|
||||
break;
|
||||
|
||||
case GTK_POS_TOP:
|
||||
case GTK_POS_BOTTOM:
|
||||
gtk_widget_set_cursor_from_name (GTK_WIDGET (self), "row-resize");
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (self->separator), GTK_ORIENTATION_HORIZONTAL);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
egg_handle_new (GtkPositionType position)
|
||||
{
|
||||
EggHandle *self;
|
||||
|
||||
self = g_object_new (EGG_TYPE_HANDLE, NULL);
|
||||
egg_handle_set_position (self, position);
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
/* egg-paned.h
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EGG_TYPE_PANED (egg_paned_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (EggPaned, egg_paned, EGG, PANED, GtkWidget)
|
||||
|
||||
GtkWidget *egg_paned_new (void);
|
||||
void egg_paned_append (EggPaned *self,
|
||||
GtkWidget *child);
|
||||
void egg_paned_prepend (EggPaned *self,
|
||||
GtkWidget *child);
|
||||
void egg_paned_insert (EggPaned *self,
|
||||
int position,
|
||||
GtkWidget *child);
|
||||
void egg_paned_insert_after (EggPaned *self,
|
||||
GtkWidget *child,
|
||||
GtkWidget *sibling);
|
||||
void egg_paned_remove (EggPaned *self,
|
||||
GtkWidget *child);
|
||||
guint egg_paned_get_n_children (EggPaned *self);
|
||||
GtkWidget *egg_paned_get_nth_child (EggPaned *self,
|
||||
guint nth);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,593 +0,0 @@
|
||||
/* egg-paned.c
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "egg-paned-private.h"
|
||||
#include "egg-resizer-private.h"
|
||||
|
||||
struct _EggPaned
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
GtkOrientation orientation;
|
||||
};
|
||||
|
||||
static void buildable_iface_init (GtkBuildableIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (EggPaned, egg_paned, GTK_TYPE_WIDGET,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
N_PROPS,
|
||||
|
||||
PROP_ORIENTATION,
|
||||
};
|
||||
|
||||
static void
|
||||
update_orientation (GtkWidget *widget,
|
||||
GtkOrientation orientation)
|
||||
{
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
gtk_widget_remove_css_class (widget, "vertical");
|
||||
gtk_widget_add_css_class (widget, "horizontal");
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_remove_css_class (widget, "horizontal");
|
||||
gtk_widget_add_css_class (widget, "vertical");
|
||||
}
|
||||
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (widget),
|
||||
GTK_ACCESSIBLE_PROPERTY_ORIENTATION, orientation,
|
||||
-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_paned_new:
|
||||
*
|
||||
* Create a new #EggPaned.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #EggPaned
|
||||
*/
|
||||
GtkWidget *
|
||||
egg_paned_new (void)
|
||||
{
|
||||
return g_object_new (EGG_TYPE_PANED, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_set_orientation (EggPaned *self,
|
||||
GtkOrientation orientation)
|
||||
{
|
||||
GtkPositionType pos;
|
||||
|
||||
g_assert (EGG_IS_PANED (self));
|
||||
g_assert (orientation == GTK_ORIENTATION_HORIZONTAL ||
|
||||
orientation == GTK_ORIENTATION_VERTICAL);
|
||||
|
||||
if (self->orientation == orientation)
|
||||
return;
|
||||
|
||||
self->orientation = orientation;
|
||||
|
||||
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
pos = GTK_POS_LEFT;
|
||||
else
|
||||
pos = GTK_POS_TOP;
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_last_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_prev_sibling (child))
|
||||
{
|
||||
g_assert (EGG_IS_RESIZER (child));
|
||||
|
||||
egg_resizer_set_position (EGG_RESIZER (child), pos);
|
||||
}
|
||||
|
||||
update_orientation (GTK_WIDGET (self), self->orientation);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
g_object_notify (G_OBJECT (self), "orientation");
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
EggPaned *self = (EggPaned *)widget;
|
||||
|
||||
g_assert (EGG_IS_PANED (self));
|
||||
|
||||
*minimum = 0;
|
||||
*natural = 0;
|
||||
*minimum_baseline = -1;
|
||||
*natural_baseline = -1;
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
int child_min, child_nat;
|
||||
|
||||
gtk_widget_measure (child, orientation, for_size, &child_min, &child_nat, NULL, NULL);
|
||||
|
||||
if (orientation == self->orientation)
|
||||
{
|
||||
*minimum += child_min;
|
||||
*natural += child_nat;
|
||||
}
|
||||
else
|
||||
{
|
||||
*minimum = MAX (*minimum, child_min);
|
||||
*natural = MAX (*natural, child_nat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GtkRequisition min_request;
|
||||
GtkRequisition nat_request;
|
||||
GtkAllocation alloc;
|
||||
} ChildAllocation;
|
||||
|
||||
static void
|
||||
egg_paned_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
EggPaned *self = (EggPaned *)widget;
|
||||
ChildAllocation *allocs;
|
||||
ChildAllocation *last_alloc = NULL;
|
||||
GtkOrientation orientation;
|
||||
guint n_children = 0;
|
||||
guint n_expand = 0;
|
||||
guint i;
|
||||
int extra_width = width;
|
||||
int extra_height = height;
|
||||
int expand_width;
|
||||
int expand_height;
|
||||
int x, y;
|
||||
|
||||
g_assert (EGG_IS_PANED (self));
|
||||
|
||||
GTK_WIDGET_CLASS (egg_paned_parent_class)->size_allocate (widget, width, height, baseline);
|
||||
|
||||
n_children = egg_paned_get_n_children (self);
|
||||
|
||||
if (n_children == 1)
|
||||
{
|
||||
GtkWidget *child = gtk_widget_get_first_child (widget);
|
||||
GtkAllocation alloc = { 0, 0, width, height };
|
||||
|
||||
if (gtk_widget_get_visible (child))
|
||||
{
|
||||
gtk_widget_size_allocate (child, &alloc, -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (self));
|
||||
allocs = g_newa (ChildAllocation, n_children);
|
||||
memset (allocs, 0, sizeof *allocs * n_children);
|
||||
|
||||
/* Give min size to each of the children */
|
||||
i = 0;
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child), i++)
|
||||
{
|
||||
ChildAllocation *child_alloc = &allocs[i];
|
||||
|
||||
if (!gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
gtk_widget_measure (child, GTK_ORIENTATION_HORIZONTAL, height,
|
||||
&child_alloc->min_request.width,
|
||||
&child_alloc->nat_request.width,
|
||||
NULL, NULL);
|
||||
gtk_widget_measure (child, GTK_ORIENTATION_VERTICAL, width,
|
||||
&child_alloc->min_request.height,
|
||||
&child_alloc->nat_request.height,
|
||||
NULL, NULL);
|
||||
|
||||
child_alloc->alloc.width = child_alloc->min_request.width;
|
||||
child_alloc->alloc.height = child_alloc->min_request.height;
|
||||
|
||||
n_expand += gtk_widget_compute_expand (child, orientation);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
extra_width -= child_alloc->alloc.width;
|
||||
child_alloc->alloc.height = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra_height -= child_alloc->alloc.height;
|
||||
child_alloc->alloc.width = width;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now try to distribute extra space for natural size */
|
||||
i = 0;
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child), i++)
|
||||
{
|
||||
ChildAllocation *child_alloc = &allocs[i];
|
||||
|
||||
if (!gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
int taken = MIN (extra_width, child_alloc->nat_request.width - child_alloc->alloc.width);
|
||||
|
||||
if (taken > 0)
|
||||
{
|
||||
child_alloc->alloc.width += taken;
|
||||
extra_width -= taken;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int taken = MIN (extra_height, child_alloc->nat_request.height - child_alloc->alloc.height);
|
||||
|
||||
if (taken > 0)
|
||||
{
|
||||
child_alloc->alloc.height += taken;
|
||||
extra_height -= taken;
|
||||
}
|
||||
}
|
||||
|
||||
last_alloc = child_alloc;
|
||||
}
|
||||
|
||||
/* Now give extra space for those that expand */
|
||||
expand_width = n_expand ? extra_width / n_expand : 0;
|
||||
expand_height = n_expand ? extra_height / n_expand : 0;
|
||||
i = n_children;
|
||||
for (GtkWidget *child = gtk_widget_get_last_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_prev_sibling (child), i--)
|
||||
{
|
||||
ChildAllocation *child_alloc = &allocs[i-1];
|
||||
|
||||
if (!gtk_widget_get_visible (child))
|
||||
continue;
|
||||
|
||||
if (!gtk_widget_compute_expand (child, orientation))
|
||||
continue;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
child_alloc->alloc.width += expand_width;
|
||||
extra_width -= expand_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
child_alloc->alloc.height += expand_height;
|
||||
extra_height -= expand_height;
|
||||
}
|
||||
}
|
||||
|
||||
/* Give any leftover to the last visible child */
|
||||
if (last_alloc)
|
||||
{
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
last_alloc->alloc.width += extra_width;
|
||||
else
|
||||
last_alloc->alloc.height += extra_height;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
x = 0;
|
||||
y = 0;
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child), i++)
|
||||
{
|
||||
ChildAllocation *child_alloc = &allocs[i];
|
||||
|
||||
child_alloc->alloc.x = x;
|
||||
child_alloc->alloc.y = y;
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
x += child_alloc->alloc.width;
|
||||
else
|
||||
y += child_alloc->alloc.height;
|
||||
|
||||
gtk_widget_size_allocate (child, &child_alloc->alloc, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_dispose (GObject *object)
|
||||
{
|
||||
EggPaned *self = (EggPaned *)object;
|
||||
GtkWidget *child;
|
||||
|
||||
child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
while (child)
|
||||
{
|
||||
GtkWidget *next = gtk_widget_get_next_sibling (child);
|
||||
gtk_widget_unparent (child);
|
||||
child = next;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (egg_paned_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
EggPaned *self = EGG_PANED (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ORIENTATION:
|
||||
g_value_set_enum (value, self->orientation);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
EggPaned *self = EGG_PANED (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ORIENTATION:
|
||||
egg_paned_set_orientation (self, g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_class_init (EggPanedClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = egg_paned_dispose;
|
||||
object_class->get_property = egg_paned_get_property;
|
||||
object_class->set_property = egg_paned_set_property;
|
||||
|
||||
widget_class->measure = egg_paned_measure;
|
||||
widget_class->size_allocate = egg_paned_size_allocate;
|
||||
|
||||
g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "eggpaned");
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_init (EggPaned *self)
|
||||
{
|
||||
self->orientation = GTK_ORIENTATION_HORIZONTAL;
|
||||
|
||||
update_orientation (GTK_WIDGET (self), self->orientation);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_update_handles (EggPaned *self)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
g_assert (EGG_IS_PANED (self));
|
||||
|
||||
for (child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
GtkWidget *handle;
|
||||
|
||||
g_assert (EGG_IS_RESIZER (child));
|
||||
|
||||
if ((handle = egg_resizer_get_handle (EGG_RESIZER (child))))
|
||||
gtk_widget_show (handle);
|
||||
}
|
||||
|
||||
if ((child = gtk_widget_get_last_child (GTK_WIDGET (self))))
|
||||
{
|
||||
GtkWidget *handle = egg_resizer_get_handle (EGG_RESIZER (child));
|
||||
gtk_widget_hide (handle);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_remove (EggPaned *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
GtkWidget *resizer;
|
||||
|
||||
g_return_if_fail (EGG_IS_PANED (self));
|
||||
g_return_if_fail (GTK_IS_WIDGET (child));
|
||||
|
||||
resizer = gtk_widget_get_ancestor (child, EGG_TYPE_RESIZER);
|
||||
g_return_if_fail (resizer != NULL &&
|
||||
gtk_widget_get_parent (resizer) == GTK_WIDGET (self));
|
||||
gtk_widget_unparent (resizer);
|
||||
egg_paned_update_handles (self);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_insert (EggPaned *self,
|
||||
int position,
|
||||
GtkWidget *child)
|
||||
{
|
||||
GtkPositionType pos;
|
||||
GtkWidget *resizer;
|
||||
|
||||
g_return_if_fail (EGG_IS_PANED (self));
|
||||
g_return_if_fail (GTK_IS_WIDGET (child));
|
||||
g_return_if_fail (gtk_widget_get_parent (child) == NULL);
|
||||
|
||||
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
pos = GTK_POS_LEFT;
|
||||
else
|
||||
pos = GTK_POS_TOP;
|
||||
|
||||
resizer = egg_resizer_new (pos);
|
||||
egg_resizer_set_child (EGG_RESIZER (resizer), child);
|
||||
|
||||
if (position < 0)
|
||||
gtk_widget_insert_before (GTK_WIDGET (resizer), GTK_WIDGET (self), NULL);
|
||||
else if (position == 0)
|
||||
gtk_widget_insert_after (GTK_WIDGET (resizer), GTK_WIDGET (self), NULL);
|
||||
else
|
||||
{
|
||||
GtkWidget *sibling = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
|
||||
for (int i = position; i > 0 && sibling != NULL; i--)
|
||||
sibling = gtk_widget_get_next_sibling (sibling);
|
||||
|
||||
gtk_widget_insert_before (GTK_WIDGET (resizer), GTK_WIDGET (self), sibling);
|
||||
}
|
||||
|
||||
egg_paned_update_handles (self);
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_append (EggPaned *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
egg_paned_insert (self, -1, child);
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_prepend (EggPaned *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
egg_paned_insert (self, 0, child);
|
||||
}
|
||||
|
||||
void
|
||||
egg_paned_insert_after (EggPaned *self,
|
||||
GtkWidget *child,
|
||||
GtkWidget *sibling)
|
||||
{
|
||||
int position = 0;
|
||||
|
||||
g_return_if_fail (EGG_IS_PANED (self));
|
||||
g_return_if_fail (GTK_IS_WIDGET (child));
|
||||
g_return_if_fail (!sibling || GTK_IS_WIDGET (sibling));
|
||||
|
||||
if (sibling == NULL)
|
||||
{
|
||||
egg_paned_prepend (self, child);
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: We should reverse insert() to call this */
|
||||
|
||||
for (GtkWidget *ancestor = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
ancestor != NULL;
|
||||
ancestor = gtk_widget_get_next_sibling (ancestor))
|
||||
{
|
||||
position++;
|
||||
|
||||
if (sibling == ancestor || gtk_widget_is_ancestor (sibling, ancestor))
|
||||
break;
|
||||
}
|
||||
|
||||
egg_paned_insert (self, position, child);
|
||||
}
|
||||
|
||||
guint
|
||||
egg_paned_get_n_children (EggPaned *self)
|
||||
{
|
||||
guint count = 0;
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
egg_paned_get_nth_child (EggPaned *self,
|
||||
guint nth)
|
||||
{
|
||||
g_return_val_if_fail (EGG_IS_PANED (self), NULL);
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
g_assert (EGG_IS_RESIZER (child));
|
||||
|
||||
if (nth == 0)
|
||||
return egg_resizer_get_child (EGG_RESIZER (child));
|
||||
|
||||
nth--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
egg_paned_add_child (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
GObject *child,
|
||||
const char *type)
|
||||
{
|
||||
if (GTK_IS_WIDGET (child))
|
||||
egg_paned_append (EGG_PANED (buildable), GTK_WIDGET (child));
|
||||
else
|
||||
g_warning ("Cannot add child of type %s to %s",
|
||||
G_OBJECT_TYPE_NAME (child),
|
||||
G_OBJECT_TYPE_NAME (buildable));
|
||||
}
|
||||
|
||||
static void
|
||||
buildable_iface_init (GtkBuildableIface *iface)
|
||||
{
|
||||
iface->add_child = egg_paned_add_child;
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
/* egg-resizer.h
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EGG_TYPE_RESIZER (egg_resizer_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (EggResizer, egg_resizer, EGG, RESIZER, GtkWidget)
|
||||
|
||||
GtkWidget *egg_resizer_new (GtkPositionType position);
|
||||
GtkPositionType egg_resizer_get_position (EggResizer *self);
|
||||
void egg_resizer_set_position (EggResizer *self,
|
||||
GtkPositionType position);
|
||||
GtkWidget *egg_resizer_get_child (EggResizer *self);
|
||||
void egg_resizer_set_child (EggResizer *self,
|
||||
GtkWidget *child);
|
||||
GtkWidget *egg_resizer_get_handle (EggResizer *self);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,495 +0,0 @@
|
||||
/* egg-resizer.c
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation; either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 Lesser 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: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "egg-handle-private.h"
|
||||
#include "egg-resizer-private.h"
|
||||
|
||||
#define HANDLE_SIZE 8
|
||||
|
||||
struct _EggResizer
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
EggHandle *handle;
|
||||
GtkWidget *child;
|
||||
|
||||
double drag_orig_size;
|
||||
double drag_position;
|
||||
|
||||
GtkPositionType position : 3;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (EggResizer, egg_resizer, GTK_TYPE_WIDGET)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CHILD,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
egg_resizer_drag_begin_cb (EggResizer *self,
|
||||
double start_x,
|
||||
double start_y,
|
||||
GtkGestureDrag *drag)
|
||||
{
|
||||
GtkAllocation child_alloc;
|
||||
GtkAllocation handle_alloc;
|
||||
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
g_assert (GTK_IS_GESTURE_DRAG (drag));
|
||||
|
||||
if (self->child == NULL)
|
||||
return;
|
||||
|
||||
switch (self->position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
if (start_x > gtk_widget_get_width (GTK_WIDGET (self)) - HANDLE_SIZE)
|
||||
goto start_drag;
|
||||
break;
|
||||
|
||||
case GTK_POS_RIGHT:
|
||||
if (start_x <= HANDLE_SIZE)
|
||||
goto start_drag;
|
||||
break;
|
||||
|
||||
case GTK_POS_TOP:
|
||||
if (start_y > gtk_widget_get_height (GTK_WIDGET (self)) - HANDLE_SIZE)
|
||||
goto start_drag;
|
||||
break;
|
||||
|
||||
case GTK_POS_BOTTOM:
|
||||
if (start_y <= HANDLE_SIZE)
|
||||
goto start_drag;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (drag),
|
||||
GTK_EVENT_SEQUENCE_DENIED);
|
||||
|
||||
return;
|
||||
|
||||
start_drag:
|
||||
|
||||
gtk_widget_get_allocation (self->child, &child_alloc);
|
||||
gtk_widget_get_allocation (GTK_WIDGET (self->handle), &handle_alloc);
|
||||
|
||||
if (self->position == GTK_POS_LEFT ||
|
||||
self->position == GTK_POS_RIGHT)
|
||||
{
|
||||
self->drag_orig_size = child_alloc.width + handle_alloc.width;
|
||||
gtk_widget_set_hexpand (self->child, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->drag_orig_size = child_alloc.height + handle_alloc.height;
|
||||
gtk_widget_set_vexpand (self->child, FALSE);
|
||||
}
|
||||
|
||||
self->drag_position = self->drag_orig_size;
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_drag_update_cb (EggResizer *self,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkGestureDrag *drag)
|
||||
{
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
g_assert (GTK_IS_GESTURE_DRAG (drag));
|
||||
|
||||
if (self->position == GTK_POS_LEFT)
|
||||
self->drag_position = self->drag_orig_size + offset_x;
|
||||
else if (self->position == GTK_POS_RIGHT)
|
||||
self->drag_position = gtk_widget_get_width (GTK_WIDGET (self)) - offset_x;
|
||||
else if (self->position == GTK_POS_TOP)
|
||||
self->drag_position = self->drag_orig_size + offset_y;
|
||||
else if (self->position == GTK_POS_BOTTOM)
|
||||
self->drag_position = gtk_widget_get_height (GTK_WIDGET (self)) - offset_y;
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_drag_end_cb (EggResizer *self,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkGestureDrag *drag)
|
||||
{
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
g_assert (GTK_IS_GESTURE_DRAG (drag));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
egg_resizer_new (GtkPositionType position)
|
||||
{
|
||||
EggResizer *self;
|
||||
|
||||
self = g_object_new (EGG_TYPE_RESIZER, NULL);
|
||||
self->position = position;
|
||||
self->handle = EGG_HANDLE (egg_handle_new (position));
|
||||
gtk_widget_set_parent (GTK_WIDGET (self->handle), GTK_WIDGET (self));
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
EggResizer *self = (EggResizer *)widget;
|
||||
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
|
||||
*minimum = 0;
|
||||
*natural = 0;
|
||||
*minimum_baseline = -1;
|
||||
*natural_baseline = -1;
|
||||
|
||||
if (self->child != NULL)
|
||||
gtk_widget_measure (self->child,
|
||||
orientation,
|
||||
for_size,
|
||||
minimum, natural,
|
||||
NULL, NULL);
|
||||
|
||||
if ((orientation == GTK_ORIENTATION_HORIZONTAL &&
|
||||
(self->position == GTK_POS_LEFT ||
|
||||
self->position == GTK_POS_RIGHT)) ||
|
||||
(orientation == GTK_ORIENTATION_VERTICAL &&
|
||||
(self->position == GTK_POS_TOP ||
|
||||
self->position == GTK_POS_BOTTOM)))
|
||||
{
|
||||
int handle_min, handle_nat;
|
||||
|
||||
if (self->drag_position != 0)
|
||||
{
|
||||
if (self->drag_position > *minimum)
|
||||
*natural = self->drag_position;
|
||||
else if (self->drag_position < *minimum)
|
||||
*natural = *minimum;
|
||||
}
|
||||
|
||||
if (gtk_widget_get_visible (GTK_WIDGET (self->handle)))
|
||||
{
|
||||
gtk_widget_measure (GTK_WIDGET (self->handle),
|
||||
orientation, for_size,
|
||||
&handle_min, &handle_nat,
|
||||
NULL, NULL);
|
||||
|
||||
*minimum += handle_min;
|
||||
*natural += handle_nat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
EggResizer *self = (EggResizer *)widget;
|
||||
GtkOrientation orientation;
|
||||
GtkAllocation child_alloc;
|
||||
GtkAllocation handle_alloc;
|
||||
int handle_min = 0, handle_nat = 0;
|
||||
|
||||
g_assert (EGG_IS_RESIZER (self));
|
||||
|
||||
if (self->position == GTK_POS_LEFT ||
|
||||
self->position == GTK_POS_RIGHT)
|
||||
orientation = GTK_ORIENTATION_HORIZONTAL;
|
||||
else
|
||||
orientation = GTK_ORIENTATION_VERTICAL;
|
||||
|
||||
if (gtk_widget_get_visible (GTK_WIDGET (self->handle)))
|
||||
gtk_widget_measure (GTK_WIDGET (self->handle),
|
||||
orientation,
|
||||
-1,
|
||||
&handle_min, &handle_nat,
|
||||
NULL, NULL);
|
||||
|
||||
switch (self->position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
handle_alloc.x = width - handle_min;
|
||||
handle_alloc.width = handle_min;
|
||||
handle_alloc.y = 0;
|
||||
handle_alloc.height = height;
|
||||
child_alloc.x = 0;
|
||||
child_alloc.y = 0;
|
||||
child_alloc.width = width - handle_min;
|
||||
child_alloc.height = height;
|
||||
break;
|
||||
|
||||
case GTK_POS_RIGHT:
|
||||
handle_alloc.x = 0;
|
||||
handle_alloc.width = handle_min;
|
||||
handle_alloc.y = 0;
|
||||
handle_alloc.height = height;
|
||||
child_alloc.x = handle_min;
|
||||
child_alloc.y = 0;
|
||||
child_alloc.width = width - handle_min;
|
||||
child_alloc.height = height;
|
||||
break;
|
||||
|
||||
case GTK_POS_TOP:
|
||||
handle_alloc.x = 0;
|
||||
handle_alloc.width = width;
|
||||
handle_alloc.y = height - handle_min;
|
||||
handle_alloc.height = handle_min;
|
||||
child_alloc.x = 0;
|
||||
child_alloc.y = 0;
|
||||
child_alloc.width = width;
|
||||
child_alloc.height = height - handle_min;
|
||||
break;
|
||||
|
||||
case GTK_POS_BOTTOM:
|
||||
handle_alloc.x = 0;
|
||||
handle_alloc.width = width;
|
||||
handle_alloc.y = 0;
|
||||
handle_alloc.height = handle_min;
|
||||
child_alloc.x = 0;
|
||||
child_alloc.y = handle_min;
|
||||
child_alloc.width = width;
|
||||
child_alloc.height = height - handle_min;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
if (gtk_widget_get_mapped (GTK_WIDGET (self->handle)))
|
||||
gtk_widget_size_allocate (GTK_WIDGET (self->handle), &handle_alloc, -1);
|
||||
|
||||
if (self->child != NULL &&
|
||||
gtk_widget_get_mapped (self->child))
|
||||
gtk_widget_size_allocate (self->child, &child_alloc, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_compute_expand (GtkWidget *widget,
|
||||
gboolean *hexpand,
|
||||
gboolean *vexpand)
|
||||
{
|
||||
EggResizer *self = EGG_RESIZER (widget);
|
||||
|
||||
if (self->child != NULL)
|
||||
{
|
||||
*hexpand = gtk_widget_compute_expand (self->child, GTK_ORIENTATION_HORIZONTAL);
|
||||
*vexpand = gtk_widget_compute_expand (self->child, GTK_ORIENTATION_VERTICAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
*hexpand = FALSE;
|
||||
*vexpand = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_dispose (GObject *object)
|
||||
{
|
||||
EggResizer *self = (EggResizer *)object;
|
||||
|
||||
if (self->handle)
|
||||
gtk_widget_unparent (GTK_WIDGET (self->handle));
|
||||
self->handle = NULL;
|
||||
|
||||
if (self->child)
|
||||
gtk_widget_unparent (self->child);
|
||||
self->child = NULL;
|
||||
|
||||
G_OBJECT_CLASS (egg_resizer_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
EggResizer *self = EGG_RESIZER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CHILD:
|
||||
g_value_set_object (value, egg_resizer_get_child (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
EggResizer *self = EGG_RESIZER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CHILD:
|
||||
egg_resizer_set_child (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_class_init (EggResizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = egg_resizer_dispose;
|
||||
object_class->get_property = egg_resizer_get_property;
|
||||
object_class->set_property = egg_resizer_set_property;
|
||||
|
||||
widget_class->compute_expand = egg_resizer_compute_expand;
|
||||
widget_class->measure = egg_resizer_measure;
|
||||
widget_class->size_allocate = egg_resizer_size_allocate;
|
||||
|
||||
properties [PROP_CHILD] =
|
||||
g_param_spec_object ("child",
|
||||
"Child",
|
||||
"Child",
|
||||
GTK_TYPE_WIDGET,
|
||||
(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_css_name (widget_class, "eggresizer");
|
||||
}
|
||||
|
||||
static void
|
||||
egg_resizer_init (EggResizer *self)
|
||||
{
|
||||
GtkGesture *gesture;
|
||||
|
||||
gesture = gtk_gesture_drag_new ();
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), GTK_PHASE_CAPTURE);
|
||||
g_signal_connect_object (gesture,
|
||||
"drag-begin",
|
||||
G_CALLBACK (egg_resizer_drag_begin_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_signal_connect_object (gesture,
|
||||
"drag-update",
|
||||
G_CALLBACK (egg_resizer_drag_update_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_signal_connect_object (gesture,
|
||||
"drag-end",
|
||||
G_CALLBACK (egg_resizer_drag_end_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
|
||||
}
|
||||
|
||||
/**
|
||||
* egg_resizer_get_child:
|
||||
* @self: a #EggResizer
|
||||
*
|
||||
* Gets the child widget of the resizer.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): A #GtkWidget or %NULL
|
||||
*/
|
||||
GtkWidget *
|
||||
egg_resizer_get_child (EggResizer *self)
|
||||
{
|
||||
g_return_val_if_fail (EGG_IS_RESIZER (self), NULL);
|
||||
|
||||
return self->child;
|
||||
}
|
||||
|
||||
void
|
||||
egg_resizer_set_child (EggResizer *self,
|
||||
GtkWidget *child)
|
||||
{
|
||||
g_return_if_fail (EGG_IS_RESIZER (self));
|
||||
g_return_if_fail (!child || GTK_IS_WIDGET (child));
|
||||
|
||||
if (child == self->child)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&self->child, gtk_widget_unparent);
|
||||
|
||||
self->child = child;
|
||||
|
||||
if (self->child != NULL)
|
||||
gtk_widget_insert_before (self->child,
|
||||
GTK_WIDGET (self),
|
||||
GTK_WIDGET (self->handle));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CHILD]);
|
||||
}
|
||||
|
||||
GtkPositionType
|
||||
egg_resizer_get_position (EggResizer *self)
|
||||
{
|
||||
g_return_val_if_fail (EGG_IS_RESIZER (self), 0);
|
||||
|
||||
return self->position;
|
||||
}
|
||||
|
||||
void
|
||||
egg_resizer_set_position (EggResizer *self,
|
||||
GtkPositionType position)
|
||||
{
|
||||
g_return_if_fail (EGG_IS_RESIZER (self));
|
||||
|
||||
if (position != self->position)
|
||||
{
|
||||
self->position = position;
|
||||
|
||||
egg_handle_set_position (self->handle, position);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
egg_resizer_get_handle (EggResizer *self)
|
||||
{
|
||||
g_return_val_if_fail (EGG_IS_RESIZER (self), NULL);
|
||||
|
||||
return GTK_WIDGET (self->handle);
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/sysprof">
|
||||
<file compressed="true">css/SysprofEnvironEditor-shared.css</file>
|
||||
<file compressed="true">css/SysprofDisplay-shared.css</file>
|
||||
<file compressed="true">css/SysprofProfilerAssistant-shared.css</file>
|
||||
|
||||
<!-- Application icons -->
|
||||
<file alias="icons/scalable/apps/org.gnome.Sysprof.svg">../../data/icons/org.gnome.Sysprof.svg</file>
|
||||
<file alias="icons/scalable/apps/org.gnome.Sysprof-symbolic.svg">../../data/icons/symbolic/apps/org.gnome.Sysprof-symbolic.svg</file>
|
||||
<file alias="icons/symbolic/apps/org.gnome.Sysprof-symbolic.svg">../../data/icons/symbolic/apps/org.gnome.Sysprof-symbolic.svg</file>
|
||||
</gresource>
|
||||
|
||||
<gresource prefix="/org/gnome/sysprof/ui">
|
||||
<file preprocess="xml-stripblanks">sysprof-aid-icon.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-callgraph-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-details-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-display.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-environ-editor-row.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-failed-state-view.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-logs-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-marks-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-memprof-page.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-process-model-row.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-profiler-assistant.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-recording-state-view.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-tab.ui</file>
|
||||
<file preprocess="xml-stripblanks">sysprof-visualizers-frame.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
@ -1,136 +0,0 @@
|
||||
libsysprof_ui_public_sources = [
|
||||
'sysprof-check.c',
|
||||
'sysprof-display.c',
|
||||
'sysprof-model-filter.c',
|
||||
'sysprof-notebook.c',
|
||||
'sysprof-page.c',
|
||||
'sysprof-process-model-row.c',
|
||||
'sysprof-visualizer.c',
|
||||
'sysprof-visualizer-group.c',
|
||||
'sysprof-zoom-manager.c',
|
||||
]
|
||||
|
||||
libsysprof_ui_private_sources = [
|
||||
'egg-handle.c',
|
||||
'egg-paned.c',
|
||||
'egg-resizer.c',
|
||||
|
||||
'pointcache.c',
|
||||
'rectangles.c',
|
||||
'sysprof-aid.c',
|
||||
'sysprof-aid-icon.c',
|
||||
'sysprof-battery-aid.c',
|
||||
'sysprof-cairo.c',
|
||||
'sysprof-callgraph-aid.c',
|
||||
'sysprof-callgraph-page.c',
|
||||
'sysprof-cell-renderer-duration.c',
|
||||
'sysprof-cell-renderer-percent.c',
|
||||
'sysprof-cell-renderer-progress.c',
|
||||
'sysprof-color-cycle.c',
|
||||
'sysprof-counters-aid.c',
|
||||
'sysprof-cpu-aid.c',
|
||||
'sysprof-depth-visualizer.c',
|
||||
'sysprof-details-page.c',
|
||||
'sysprof-diskstat-aid.c',
|
||||
'sysprof-display.c',
|
||||
'sysprof-duplex-visualizer.c',
|
||||
'sysprof-environ.c',
|
||||
'sysprof-environ-editor.c',
|
||||
'sysprof-environ-editor-row.c',
|
||||
'sysprof-environ-variable.c',
|
||||
'sysprof-failed-state-view.c',
|
||||
'sysprof-line-visualizer.c',
|
||||
'sysprof-log-model.c',
|
||||
'sysprof-logs-aid.c',
|
||||
'sysprof-logs-page.c',
|
||||
'sysprof-mark-detail.c',
|
||||
'sysprof-marks-aid.c',
|
||||
'sysprof-marks-model.c',
|
||||
'sysprof-marks-page.c',
|
||||
'sysprof-mark-visualizer.c',
|
||||
'sysprof-memory-aid.c',
|
||||
'sysprof-memprof-aid.c',
|
||||
'sysprof-memprof-page.c',
|
||||
'sysprof-memprof-visualizer.c',
|
||||
'sysprof-netdev-aid.c',
|
||||
'sysprof-procs-visualizer.c',
|
||||
'sysprof-profiler-assistant.c',
|
||||
'sysprof-proxy-aid.c',
|
||||
'sysprof-rapl-aid.c',
|
||||
'sysprof-recording-state-view.c',
|
||||
'sysprof-scrollmap.c',
|
||||
'sysprof-tab.c',
|
||||
'sysprof-theme-manager.c',
|
||||
'sysprof-time-label.c',
|
||||
'sysprof-time-visualizer.c',
|
||||
'sysprof-visualizer-group-header.c',
|
||||
'sysprof-visualizers-frame.c',
|
||||
'sysprof-visualizer-ticks.c',
|
||||
'../stackstash.c',
|
||||
]
|
||||
|
||||
libsysprof_ui_public_headers = [
|
||||
'sysprof-check.h',
|
||||
'sysprof-display.h',
|
||||
'sysprof-model-filter.h',
|
||||
'sysprof-notebook.h',
|
||||
'sysprof-page.h',
|
||||
'sysprof-process-model-row.h',
|
||||
'sysprof-visualizer.h',
|
||||
'sysprof-visualizer-group.h',
|
||||
'sysprof-zoom-manager.h',
|
||||
'sysprof-ui.h',
|
||||
]
|
||||
|
||||
libsysprof_ui_resources = gnome.compile_resources(
|
||||
'libsysprof-ui-resources',
|
||||
'libsysprof-ui.gresource.xml',
|
||||
c_name: 'lisysprof_ui',
|
||||
)
|
||||
|
||||
# Subset of dependencies used in generating the pkg-config file
|
||||
libsysprof_ui_pkg_deps = [
|
||||
dependency('gio-2.0', version: glib_req_version),
|
||||
dependency('gtk4', version: gtk_req_version),
|
||||
dependency('libadwaita-1'),
|
||||
]
|
||||
|
||||
libsysprof_ui_deps = libsysprof_ui_pkg_deps + [
|
||||
libsysprof_dep,
|
||||
]
|
||||
|
||||
# Meson's pkgconfig module wants to see a library here, not an internal
|
||||
# dependency object
|
||||
libsysprof_ui_pkg_deps += libsysprof
|
||||
|
||||
libsysprof_ui = shared_library(
|
||||
'sysprof-ui-@0@'.format(libsysprof_ui_api_version),
|
||||
libsysprof_ui_public_sources + libsysprof_ui_private_sources + libsysprof_ui_resources,
|
||||
|
||||
dependencies: libsysprof_ui_deps + [librax_dep],
|
||||
install_dir: get_option('libdir'),
|
||||
install: true,
|
||||
c_args: [ '-DSYSPROF_UI_COMPILATION' ],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
)
|
||||
|
||||
libsysprof_ui_dep = declare_dependency(
|
||||
link_with: libsysprof_ui,
|
||||
dependencies: libsysprof_ui_deps,
|
||||
include_directories: include_directories('.'),
|
||||
)
|
||||
meson.override_dependency('sysprof-ui-@0@'.format(libsysprof_api_version), libsysprof_ui_dep)
|
||||
|
||||
pkgconfig.generate(
|
||||
libsysprof_ui,
|
||||
subdirs: [ sysprof_ui_header_subdir ],
|
||||
description: 'The UI library for GTK applications embedding sysprof',
|
||||
install_dir: join_paths(get_option('libdir'), 'pkgconfig'),
|
||||
requires: [ 'gio-2.0', 'gtk4' ],
|
||||
libraries_private: libsysprof_ui_pkg_deps,
|
||||
variables: [
|
||||
'datadir=' + datadir_for_pc_file,
|
||||
],
|
||||
)
|
||||
|
||||
install_headers(libsysprof_ui_public_headers, subdir: sysprof_ui_header_subdir)
|
||||
@ -1,116 +0,0 @@
|
||||
/* pointcache.c
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "pointcache"
|
||||
|
||||
#include "pointcache.h"
|
||||
|
||||
struct _PointCache
|
||||
{
|
||||
volatile gint ref_count;
|
||||
GHashTable *sets;
|
||||
};
|
||||
|
||||
static void
|
||||
point_cache_finalize (PointCache *self)
|
||||
{
|
||||
g_clear_pointer (&self->sets, g_hash_table_unref);
|
||||
g_slice_free (PointCache, self);
|
||||
}
|
||||
|
||||
PointCache *
|
||||
point_cache_ref (PointCache *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
g_return_val_if_fail (self->ref_count > 0, NULL);
|
||||
|
||||
g_atomic_int_inc (&self->ref_count);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
point_cache_unref (PointCache *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->ref_count > 0);
|
||||
|
||||
if (g_atomic_int_dec_and_test (&self->ref_count))
|
||||
point_cache_finalize (self);
|
||||
}
|
||||
|
||||
PointCache *
|
||||
point_cache_new (void)
|
||||
{
|
||||
PointCache *self;
|
||||
|
||||
self = g_slice_new0 (PointCache);
|
||||
self->ref_count = 1;
|
||||
self->sets = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_array_unref);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
point_cache_add_set (PointCache *self,
|
||||
guint set_id)
|
||||
{
|
||||
g_hash_table_insert (self->sets,
|
||||
GUINT_TO_POINTER (set_id),
|
||||
g_array_new (FALSE, FALSE, sizeof (Point)));
|
||||
}
|
||||
|
||||
gboolean
|
||||
point_cache_contains_set (PointCache *self,
|
||||
guint set_id)
|
||||
{
|
||||
return g_hash_table_contains (self->sets, GUINT_TO_POINTER (set_id));
|
||||
}
|
||||
|
||||
void
|
||||
point_cache_add_point_to_set (PointCache *self,
|
||||
guint set_id,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
GArray *ar;
|
||||
Point point = { x, y };
|
||||
|
||||
ar = g_hash_table_lookup (self->sets, GUINT_TO_POINTER (set_id));
|
||||
g_array_append_val (ar, point);
|
||||
}
|
||||
|
||||
const Point *
|
||||
point_cache_get_points (PointCache *self,
|
||||
guint set_id,
|
||||
guint *n_points)
|
||||
{
|
||||
GArray *ar;
|
||||
|
||||
*n_points = 0;
|
||||
|
||||
if ((ar = g_hash_table_lookup (self->sets, GUINT_TO_POINTER (set_id))))
|
||||
{
|
||||
*n_points = ar->len;
|
||||
return &g_array_index (ar, const Point, 0);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/* pointcache.h
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _PointCache PointCache;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
} Point;
|
||||
|
||||
PointCache *point_cache_new (void);
|
||||
PointCache *point_cache_ref (PointCache *self);
|
||||
void point_cache_unref (PointCache *self);
|
||||
void point_cache_add_set (PointCache *self,
|
||||
guint set_id);
|
||||
gboolean point_cache_contains_set (PointCache *self,
|
||||
guint set_id);
|
||||
void point_cache_add_point_to_set (PointCache *self,
|
||||
guint set_id,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
const Point *point_cache_get_points (PointCache *self,
|
||||
guint set_id,
|
||||
guint *n_points);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (PointCache, point_cache_unref)
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,248 +0,0 @@
|
||||
/* rectangles.c
|
||||
*
|
||||
* Copyright 2018-2019 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 "rectangles.h"
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-visualizer.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gchar *name;
|
||||
const gchar *message;
|
||||
gint64 begin;
|
||||
gint64 end;
|
||||
GdkRectangle area;
|
||||
} Rectangle;
|
||||
|
||||
struct _Rectangles
|
||||
{
|
||||
GStringChunk *strings;
|
||||
GArray *rectangles;
|
||||
GHashTable *y_indexes;
|
||||
GHashTable *colors;
|
||||
SysprofColorCycle *cycle;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
guint sorted : 1;
|
||||
};
|
||||
|
||||
Rectangles *
|
||||
rectangles_new (gint64 begin_time,
|
||||
gint64 end_time)
|
||||
{
|
||||
Rectangles *self;
|
||||
|
||||
self = g_slice_new0 (Rectangles);
|
||||
self->strings = g_string_chunk_new (4096);
|
||||
self->rectangles = g_array_new (FALSE, FALSE, sizeof (Rectangle));
|
||||
self->y_indexes = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
self->colors = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
|
||||
self->cycle = sysprof_color_cycle_new ();
|
||||
self->begin_time = begin_time;
|
||||
self->end_time = end_time;
|
||||
self->sorted = FALSE;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
rectangles_add (Rectangles *self,
|
||||
gint64 begin_time,
|
||||
gint64 end_time,
|
||||
const gchar *name,
|
||||
const gchar *message)
|
||||
{
|
||||
Rectangle rect = {0};
|
||||
|
||||
g_assert (self != NULL);
|
||||
|
||||
if (message != NULL)
|
||||
rect.message = g_string_chunk_insert_const (self->strings, message);
|
||||
|
||||
if (name != NULL)
|
||||
rect.name = g_string_chunk_insert_const (self->strings, name);
|
||||
|
||||
rect.begin = begin_time;
|
||||
rect.end = end_time;
|
||||
|
||||
if (rect.end == rect.begin)
|
||||
rect.area.width = 1;
|
||||
|
||||
g_array_append_val (self->rectangles, rect);
|
||||
|
||||
self->sorted = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
rectangles_free (Rectangles *self)
|
||||
{
|
||||
g_string_chunk_free (self->strings);
|
||||
g_array_unref (self->rectangles);
|
||||
g_hash_table_unref (self->colors);
|
||||
g_hash_table_unref (self->y_indexes);
|
||||
sysprof_color_cycle_unref (self->cycle);
|
||||
g_slice_free (Rectangles, self);
|
||||
}
|
||||
|
||||
static gint
|
||||
sort_rectangles (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const Rectangle *r1 = a;
|
||||
const Rectangle *r2 = b;
|
||||
gint64 r = r1->begin - r2->begin;
|
||||
if (r == 0)
|
||||
r = r1->end - r2->end;
|
||||
if (r > 0) return 1;
|
||||
else if (r < 0) return -1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rectangles_sort (Rectangles *self)
|
||||
{
|
||||
guint sequence = 0;
|
||||
|
||||
g_assert (self != NULL);
|
||||
|
||||
if (self->sorted)
|
||||
return;
|
||||
|
||||
g_array_sort (self->rectangles, sort_rectangles);
|
||||
|
||||
g_hash_table_remove_all (self->y_indexes);
|
||||
|
||||
for (guint i = 0; i < self->rectangles->len; i++)
|
||||
{
|
||||
const Rectangle *rect = &g_array_index (self->rectangles, Rectangle, i);
|
||||
|
||||
if (!g_hash_table_contains (self->y_indexes, rect->name))
|
||||
{
|
||||
GdkRGBA rgba;
|
||||
|
||||
sysprof_color_cycle_next (self->cycle, &rgba);
|
||||
g_hash_table_insert (self->y_indexes, (gchar *)rect->name, GUINT_TO_POINTER (++sequence));
|
||||
g_hash_table_insert (self->colors, (gchar *)rect->name, g_memdup2 (&rgba, sizeof rgba));
|
||||
}
|
||||
}
|
||||
|
||||
self->sorted = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
rectangles_draw (Rectangles *self,
|
||||
GtkWidget *row,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GtkAllocation alloc;
|
||||
gdouble range;
|
||||
guint ns;
|
||||
|
||||
g_assert (self != NULL);
|
||||
g_assert (SYSPROF_IS_VISUALIZER (row));
|
||||
g_assert (cr != NULL);
|
||||
|
||||
if (!self->sorted)
|
||||
rectangles_sort (self);
|
||||
|
||||
gtk_widget_get_allocation (row, &alloc);
|
||||
ns = g_hash_table_size (self->y_indexes);
|
||||
if (ns == 0 || alloc.height == 0)
|
||||
return;
|
||||
|
||||
range = self->end_time - self->begin_time;
|
||||
|
||||
for (guint i = 0; i < self->rectangles->len; i++)
|
||||
{
|
||||
Rectangle *rect = &g_array_index (self->rectangles, Rectangle, i);
|
||||
guint y_index = GPOINTER_TO_UINT (g_hash_table_lookup (self->y_indexes, rect->name));
|
||||
SysprofVisualizerRelativePoint in_points[2];
|
||||
SysprofVisualizerAbsolutePoint out_points[2];
|
||||
GdkRectangle r;
|
||||
GdkRGBA *rgba;
|
||||
|
||||
g_assert (y_index > 0);
|
||||
g_assert (y_index <= ns);
|
||||
|
||||
in_points[0].x = (rect->begin - self->begin_time) / range;
|
||||
in_points[0].y = (y_index - 1) / (gdouble)ns;
|
||||
in_points[1].x = (rect->end - self->begin_time) / range;
|
||||
in_points[1].y = 0;
|
||||
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (row),
|
||||
in_points, G_N_ELEMENTS (in_points),
|
||||
out_points, G_N_ELEMENTS (out_points));
|
||||
|
||||
r.height = alloc.height / (gdouble)ns;
|
||||
r.x = out_points[0].x;
|
||||
r.y = out_points[0].y - r.height;
|
||||
|
||||
if (rect->end <= rect->begin)
|
||||
r.width = 1;
|
||||
else
|
||||
r.width = MAX (1, out_points[1].x - out_points[0].x);
|
||||
|
||||
rect->area = r;
|
||||
|
||||
rgba = g_hash_table_lookup (self->colors, rect->name);
|
||||
|
||||
gdk_cairo_rectangle (cr, &r);
|
||||
gdk_cairo_set_source_rgba (cr, rgba);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rectangles_set_end_time (Rectangles *self,
|
||||
gint64 end_time)
|
||||
{
|
||||
/* We might not know the real end time until we've exhausted the stream */
|
||||
self->end_time = end_time;
|
||||
}
|
||||
|
||||
gboolean
|
||||
rectangles_query_tooltip (Rectangles *self,
|
||||
GtkTooltip *tooltip,
|
||||
const gchar *group,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
g_assert (self != NULL);
|
||||
g_assert (GTK_IS_TOOLTIP (tooltip));
|
||||
|
||||
/* TODO: Sort, binary search, etc. */
|
||||
|
||||
for (guint i = 0; i < self->rectangles->len; i++)
|
||||
{
|
||||
const Rectangle *r = &g_array_index (self->rectangles, Rectangle, i);
|
||||
|
||||
if (r->area.x <= x &&
|
||||
r->area.y <= y &&
|
||||
r->area.x + r->area.width >= x &&
|
||||
r->area.y + r->area.height >= y)
|
||||
{
|
||||
g_autofree gchar *text = g_strdup_printf ("%s:%s: %s", group, r->name, r->message);
|
||||
gtk_tooltip_set_text (tooltip, text);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
/* rectangles.h
|
||||
*
|
||||
* Copyright 2018-2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _Rectangles Rectangles;
|
||||
|
||||
Rectangles *rectangles_new (gint64 begin_time,
|
||||
gint64 end_time);
|
||||
void rectangles_free (Rectangles *self);
|
||||
void rectangles_draw (Rectangles *self,
|
||||
GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
void rectangles_add (Rectangles *self,
|
||||
gint64 begin_time,
|
||||
gint64 end_time,
|
||||
const gchar *name,
|
||||
const gchar *message);
|
||||
void rectangles_set_end_time (Rectangles *self,
|
||||
gint64 end_time);
|
||||
gboolean rectangles_query_tooltip (Rectangles *self,
|
||||
GtkTooltip *tooltip,
|
||||
const gchar *group,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,211 +0,0 @@
|
||||
/* sysprof-aid-icon.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-aid-icon"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-aid-icon.h"
|
||||
|
||||
struct _SysprofAidIcon
|
||||
{
|
||||
GtkFlowBoxChild parent_instance;
|
||||
|
||||
SysprofAid *aid;
|
||||
|
||||
/* Template Objects */
|
||||
GtkLabel *label;
|
||||
GtkImage *image;
|
||||
GtkImage *check;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofAidIcon, sysprof_aid_icon, GTK_TYPE_FLOW_BOX_CHILD)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_AID,
|
||||
PROP_SELECTED,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
/**
|
||||
* sysprof_aid_icon_new:
|
||||
*
|
||||
* Create a new #SysprofAidIcon.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofAidIcon
|
||||
*/
|
||||
GtkWidget *
|
||||
sysprof_aid_icon_new (SysprofAid *aid)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_AID (aid), NULL);
|
||||
|
||||
return g_object_new (SYSPROF_TYPE_AID_ICON,
|
||||
"aid", aid,
|
||||
NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_aid_icon_is_selected (SysprofAidIcon *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_AID_ICON (self), FALSE);
|
||||
|
||||
return gtk_widget_get_visible (GTK_WIDGET (self->check));
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_aid_icon_get_aid:
|
||||
*
|
||||
* Get the aid that is represented by the icon.
|
||||
*
|
||||
* Returns: (transfer none): a #SysprofAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_aid_icon_get_aid (SysprofAidIcon *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_AID_ICON (self), NULL);
|
||||
|
||||
return self->aid;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_set_aid (SysprofAidIcon *self,
|
||||
SysprofAid *aid)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_AID_ICON (self));
|
||||
g_return_if_fail (SYSPROF_IS_AID (aid));
|
||||
|
||||
if (g_set_object (&self->aid, aid))
|
||||
{
|
||||
GIcon *icon = sysprof_aid_get_icon (aid);
|
||||
const gchar *title = sysprof_aid_get_display_name (aid);
|
||||
|
||||
g_object_set (self->image, "gicon", icon, NULL);
|
||||
gtk_label_set_label (self->label, title);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_finalize (GObject *object)
|
||||
{
|
||||
SysprofAidIcon *self = (SysprofAidIcon *)object;
|
||||
|
||||
g_clear_object (&self->aid);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_aid_icon_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofAidIcon *self = SYSPROF_AID_ICON (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_AID:
|
||||
g_value_set_object (value, sysprof_aid_icon_get_aid (self));
|
||||
break;
|
||||
|
||||
case PROP_SELECTED:
|
||||
g_value_set_boolean (value, gtk_widget_get_visible (GTK_WIDGET (self->check)));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofAidIcon *self = SYSPROF_AID_ICON (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_AID:
|
||||
sysprof_aid_icon_set_aid (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_SELECTED:
|
||||
gtk_widget_set_visible (GTK_WIDGET (self->check), g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_class_init (SysprofAidIconClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_aid_icon_finalize;
|
||||
object_class->get_property = sysprof_aid_icon_get_property;
|
||||
object_class->set_property = sysprof_aid_icon_set_property;
|
||||
|
||||
properties [PROP_AID] =
|
||||
g_param_spec_object ("aid",
|
||||
"Aid",
|
||||
"The aid for the icon",
|
||||
SYSPROF_TYPE_AID,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_SELECTED] =
|
||||
g_param_spec_boolean ("selected",
|
||||
"Selected",
|
||||
"If the item is selected",
|
||||
FALSE,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "sysprofaidicon");
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-aid-icon.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofAidIcon, check);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofAidIcon, image);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofAidIcon, label);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_icon_init (SysprofAidIcon *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_icon_toggle (SysprofAidIcon *self)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_AID_ICON (self));
|
||||
|
||||
gtk_widget_set_visible (GTK_WIDGET (self->check),
|
||||
!gtk_widget_get_visible (GTK_WIDGET (self->check)));
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
/* sysprof-aid-icon.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_AID_ICON (sysprof_aid_icon_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofAidIcon, sysprof_aid_icon, SYSPROF, AID_ICON, GtkFlowBoxChild)
|
||||
|
||||
GtkWidget *sysprof_aid_icon_new (SysprofAid *aid);
|
||||
SysprofAid *sysprof_aid_icon_get_aid (SysprofAidIcon *self);
|
||||
void sysprof_aid_icon_toggle (SysprofAidIcon *self);
|
||||
gboolean sysprof_aid_icon_is_selected (SysprofAidIcon *self);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="SysprofAidIcon" parent="GtkFlowBoxChild">
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkOverlay">
|
||||
<property name="halign">center</property>
|
||||
<property name="child">
|
||||
<object class="GtkImage" id="image">
|
||||
<property name="pixel-size">48</property>
|
||||
<property name="width-request">64</property>
|
||||
<property name="icon-name">org.gnome.Sysprof-symbolic</property>
|
||||
</object>
|
||||
</property>
|
||||
<child type="overlay">
|
||||
<object class="GtkImage" id="check">
|
||||
<property name="pixel-size">14</property>
|
||||
<property name="icon-name">object-select-symbolic</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">start</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label">
|
||||
<property name="use-underline">1</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="wrap">1</property>
|
||||
<property name="mnemonic-widget">SysprofAidIcon</property>
|
||||
<property name="max-width-chars">12</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,353 +0,0 @@
|
||||
/* sysprof-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GPtrArray *sources;
|
||||
gchar *display_name;
|
||||
GIcon *icon;
|
||||
} SysprofAidPrivate;
|
||||
|
||||
static void buildable_iface_init (GtkBuildableIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (SysprofAid, sysprof_aid, G_TYPE_OBJECT,
|
||||
G_ADD_PRIVATE (SysprofAid)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DISPLAY_NAME,
|
||||
PROP_ICON,
|
||||
PROP_ICON_NAME,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_aid_real_present_async (SysprofAid *self,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_task_report_new_error (self, callback, user_data,
|
||||
sysprof_aid_real_present_async,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_SUPPORTED,
|
||||
"Not supported");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_aid_real_present_finish (SysprofAid *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_finalize (GObject *object)
|
||||
{
|
||||
SysprofAid *self = (SysprofAid *)object;
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->sources, g_ptr_array_unref);
|
||||
g_clear_pointer (&priv->display_name, g_free);
|
||||
g_clear_object (&priv->icon);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_aid_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofAid *self = SYSPROF_AID (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DISPLAY_NAME:
|
||||
g_value_set_string (value, sysprof_aid_get_display_name (self));
|
||||
break;
|
||||
|
||||
case PROP_ICON:
|
||||
g_value_set_object (value, sysprof_aid_get_icon (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofAid *self = SYSPROF_AID (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DISPLAY_NAME:
|
||||
sysprof_aid_set_display_name (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_ICON:
|
||||
sysprof_aid_set_icon (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_ICON_NAME:
|
||||
sysprof_aid_set_icon_name (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_class_init (SysprofAidClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_aid_finalize;
|
||||
object_class->get_property = sysprof_aid_get_property;
|
||||
object_class->set_property = sysprof_aid_set_property;
|
||||
|
||||
klass->present_async = sysprof_aid_real_present_async;
|
||||
klass->present_finish = sysprof_aid_real_present_finish;
|
||||
|
||||
properties [PROP_DISPLAY_NAME] =
|
||||
g_param_spec_string ("display-name",
|
||||
"Display Name",
|
||||
"Display Name",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_ICON_NAME] =
|
||||
g_param_spec_string ("icon-name",
|
||||
"Icon Name",
|
||||
"Icon Name",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_ICON] =
|
||||
g_param_spec_object ("icon",
|
||||
"Icon",
|
||||
"The icon to display",
|
||||
G_TYPE_ICON,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_init (SysprofAid *self G_GNUC_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_aid_get_display_name:
|
||||
* @self: a #SysprofAid
|
||||
*
|
||||
* Gets the display name as it should be shown to the user.
|
||||
*
|
||||
* Returns: a string containing the display name
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
const gchar *
|
||||
sysprof_aid_get_display_name (SysprofAid *self)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_AID (self), NULL);
|
||||
|
||||
return priv->display_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_aid_get_icon:
|
||||
*
|
||||
* Gets the icon for the aid.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GIcon or %NULL
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
GIcon *
|
||||
sysprof_aid_get_icon (SysprofAid *self)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_AID (self), NULL);
|
||||
|
||||
return priv->icon;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_set_icon (SysprofAid *self,
|
||||
GIcon *icon)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
|
||||
if (g_set_object (&priv->icon, icon))
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON]);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_set_icon_name (SysprofAid *self,
|
||||
const gchar *icon_name)
|
||||
{
|
||||
g_autoptr(GIcon) icon = NULL;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
|
||||
if (icon_name != NULL)
|
||||
icon = g_themed_icon_new (icon_name);
|
||||
|
||||
sysprof_aid_set_icon (self, icon);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_set_display_name (SysprofAid *self,
|
||||
const gchar *display_name)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
|
||||
if (g_strcmp0 (display_name, priv->display_name) != 0)
|
||||
{
|
||||
g_free (priv->display_name);
|
||||
priv->display_name = g_strdup (display_name);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DISPLAY_NAME]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
g_return_if_fail (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
if (priv->sources != NULL)
|
||||
{
|
||||
for (guint i = 0; i < priv->sources->len; i++)
|
||||
{
|
||||
SysprofSource *source = g_ptr_array_index (priv->sources, i);
|
||||
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
}
|
||||
|
||||
if (priv->sources->len > 0)
|
||||
g_ptr_array_remove_range (priv->sources, 0, priv->sources->len);
|
||||
}
|
||||
|
||||
if (SYSPROF_AID_GET_CLASS (self)->prepare)
|
||||
SYSPROF_AID_GET_CLASS (self)->prepare (self, profiler);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_aid_add_child (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
GObject *object,
|
||||
const gchar *type G_GNUC_UNUSED)
|
||||
{
|
||||
SysprofAid *self = (SysprofAid *)buildable;
|
||||
SysprofAidPrivate *priv = sysprof_aid_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_AID (self));
|
||||
g_assert (GTK_IS_BUILDER (builder));
|
||||
g_assert (G_IS_OBJECT (object));
|
||||
|
||||
if (SYSPROF_IS_SOURCE (object))
|
||||
{
|
||||
if (priv->sources == NULL)
|
||||
priv->sources = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
g_ptr_array_add (priv->sources, g_object_ref (object));
|
||||
return;
|
||||
}
|
||||
|
||||
g_warning ("Unsupported child type of %s: %s",
|
||||
G_OBJECT_TYPE_NAME (self),
|
||||
G_OBJECT_TYPE_NAME (object));
|
||||
}
|
||||
|
||||
static void
|
||||
buildable_iface_init (GtkBuildableIface *iface)
|
||||
{
|
||||
iface->add_child = sysprof_aid_add_child;
|
||||
}
|
||||
|
||||
SysprofAid *
|
||||
sysprof_aid_new (const gchar *display_name,
|
||||
const gchar *icon_name)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_AID,
|
||||
"display-aid", display_name,
|
||||
"icon-name", icon_name,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_aid_present_async (SysprofAid *self,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_AID (self));
|
||||
g_return_if_fail (reader != NULL);
|
||||
g_return_if_fail (SYSPROF_IS_DISPLAY (display));
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
SYSPROF_AID_GET_CLASS (self)->present_async (self, reader, display, cancellable, callback, user_data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_aid_present_finish (SysprofAid *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_AID (self), FALSE);
|
||||
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
||||
|
||||
return SYSPROF_AID_GET_CLASS (self)->present_finish (self, result, error);
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
/* sysprof-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "sysprof-display.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_AID (sysprof_aid_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofAid, sysprof_aid, SYSPROF, AID, GObject)
|
||||
|
||||
struct _SysprofAidClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*prepare) (SysprofAid *self,
|
||||
SysprofProfiler *profiler);
|
||||
void (*present_async) (SysprofAid *self,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean (*present_finish) (SysprofAid *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
SysprofAid *sysprof_aid_new (const gchar *display_name,
|
||||
const gchar *icon_name);
|
||||
const gchar *sysprof_aid_get_display_name (SysprofAid *self);
|
||||
void sysprof_aid_set_display_name (SysprofAid *self,
|
||||
const gchar *display_name);
|
||||
GIcon *sysprof_aid_get_icon (SysprofAid *self);
|
||||
void sysprof_aid_set_icon (SysprofAid *self,
|
||||
GIcon *icon);
|
||||
void sysprof_aid_set_icon_name (SysprofAid *self,
|
||||
const gchar *icon_name);
|
||||
void sysprof_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler);
|
||||
void sysprof_aid_present_async (SysprofAid *self,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean sysprof_aid_present_finish (SysprofAid *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,242 +0,0 @@
|
||||
/* sysprof-battery-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-battery-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-battery-aid.h"
|
||||
#include "sysprof-line-visualizer.h"
|
||||
|
||||
struct _SysprofBatteryAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofBatteryAid, sysprof_battery_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_battery_aid_new:
|
||||
*
|
||||
* Create a new #SysprofBatteryAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofBatteryAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_battery_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_BATTERY_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
#ifdef __linux__
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_BATTERY_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
source = sysprof_battery_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_battery_counters (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
GArray *counters = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (counters != NULL);
|
||||
|
||||
for (guint i = 0; i < def->n_counters; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *counter = &def->counters[i];
|
||||
|
||||
if (g_strcmp0 (counter->category, "Battery Charge") == 0)
|
||||
g_array_append_vals (counters, counter, 1);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *present = task_data;
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_BATTERY_AID (source_object));
|
||||
g_assert (present != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
|
||||
sysprof_capture_cursor_foreach (present->cursor, collect_battery_counters, counters);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&counters),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_BATTERY_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_battery_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_battery_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_battery_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
Present *present;
|
||||
|
||||
g_assert (SYSPROF_IS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
present = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *group;
|
||||
guint found = 0;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"title", _("Battery Charge"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_strcmp0 (ctr->category, "Battery Charge") == 0)
|
||||
{
|
||||
g_autofree gchar *title = NULL;
|
||||
gboolean is_combined = g_str_equal (ctr->name, "Combined");
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
if (is_combined)
|
||||
title = g_strdup (_("Battery Charge (All)"));
|
||||
else
|
||||
title = g_strdup_printf ("Battery Charge (%s)", ctr->name);
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", title,
|
||||
"height-request", 35,
|
||||
"visible", is_combined,
|
||||
NULL);
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_visualizer_group_insert (group,
|
||||
SYSPROF_VISUALIZER (row),
|
||||
is_combined ? 0 : -1,
|
||||
!is_combined);
|
||||
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
if (found > 0)
|
||||
sysprof_display_add_group (present->display, group);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (group));
|
||||
}
|
||||
|
||||
return counters != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_class_init (SysprofBatteryAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_battery_aid_prepare;
|
||||
aid_class->present_async = sysprof_battery_aid_present_async;
|
||||
aid_class->present_finish = sysprof_battery_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_battery_aid_init (SysprofBatteryAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Battery"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "battery-low-charging-symbolic");
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-battery-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_BATTERY_AID (sysprof_battery_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofBatteryAid, sysprof_battery_aid, SYSPROF, BATTERY_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_battery_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,71 +0,0 @@
|
||||
/* sysprof-cairo.c
|
||||
*
|
||||
* Copyright 2019 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 "sysprof-ui-private.h"
|
||||
|
||||
void
|
||||
_sysprof_rounded_rectangle (cairo_t *cr,
|
||||
const GdkRectangle *rect,
|
||||
gint x_radius,
|
||||
gint y_radius)
|
||||
{
|
||||
gint x;
|
||||
gint y;
|
||||
gint width;
|
||||
gint height;
|
||||
gint x1, x2;
|
||||
gint y1, y2;
|
||||
gint xr1, xr2;
|
||||
gint yr1, yr2;
|
||||
|
||||
g_return_if_fail (cr);
|
||||
g_return_if_fail (rect);
|
||||
|
||||
x = rect->x;
|
||||
y = rect->y;
|
||||
width = rect->width;
|
||||
height = rect->height;
|
||||
|
||||
x1 = x;
|
||||
x2 = x1 + width;
|
||||
y1 = y;
|
||||
y2 = y1 + height;
|
||||
|
||||
x_radius = MIN (x_radius, width / 2.0);
|
||||
y_radius = MIN (y_radius, width / 2.0);
|
||||
|
||||
xr1 = x_radius;
|
||||
xr2 = x_radius / 2.0;
|
||||
yr1 = y_radius;
|
||||
yr2 = y_radius / 2.0;
|
||||
|
||||
cairo_move_to (cr, x1 + xr1, y1);
|
||||
cairo_line_to (cr, x2 - xr1, y1);
|
||||
cairo_curve_to (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1);
|
||||
cairo_line_to (cr, x2, y2 - yr1);
|
||||
cairo_curve_to (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2);
|
||||
cairo_line_to (cr, x1 + xr1, y2);
|
||||
cairo_curve_to (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1);
|
||||
cairo_line_to (cr, x1, y1 + yr1);
|
||||
cairo_curve_to (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
@ -1,275 +0,0 @@
|
||||
/* sysprof-callgraph-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-callgraph-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-callgraph-aid.h"
|
||||
#include "sysprof-callgraph-page.h"
|
||||
#include "sysprof-depth-visualizer.h"
|
||||
|
||||
struct _SysprofCallgraphAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
guint has_samples : 1;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofCallgraphAid, sysprof_callgraph_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
static void
|
||||
on_group_activated_cb (SysprofVisualizerGroup *group,
|
||||
SysprofPage *page)
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
|
||||
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
|
||||
g_assert (SYSPROF_IS_PAGE (page));
|
||||
|
||||
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
|
||||
sysprof_display_set_visible_page (display, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_callgraph_aid_new:
|
||||
*
|
||||
* Create a new #SysprofCallgraphAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofCallgraphAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_callgraph_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_CALLGRAPH_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
g_assert (SYSPROF_IS_CALLGRAPH_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
#ifdef __linux__
|
||||
{
|
||||
const GPid *pids;
|
||||
guint n_pids;
|
||||
|
||||
if ((pids = sysprof_profiler_get_pids (profiler, &n_pids)))
|
||||
{
|
||||
for (guint i = 0; i < n_pids; i++)
|
||||
{
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
source = sysprof_perf_source_new ();
|
||||
sysprof_perf_source_set_target_pid (SYSPROF_PERF_SOURCE (source), pids[i]);
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
source = sysprof_perf_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
discover_samples_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
Present *p = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (p != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE)
|
||||
{
|
||||
p->has_samples = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *p = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_CALLGRAPH_AID (source_object));
|
||||
g_assert (p != NULL);
|
||||
g_assert (p->cursor != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
/* If we find a sample frame, then we should enable the callgraph
|
||||
* and stack visualizers.
|
||||
*/
|
||||
sysprof_capture_cursor_foreach (p->cursor, discover_samples_cb, p);
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_SAMPLE };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_CALLGRAPH_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_callgraph_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_callgraph_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_callgraph_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
Present *p;
|
||||
|
||||
g_assert (SYSPROF_IS_CALLGRAPH_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
p = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if (p->has_samples)
|
||||
{
|
||||
SysprofVisualizerGroup *group;
|
||||
SysprofVisualizer *depth;
|
||||
SysprofPage *page;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"has-page", TRUE,
|
||||
"priority", -500,
|
||||
"title", _("Stack Traces"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_COMBINED);
|
||||
g_object_set (depth,
|
||||
"title", _("Stack Traces"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (group, depth, 0, FALSE);
|
||||
|
||||
depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY);
|
||||
g_object_set (depth,
|
||||
"title", _("Stack Traces (In Kernel)"),
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (group, depth, 1, TRUE);
|
||||
|
||||
depth = sysprof_depth_visualizer_new (SYSPROF_DEPTH_VISUALIZER_USER_ONLY);
|
||||
g_object_set (depth,
|
||||
"title", _("Stack Traces (In User)"),
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (group, depth, 2, TRUE);
|
||||
|
||||
sysprof_display_add_group (p->display, group);
|
||||
|
||||
page = g_object_new (SYSPROF_TYPE_CALLGRAPH_PAGE,
|
||||
"title", _("Callgraph"),
|
||||
"vexpand", TRUE,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
sysprof_display_add_page (p->display, page);
|
||||
sysprof_display_set_visible_page (p->display, page);
|
||||
|
||||
g_signal_connect_object (group,
|
||||
"group-activated",
|
||||
G_CALLBACK (on_group_activated_cb),
|
||||
page,
|
||||
0);
|
||||
}
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_class_init (SysprofCallgraphAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_callgraph_aid_prepare;
|
||||
aid_class->present_async = sysprof_callgraph_aid_present_async;
|
||||
aid_class->present_finish = sysprof_callgraph_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_callgraph_aid_init (SysprofCallgraphAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Callgraph"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-callgraph-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CALLGRAPH_AID (sysprof_callgraph_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofCallgraphAid, sysprof_callgraph_aid, SYSPROF, CALLGRAPH_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_callgraph_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
/* sysprof-callgraph-page.h
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "sysprof-page.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CALLGRAPH_PAGE (sysprof_callgraph_page_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofCallgraphPage, sysprof_callgraph_page, SYSPROF, CALLGRAPH_PAGE, SysprofPage)
|
||||
|
||||
struct _SysprofCallgraphPageClass
|
||||
{
|
||||
SysprofPageClass parent_class;
|
||||
|
||||
void (*go_previous) (SysprofCallgraphPage *self);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
GtkWidget *sysprof_callgraph_page_new (void);
|
||||
SysprofCallgraphProfile *sysprof_callgraph_page_get_profile (SysprofCallgraphPage *self);
|
||||
void sysprof_callgraph_page_set_profile (SysprofCallgraphPage *self,
|
||||
SysprofCallgraphProfile *profile);
|
||||
gchar *sysprof_callgraph_page_screenshot (SysprofCallgraphPage *self);
|
||||
guint sysprof_callgraph_page_get_n_functions (SysprofCallgraphPage *self);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,212 +0,0 @@
|
||||
<interface>
|
||||
<template class="SysprofCallgraphPage" parent="SysprofPage">
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<child>
|
||||
<object class="EggPaned" id="callgraph">
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
<object class="EggPaned">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="width-request">400</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="functions_view">
|
||||
<property name="fixed-height-mode">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_name_column">
|
||||
<property name="expand">true</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<property name="title" translatable="yes">Functions</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="ellipsize">middle</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_self_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<property name="title" translatable="yes">Self</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_total_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<property name="title" translatable="yes">Total</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="callers_view">
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="callers_name_column">
|
||||
<property name="expand">true</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<property name="title" translatable="yes">Callers</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="ellipsize">middle</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="callers_self_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<property name="title" translatable="yes">Self</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="callers_total_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<property name="title" translatable="yes">Total</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="descendants_view">
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="descendants_name_column">
|
||||
<property name="expand">true</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<property name="title" translatable="yes">Descendants</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="descendants_self_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<property name="title" translatable="yes">Self</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="descendants_total_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<property name="title" translatable="yes">Total</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_hits_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="title" translatable="yes">Hits</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="xalign">1.0</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">4</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwStatusPage" id="loading_state">
|
||||
<property name="icon-name">content-loading-symbolic</property>
|
||||
<property name="title" translatable="yes">Generating Callgraph</property>
|
||||
<property name="description" translatable="yes">Sysprof is busy creating the selected callgraph.</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwStatusPage" id="empty_state">
|
||||
<property name="icon-name">computer-fail-symbolic</property>
|
||||
<property name="title" translatable="yes">Not Enough Samples</property>
|
||||
<property name="description" translatable="yes">More samples are necessary to display a callgraph.</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,455 +0,0 @@
|
||||
/* sysprof-cell-renderer-duration.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-cell-renderer-duration"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-cell-renderer-duration.h"
|
||||
#include "sysprof-ui-private.h"
|
||||
#include "sysprof-zoom-manager.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 capture_begin_time;
|
||||
gint64 capture_end_time;
|
||||
gint64 capture_duration;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
gchar *text;
|
||||
SysprofZoomManager *zoom_manager;
|
||||
GdkRGBA color;
|
||||
guint color_set : 1;
|
||||
} SysprofCellRendererDurationPrivate;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_BEGIN_TIME,
|
||||
PROP_CAPTURE_BEGIN_TIME,
|
||||
PROP_CAPTURE_END_TIME,
|
||||
PROP_COLOR,
|
||||
PROP_END_TIME,
|
||||
PROP_TEXT,
|
||||
PROP_ZOOM_MANAGER,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (SysprofCellRendererDuration, sysprof_cell_renderer_duration, GTK_TYPE_CELL_RENDERER)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static inline void
|
||||
rounded_rectangle (cairo_t *cr,
|
||||
const GdkRectangle *rect,
|
||||
int x_radius,
|
||||
int y_radius)
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
int x1, x2;
|
||||
int y1, y2;
|
||||
int xr1, xr2;
|
||||
int yr1, yr2;
|
||||
|
||||
g_assert (cr);
|
||||
g_assert (rect);
|
||||
|
||||
x = rect->x;
|
||||
y = rect->y;
|
||||
width = rect->width;
|
||||
height = rect->height;
|
||||
|
||||
x1 = x;
|
||||
x2 = x1 + width;
|
||||
y1 = y;
|
||||
y2 = y1 + height;
|
||||
|
||||
x_radius = MIN (x_radius, width / 2.0);
|
||||
y_radius = MIN (y_radius, width / 2.0);
|
||||
|
||||
xr1 = x_radius;
|
||||
xr2 = x_radius / 2.0;
|
||||
yr1 = y_radius;
|
||||
yr2 = y_radius / 2.0;
|
||||
|
||||
cairo_move_to (cr, x1 + xr1, y1);
|
||||
cairo_line_to (cr, x2 - xr1, y1);
|
||||
cairo_curve_to (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1);
|
||||
cairo_line_to (cr, x2, y2 - yr1);
|
||||
cairo_curve_to (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2);
|
||||
cairo_line_to (cr, x1 + xr1, y2);
|
||||
cairo_curve_to (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1);
|
||||
cairo_line_to (cr, x1, y1 + yr1);
|
||||
cairo_curve_to (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_snapshot (GtkCellRenderer *renderer,
|
||||
GtkSnapshot *snapshot,
|
||||
GtkWidget *widget,
|
||||
const GdkRectangle *bg_area,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState state)
|
||||
{
|
||||
SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)renderer;
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
g_autoptr(GString) str = NULL;
|
||||
GtkStyleContext *style_context;
|
||||
cairo_t *cr;
|
||||
gdouble x1, x2;
|
||||
GdkRGBA rgba;
|
||||
GdkRectangle r;
|
||||
gint64 duration;
|
||||
|
||||
g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (self));
|
||||
g_assert (snapshot != NULL);
|
||||
g_assert (GTK_IS_WIDGET (widget));
|
||||
|
||||
if (priv->zoom_manager == NULL)
|
||||
return;
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (cell_area->x, cell_area->y, cell_area->width, cell_area->height));
|
||||
|
||||
style_context = gtk_widget_get_style_context (widget);
|
||||
|
||||
if (priv->color_set)
|
||||
rgba = priv->color;
|
||||
else
|
||||
gtk_style_context_get_color (style_context, &rgba);
|
||||
|
||||
duration = sysprof_zoom_manager_get_duration_for_width (priv->zoom_manager, bg_area->width);
|
||||
|
||||
x1 = (priv->begin_time - priv->capture_begin_time) / (gdouble)duration * cell_area->width;
|
||||
x2 = (priv->end_time - priv->capture_begin_time) / (gdouble)duration * cell_area->width;
|
||||
|
||||
if (x2 < x1)
|
||||
x2 = x1;
|
||||
|
||||
r.x = cell_area->x + x1;
|
||||
r.height = 12;
|
||||
r.y = cell_area->y + (cell_area->height - r.height) / 2;
|
||||
r.width = MAX (1.0, x2 - x1);
|
||||
|
||||
if ((cell_area->height - r.height) % 2 == 1)
|
||||
r.height++;
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &rgba);
|
||||
|
||||
if (r.width > 3)
|
||||
{
|
||||
rounded_rectangle (cr, &r, 2, 2);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
else if (r.width > 1)
|
||||
{
|
||||
gdk_cairo_rectangle (cr, &r);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_set_line_width (cr, 1);
|
||||
cairo_move_to (cr, r.x + .5, r.y);
|
||||
cairo_line_to (cr, r.x + .5, r.y + r.height);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
str = g_string_new (NULL);
|
||||
|
||||
if (priv->begin_time != priv->end_time)
|
||||
{
|
||||
g_autofree gchar *fmt = _sysprof_format_duration (priv->end_time - priv->begin_time);
|
||||
g_string_append_printf (str, "%s — ", fmt);
|
||||
}
|
||||
|
||||
if (priv->text != NULL)
|
||||
g_string_append (str, priv->text);
|
||||
|
||||
if (str->len)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
gint w, h;
|
||||
|
||||
/* Add some spacing before/after */
|
||||
r.x -= 24;
|
||||
r.width += 48;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, NULL);
|
||||
pango_layout_set_text (layout, str->str, str->len);
|
||||
pango_layout_get_pixel_size (layout, &w, &h);
|
||||
|
||||
if ((r.x + r.width + w) < (cell_area->x + cell_area->width) ||
|
||||
((cell_area->x + w) > r.x))
|
||||
cairo_move_to (cr, r.x + r.width, r.y + ((r.height - h) / 2));
|
||||
else
|
||||
cairo_move_to (cr, r.x - w, r.y + ((r.height - h) / 2));
|
||||
|
||||
if (priv->end_time < priv->begin_time)
|
||||
{
|
||||
gdk_rgba_parse (&rgba, "#f00");
|
||||
if (state & GTK_CELL_RENDERER_SELECTED)
|
||||
rgba.alpha = 0.6;
|
||||
}
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &rgba);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
g_object_unref (layout);
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static GtkSizeRequestMode
|
||||
sysprof_cell_renderer_duration_get_request_mode (GtkCellRenderer *renderer)
|
||||
{
|
||||
return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_get_preferred_width (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
gint *min_width,
|
||||
gint *nat_width)
|
||||
{
|
||||
SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)cell;
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
gint width = 1;
|
||||
|
||||
g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (self));
|
||||
g_assert (GTK_IS_WIDGET (widget));
|
||||
|
||||
GTK_CELL_RENDERER_CLASS (sysprof_cell_renderer_duration_parent_class)->get_preferred_width (cell, widget, min_width, nat_width);
|
||||
|
||||
if (priv->zoom_manager && priv->capture_begin_time && priv->capture_end_time)
|
||||
width = sysprof_zoom_manager_get_width_for_duration (priv->zoom_manager,
|
||||
priv->capture_end_time - priv->capture_begin_time);
|
||||
|
||||
if (min_width)
|
||||
*min_width = width;
|
||||
|
||||
if (nat_width)
|
||||
*nat_width = width;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_get_preferred_height_for_width (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
gint width,
|
||||
gint *min_height,
|
||||
gint *nat_height)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
gint w, h;
|
||||
gint ypad;
|
||||
|
||||
g_assert (SYSPROF_IS_CELL_RENDERER_DURATION (cell));
|
||||
|
||||
gtk_cell_renderer_get_padding (cell, NULL, &ypad);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, "XMZ09");
|
||||
pango_layout_get_pixel_size (layout, &w, &h);
|
||||
g_clear_object (&layout);
|
||||
|
||||
if (min_height)
|
||||
*min_height = h + (ypad * 2);
|
||||
|
||||
if (nat_height)
|
||||
*nat_height = h + (ypad * 2);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_finalize (GObject *object)
|
||||
{
|
||||
SysprofCellRendererDuration *self = (SysprofCellRendererDuration *)object;
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
|
||||
g_clear_object (&priv->zoom_manager);
|
||||
g_clear_pointer (&priv->text, g_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_cell_renderer_duration_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererDuration *self = SYSPROF_CELL_RENDERER_DURATION (object);
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BEGIN_TIME:
|
||||
g_value_set_int64 (value, priv->begin_time);
|
||||
break;
|
||||
|
||||
case PROP_CAPTURE_BEGIN_TIME:
|
||||
g_value_set_int64 (value, priv->capture_begin_time);
|
||||
break;
|
||||
|
||||
case PROP_CAPTURE_END_TIME:
|
||||
g_value_set_int64 (value, priv->capture_end_time);
|
||||
break;
|
||||
|
||||
case PROP_END_TIME:
|
||||
g_value_set_int64 (value, priv->end_time);
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
g_value_set_string (value, priv->text);
|
||||
break;
|
||||
|
||||
case PROP_ZOOM_MANAGER:
|
||||
g_value_set_object (value, priv->zoom_manager);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererDuration *self = SYSPROF_CELL_RENDERER_DURATION (object);
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_BEGIN_TIME:
|
||||
priv->begin_time = g_value_get_int64 (value);
|
||||
break;
|
||||
|
||||
case PROP_CAPTURE_BEGIN_TIME:
|
||||
priv->capture_begin_time = g_value_get_int64 (value);
|
||||
priv->capture_duration = priv->capture_end_time - priv->capture_begin_time;
|
||||
break;
|
||||
|
||||
case PROP_CAPTURE_END_TIME:
|
||||
priv->capture_end_time = g_value_get_int64 (value);
|
||||
priv->capture_duration = priv->capture_end_time - priv->capture_begin_time;
|
||||
break;
|
||||
|
||||
case PROP_COLOR:
|
||||
if (g_value_get_boxed (value))
|
||||
priv->color = *(GdkRGBA *)g_value_get_boxed (value);
|
||||
else
|
||||
gdk_rgba_parse (&priv->color, "#000");
|
||||
priv->color_set = !!g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_END_TIME:
|
||||
priv->end_time = g_value_get_int64 (value);
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
g_free (priv->text);
|
||||
priv->text = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_ZOOM_MANAGER:
|
||||
g_set_object (&priv->zoom_manager, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_class_init (SysprofCellRendererDurationClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_cell_renderer_duration_finalize;
|
||||
object_class->get_property = sysprof_cell_renderer_duration_get_property;
|
||||
object_class->set_property = sysprof_cell_renderer_duration_set_property;
|
||||
|
||||
cell_class->get_preferred_height_for_width = sysprof_cell_renderer_duration_get_preferred_height_for_width;
|
||||
cell_class->get_preferred_width = sysprof_cell_renderer_duration_get_preferred_width;
|
||||
cell_class->get_request_mode = sysprof_cell_renderer_duration_get_request_mode;
|
||||
cell_class->snapshot = sysprof_cell_renderer_duration_snapshot;
|
||||
|
||||
/* Note we do not emit ::notify() for these properties */
|
||||
|
||||
properties [PROP_BEGIN_TIME] =
|
||||
g_param_spec_int64 ("begin-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_CAPTURE_BEGIN_TIME] =
|
||||
g_param_spec_int64 ("capture-begin-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_CAPTURE_END_TIME] =
|
||||
g_param_spec_int64 ("capture-end-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_COLOR] =
|
||||
g_param_spec_boxed ("color", NULL, NULL,
|
||||
GDK_TYPE_RGBA,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_END_TIME] =
|
||||
g_param_spec_int64 ("end-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_END_TIME] =
|
||||
g_param_spec_int64 ("end-time", NULL, NULL,
|
||||
G_MININT64, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_TEXT] =
|
||||
g_param_spec_string ("text", NULL, NULL,
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_ZOOM_MANAGER] =
|
||||
g_param_spec_object ("zoom-manager", NULL, NULL,
|
||||
SYSPROF_TYPE_ZOOM_MANAGER,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_duration_init (SysprofCellRendererDuration *self)
|
||||
{
|
||||
SysprofCellRendererDurationPrivate *priv = sysprof_cell_renderer_duration_get_instance_private (self);
|
||||
|
||||
priv->color.alpha = 1.0;
|
||||
}
|
||||
|
||||
GtkCellRenderer *
|
||||
sysprof_cell_renderer_duration_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_CELL_RENDERER_DURATION, NULL);
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
/* sysprof-cell-renderer-duration.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CELL_RENDERER_DURATION (sysprof_cell_renderer_duration_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofCellRendererDuration, sysprof_cell_renderer_duration, SYSPROF, CELL_RENDERER_DURATION, GtkCellRenderer)
|
||||
|
||||
struct _SysprofCellRendererDurationClass
|
||||
{
|
||||
GtkCellRendererClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[8];
|
||||
};
|
||||
|
||||
GtkCellRenderer *sysprof_cell_renderer_duration_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,139 +0,0 @@
|
||||
/* sysprof-cell-renderer-percent.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-cell-renderer-percent"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-cell-renderer-percent.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gdouble percent;
|
||||
} SysprofCellRendererPercentPrivate;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PERCENT,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (SysprofCellRendererPercent, sysprof_cell_renderer_percent, SYSPROF_TYPE_CELL_RENDERER_PROGRESS)
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_percent_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererPercent *self = SYSPROF_CELL_RENDERER_PERCENT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PERCENT:
|
||||
g_value_set_double (value, sysprof_cell_renderer_percent_get_percent (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_percent_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererPercent *self = SYSPROF_CELL_RENDERER_PERCENT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PERCENT:
|
||||
sysprof_cell_renderer_percent_set_percent (self, g_value_get_double (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_percent_class_init (SysprofCellRendererPercentClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = sysprof_cell_renderer_percent_get_property;
|
||||
object_class->set_property = sysprof_cell_renderer_percent_set_property;
|
||||
|
||||
properties [PROP_PERCENT] =
|
||||
g_param_spec_double ("percent",
|
||||
"Percent",
|
||||
"Percent",
|
||||
0.0,
|
||||
100.0,
|
||||
0.0,
|
||||
/* Doesn't notify to avoid signal emission */
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_percent_init (SysprofCellRendererPercent *self)
|
||||
{
|
||||
g_object_set (self, "text-xalign", 1.0f, NULL);
|
||||
}
|
||||
|
||||
gdouble
|
||||
sysprof_cell_renderer_percent_get_percent (SysprofCellRendererPercent *self)
|
||||
{
|
||||
SysprofCellRendererPercentPrivate *priv = sysprof_cell_renderer_percent_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_CELL_RENDERER_PERCENT (self), 0.0);
|
||||
|
||||
return priv->percent;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_cell_renderer_percent_set_percent (SysprofCellRendererPercent *self,
|
||||
gdouble percent)
|
||||
{
|
||||
SysprofCellRendererPercentPrivate *priv = sysprof_cell_renderer_percent_get_instance_private (self);
|
||||
gchar text[8];
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_CELL_RENDERER_PERCENT (self));
|
||||
g_return_if_fail (percent >= 0.0);
|
||||
g_return_if_fail (percent <= 100.0);
|
||||
|
||||
priv->percent = percent;
|
||||
|
||||
g_snprintf (text, sizeof text, "%.2lf%%", percent);
|
||||
text [sizeof text - 1] = '\0';
|
||||
|
||||
g_object_set (self,
|
||||
"value", (guint)percent,
|
||||
"text", text,
|
||||
NULL);
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/* sysprof-cell-renderer-percent.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-cell-renderer-progress.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CELL_RENDERER_PERCENT (sysprof_cell_renderer_percent_get_type())
|
||||
#define SYSPROF_CELL_RENDERER_PERCENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercent))
|
||||
#define SYSPROF_CELL_RENDERER_PERCENT_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercent const))
|
||||
#define SYSPROF_CELL_RENDERER_PERCENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercentClass))
|
||||
#define SYSPROF_IS_CELL_RENDERER_PERCENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT))
|
||||
#define SYSPROF_IS_CELL_RENDERER_PERCENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SYSPROF_TYPE_CELL_RENDERER_PERCENT))
|
||||
#define SYSPROF_CELL_RENDERER_PERCENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SYSPROF_TYPE_CELL_RENDERER_PERCENT, SysprofCellRendererPercentClass))
|
||||
|
||||
typedef struct _SysprofCellRendererPercent SysprofCellRendererPercent;
|
||||
typedef struct _SysprofCellRendererPercentClass SysprofCellRendererPercentClass;
|
||||
|
||||
struct _SysprofCellRendererPercent
|
||||
{
|
||||
SysprofCellRendererProgress parent;
|
||||
};
|
||||
|
||||
struct _SysprofCellRendererPercentClass
|
||||
{
|
||||
SysprofCellRendererProgressClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[4];
|
||||
};
|
||||
|
||||
GType sysprof_cell_renderer_percent_get_type (void);
|
||||
GtkCellRenderer *sysprof_cell_renderer_percent_new (void);
|
||||
gdouble sysprof_cell_renderer_percent_get_percent (SysprofCellRendererPercent *self);
|
||||
void sysprof_cell_renderer_percent_set_percent (SysprofCellRendererPercent *self,
|
||||
gdouble percent);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,712 +0,0 @@
|
||||
/* gtkcellrendererprogress.c
|
||||
* Copyright (C) 2002 Naba Kumar <kh_naba@users.sourceforge.net>
|
||||
* heavily modified by Jörgen Scheibengruber <mfcn@gmx.de>
|
||||
* heavily modified by Marco Pesenti Gritti <marco@gnome.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2007. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sysprof-cell-renderer-progress.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_VALUE,
|
||||
PROP_TEXT,
|
||||
PROP_PULSE,
|
||||
PROP_TEXT_XALIGN,
|
||||
PROP_TEXT_YALIGN,
|
||||
PROP_ORIENTATION,
|
||||
PROP_INVERTED
|
||||
};
|
||||
|
||||
struct _SysprofCellRendererProgressPrivate
|
||||
{
|
||||
int value;
|
||||
char *text;
|
||||
char *label;
|
||||
int min_h;
|
||||
int min_w;
|
||||
int pulse;
|
||||
int offset;
|
||||
float text_xalign;
|
||||
float text_yalign;
|
||||
GtkOrientation orientation;
|
||||
gboolean inverted;
|
||||
};
|
||||
|
||||
static void sysprof_cell_renderer_progress_finalize (GObject *object);
|
||||
static void sysprof_cell_renderer_progress_get_property (GObject *object,
|
||||
guint param_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void sysprof_cell_renderer_progress_set_property (GObject *object,
|
||||
guint param_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void sysprof_cell_renderer_progress_set_value (SysprofCellRendererProgress *cellprogress,
|
||||
int value);
|
||||
static void sysprof_cell_renderer_progress_set_text (SysprofCellRendererProgress *cellprogress,
|
||||
const char *text);
|
||||
static void sysprof_cell_renderer_progress_set_pulse (SysprofCellRendererProgress *cellprogress,
|
||||
int pulse);
|
||||
static void compute_dimensions (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
const char *text,
|
||||
int *width,
|
||||
int *height);
|
||||
static void sysprof_cell_renderer_progress_snapshot (GtkCellRenderer *cell,
|
||||
GtkSnapshot *snapshot,
|
||||
GtkWidget *widget,
|
||||
const GdkRectangle *background_area,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (SysprofCellRendererProgress, sysprof_cell_renderer_progress, GTK_TYPE_CELL_RENDERER,
|
||||
G_ADD_PRIVATE (SysprofCellRendererProgress)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
|
||||
|
||||
static void
|
||||
recompute_label (SysprofCellRendererProgress *cellprogress)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
char *label;
|
||||
|
||||
if (priv->text)
|
||||
label = g_strdup (priv->text);
|
||||
else if (priv->pulse < 0)
|
||||
label = g_strdup_printf (C_("progress bar label", "%d %%"), priv->value);
|
||||
else
|
||||
label = NULL;
|
||||
|
||||
g_free (priv->label);
|
||||
priv->label = label;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_set_value (SysprofCellRendererProgress *cellprogress,
|
||||
int value)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
if (priv->value != value)
|
||||
{
|
||||
priv->value = value;
|
||||
recompute_label (cellprogress);
|
||||
g_object_notify (G_OBJECT (cellprogress), "value");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_set_text (SysprofCellRendererProgress *cellprogress,
|
||||
const char *text)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
char *new_text;
|
||||
|
||||
new_text = g_strdup (text);
|
||||
g_free (priv->text);
|
||||
priv->text = new_text;
|
||||
recompute_label (cellprogress);
|
||||
g_object_notify (G_OBJECT (cellprogress), "text");
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_set_pulse (SysprofCellRendererProgress *cellprogress,
|
||||
int pulse)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
if (pulse != priv->pulse)
|
||||
{
|
||||
if (pulse <= 0)
|
||||
priv->offset = 0;
|
||||
else
|
||||
priv->offset = pulse;
|
||||
g_object_notify (G_OBJECT (cellprogress), "pulse");
|
||||
}
|
||||
|
||||
priv->pulse = pulse;
|
||||
recompute_label (cellprogress);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_finalize (GObject *object)
|
||||
{
|
||||
SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (object);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
g_free (priv->text);
|
||||
g_free (priv->label);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_cell_renderer_progress_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_get_property (GObject *object,
|
||||
guint param_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (object);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
switch (param_id)
|
||||
{
|
||||
case PROP_VALUE:
|
||||
g_value_set_int (value, priv->value);
|
||||
break;
|
||||
case PROP_TEXT:
|
||||
g_value_set_string (value, priv->text);
|
||||
break;
|
||||
case PROP_PULSE:
|
||||
g_value_set_int (value, priv->pulse);
|
||||
break;
|
||||
case PROP_TEXT_XALIGN:
|
||||
g_value_set_float (value, priv->text_xalign);
|
||||
break;
|
||||
case PROP_TEXT_YALIGN:
|
||||
g_value_set_float (value, priv->text_yalign);
|
||||
break;
|
||||
case PROP_ORIENTATION:
|
||||
g_value_set_enum (value, priv->orientation);
|
||||
break;
|
||||
case PROP_INVERTED:
|
||||
g_value_set_boolean (value, priv->inverted);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_set_property (GObject *object,
|
||||
guint param_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (object);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
switch (param_id)
|
||||
{
|
||||
case PROP_VALUE:
|
||||
sysprof_cell_renderer_progress_set_value (cellprogress,
|
||||
g_value_get_int (value));
|
||||
break;
|
||||
case PROP_TEXT:
|
||||
sysprof_cell_renderer_progress_set_text (cellprogress,
|
||||
g_value_get_string (value));
|
||||
break;
|
||||
case PROP_PULSE:
|
||||
sysprof_cell_renderer_progress_set_pulse (cellprogress,
|
||||
g_value_get_int (value));
|
||||
break;
|
||||
case PROP_TEXT_XALIGN:
|
||||
priv->text_xalign = g_value_get_float (value);
|
||||
break;
|
||||
case PROP_TEXT_YALIGN:
|
||||
priv->text_yalign = g_value_get_float (value);
|
||||
break;
|
||||
case PROP_ORIENTATION:
|
||||
if (priv->orientation != g_value_get_enum (value))
|
||||
{
|
||||
priv->orientation = g_value_get_enum (value);
|
||||
g_object_notify_by_pspec (object, pspec);
|
||||
}
|
||||
break;
|
||||
case PROP_INVERTED:
|
||||
if (priv->inverted != g_value_get_boolean (value))
|
||||
{
|
||||
priv->inverted = g_value_get_boolean (value);
|
||||
g_object_notify_by_pspec (object, pspec);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compute_dimensions (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
const char *text,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
PangoRectangle logical_rect;
|
||||
PangoLayout *layout;
|
||||
int xpad, ypad;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, text);
|
||||
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
||||
|
||||
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
|
||||
|
||||
if (width)
|
||||
*width = logical_rect.width + xpad * 2;
|
||||
|
||||
if (height)
|
||||
*height = logical_rect.height + ypad * 2;
|
||||
|
||||
g_object_unref (layout);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_get_preferred_width (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
int *minimum,
|
||||
int *natural)
|
||||
{
|
||||
SysprofCellRendererProgress *self = SYSPROF_CELL_RENDERER_PROGRESS (cell);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (self);
|
||||
int w, h;
|
||||
int size;
|
||||
|
||||
if (priv->min_w < 0)
|
||||
{
|
||||
char *text = g_strdup_printf (C_("progress bar label", "%d %%"), 100);
|
||||
compute_dimensions (cell, widget, text,
|
||||
&priv->min_w,
|
||||
&priv->min_h);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
compute_dimensions (cell, widget, priv->label, &w, &h);
|
||||
|
||||
size = MAX (priv->min_w, w);
|
||||
|
||||
if (minimum != NULL)
|
||||
*minimum = size;
|
||||
if (natural != NULL)
|
||||
*natural = size;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_get_preferred_height (GtkCellRenderer *cell,
|
||||
GtkWidget *widget,
|
||||
int *minimum,
|
||||
int *natural)
|
||||
{
|
||||
SysprofCellRendererProgress *self = SYSPROF_CELL_RENDERER_PROGRESS (cell);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (self);
|
||||
int w, h;
|
||||
int size;
|
||||
|
||||
if (priv->min_w < 0)
|
||||
{
|
||||
char *text = g_strdup_printf (C_("progress bar label", "%d %%"), 100);
|
||||
compute_dimensions (cell, widget, text,
|
||||
&priv->min_w,
|
||||
&priv->min_h);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
compute_dimensions (cell, widget, priv->label, &w, &h);
|
||||
|
||||
size = MIN (priv->min_h, h);
|
||||
|
||||
if (minimum != NULL)
|
||||
*minimum = size;
|
||||
if (natural != NULL)
|
||||
*natural = size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
get_bar_size (int pulse,
|
||||
int value,
|
||||
int full_size)
|
||||
{
|
||||
int bar_size;
|
||||
|
||||
if (pulse < 0)
|
||||
bar_size = full_size * MAX (0, value) / 100;
|
||||
else if (pulse == 0)
|
||||
bar_size = 0;
|
||||
else if (pulse == G_MAXINT)
|
||||
bar_size = full_size;
|
||||
else
|
||||
bar_size = MAX (2, full_size / 5);
|
||||
|
||||
return bar_size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
get_bar_position (int start,
|
||||
int full_size,
|
||||
int bar_size,
|
||||
int pulse,
|
||||
int offset,
|
||||
gboolean is_rtl)
|
||||
{
|
||||
int position;
|
||||
|
||||
if (pulse < 0 || pulse == 0 || pulse == G_MAXINT)
|
||||
{
|
||||
position = is_rtl ? (start + full_size - bar_size) : start;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = (is_rtl ? offset + 12 : offset) % 24;
|
||||
if (position > 12)
|
||||
position = 24 - position;
|
||||
position = start + full_size * position / 15;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_snapshot (GtkCellRenderer *cell,
|
||||
GtkSnapshot *snapshot,
|
||||
GtkWidget *widget,
|
||||
const GdkRectangle *background_area,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags)
|
||||
{
|
||||
SysprofCellRendererProgress *cellprogress = SYSPROF_CELL_RENDERER_PROGRESS (cell);
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
GtkStyleContext *context;
|
||||
GtkBorder padding;
|
||||
PangoLayout *layout;
|
||||
PangoRectangle logical_rect;
|
||||
int x, y, w, h, x_pos, y_pos, bar_position, bar_size, start, full_size;
|
||||
int xpad, ypad;
|
||||
GdkRectangle clip;
|
||||
gboolean is_rtl;
|
||||
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
|
||||
|
||||
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
|
||||
x = cell_area->x + xpad;
|
||||
y = cell_area->y + ypad;
|
||||
w = cell_area->width - xpad * 2;
|
||||
h = cell_area->height - ypad * 2;
|
||||
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_add_class (context, "trough");
|
||||
|
||||
gtk_snapshot_render_background (snapshot, context, x, y, w, h);
|
||||
gtk_snapshot_render_frame (snapshot, context, x, y, w, h);
|
||||
|
||||
gtk_style_context_get_padding (context, &padding);
|
||||
|
||||
x += padding.left;
|
||||
y += padding.top;
|
||||
w -= padding.left + padding.right;
|
||||
h -= padding.top + padding.bottom;
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
clip.y = y;
|
||||
clip.height = h;
|
||||
|
||||
start = x;
|
||||
full_size = w;
|
||||
|
||||
bar_size = get_bar_size (priv->pulse, priv->value, full_size);
|
||||
|
||||
if (!priv->inverted)
|
||||
bar_position = get_bar_position (start, full_size, bar_size,
|
||||
priv->pulse, priv->offset, is_rtl);
|
||||
else
|
||||
bar_position = get_bar_position (start, full_size, bar_size,
|
||||
priv->pulse, priv->offset, !is_rtl);
|
||||
|
||||
clip.width = bar_size;
|
||||
clip.x = bar_position;
|
||||
}
|
||||
else
|
||||
{
|
||||
clip.x = x;
|
||||
clip.width = w;
|
||||
|
||||
start = y;
|
||||
full_size = h;
|
||||
|
||||
bar_size = get_bar_size (priv->pulse, priv->value, full_size);
|
||||
|
||||
if (priv->inverted)
|
||||
bar_position = get_bar_position (start, full_size, bar_size,
|
||||
priv->pulse, priv->offset, TRUE);
|
||||
else
|
||||
bar_position = get_bar_position (start, full_size, bar_size,
|
||||
priv->pulse, priv->offset, FALSE);
|
||||
|
||||
clip.height = bar_size;
|
||||
clip.y = bar_position;
|
||||
}
|
||||
|
||||
if (bar_size > 0)
|
||||
{
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_add_class (context, "progressbar");
|
||||
|
||||
gtk_snapshot_render_background (snapshot, context, clip.x, clip.y, clip.width, clip.height);
|
||||
gtk_snapshot_render_frame (snapshot, context, clip.x, clip.y, clip.width, clip.height);
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
}
|
||||
|
||||
if (priv->label)
|
||||
{
|
||||
float text_xalign;
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, priv->label);
|
||||
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
||||
|
||||
if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
|
||||
text_xalign = 1.0 - priv->text_xalign;
|
||||
else
|
||||
text_xalign = priv->text_xalign;
|
||||
|
||||
x_pos = x + padding.left + text_xalign *
|
||||
(w - padding.left - padding.right - logical_rect.width);
|
||||
|
||||
y_pos = y + padding.top + priv->text_yalign *
|
||||
(h - padding.top - padding.bottom - logical_rect.height);
|
||||
|
||||
gtk_snapshot_push_clip (snapshot,
|
||||
&GRAPHENE_RECT_INIT(
|
||||
clip.x, clip.y,
|
||||
clip.width, clip.height
|
||||
));
|
||||
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_add_class (context, "progressbar");
|
||||
|
||||
gtk_snapshot_render_layout (snapshot, context,
|
||||
x_pos, y_pos,
|
||||
layout);
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_add_class (context, "trough");
|
||||
|
||||
if (bar_position > start)
|
||||
{
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
clip.x = x;
|
||||
clip.width = bar_position - x;
|
||||
}
|
||||
else
|
||||
{
|
||||
clip.y = y;
|
||||
clip.height = bar_position - y;
|
||||
}
|
||||
|
||||
gtk_snapshot_push_clip (snapshot,
|
||||
&GRAPHENE_RECT_INIT(
|
||||
clip.x, clip.y,
|
||||
clip.width, clip.height
|
||||
));
|
||||
|
||||
gtk_snapshot_render_layout (snapshot, context,
|
||||
x_pos, y_pos,
|
||||
layout);
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
if (bar_position + bar_size < start + full_size)
|
||||
{
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
clip.x = bar_position + bar_size;
|
||||
clip.width = x + w - (bar_position + bar_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
clip.y = bar_position + bar_size;
|
||||
clip.height = y + h - (bar_position + bar_size);
|
||||
}
|
||||
|
||||
gtk_snapshot_push_clip (snapshot,
|
||||
&GRAPHENE_RECT_INIT(
|
||||
clip.x, clip.y,
|
||||
clip.width, clip.height
|
||||
));
|
||||
|
||||
gtk_snapshot_render_layout (snapshot, context,
|
||||
x_pos, y_pos,
|
||||
layout);
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
g_object_unref (layout);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_class_init (SysprofCellRendererProgressClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_cell_renderer_progress_finalize;
|
||||
object_class->get_property = sysprof_cell_renderer_progress_get_property;
|
||||
object_class->set_property = sysprof_cell_renderer_progress_set_property;
|
||||
|
||||
cell_class->get_preferred_width = sysprof_cell_renderer_progress_get_preferred_width;
|
||||
cell_class->get_preferred_height = sysprof_cell_renderer_progress_get_preferred_height;
|
||||
cell_class->snapshot = sysprof_cell_renderer_progress_snapshot;
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:value:
|
||||
*
|
||||
* The "value" property determines the percentage to which the
|
||||
* progress bar will be "filled in".
|
||||
**/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_VALUE,
|
||||
g_param_spec_int ("value",
|
||||
"Value",
|
||||
"Value of the progress bar",
|
||||
0, 100, 0,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:text:
|
||||
*
|
||||
* The "text" property determines the label which will be drawn
|
||||
* over the progress bar. Setting this property to %NULL causes the default
|
||||
* label to be displayed. Setting this property to an empty string causes
|
||||
* no label to be displayed.
|
||||
**/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_TEXT,
|
||||
g_param_spec_string ("text",
|
||||
"Text",
|
||||
"Text on the progress bar",
|
||||
NULL,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:pulse:
|
||||
*
|
||||
* Setting this to a non-negative value causes the cell renderer to
|
||||
* enter "activity mode", where a block bounces back and forth to
|
||||
* indicate that some progress is made, without specifying exactly how
|
||||
* much.
|
||||
*
|
||||
* Each increment of the property causes the block to move by a little
|
||||
* bit.
|
||||
*
|
||||
* To indicate that the activity has not started yet, set the property
|
||||
* to zero. To indicate completion, set the property to %G_MAXINT.
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PULSE,
|
||||
g_param_spec_int ("pulse",
|
||||
"Pulse",
|
||||
"Set this to positive values to indicate that some progress is made, but you don’t know how much.",
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:text-xalign:
|
||||
*
|
||||
* The "text-xalign" property controls the horizontal alignment of the
|
||||
* text in the progress bar. Valid values range from 0 (left) to 1
|
||||
* (right). Reserved for RTL layouts.
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_TEXT_XALIGN,
|
||||
g_param_spec_float ("text-xalign",
|
||||
"Text x alignment",
|
||||
"The horizontal text alignment, from 0 (left) to 1 (right). Reversed for RTL layouts.",
|
||||
0.0, 1.0, 0.5,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* SysprofCellRendererProgress:text-yalign:
|
||||
*
|
||||
* The "text-yalign" property controls the vertical alignment of the
|
||||
* text in the progress bar. Valid values range from 0 (top) to 1
|
||||
* (bottom).
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_TEXT_YALIGN,
|
||||
g_param_spec_float ("text-yalign",
|
||||
"Text y alignment",
|
||||
"The vertical text alignment, from 0 (top) to 1 (bottom).",
|
||||
0.0, 1.0, 0.5,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_override_property (object_class,
|
||||
PROP_ORIENTATION,
|
||||
"orientation");
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_INVERTED,
|
||||
g_param_spec_boolean ("inverted",
|
||||
"Inverted",
|
||||
"Invert the direction in which the progress bar grows",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cell_renderer_progress_init (SysprofCellRendererProgress *cellprogress)
|
||||
{
|
||||
SysprofCellRendererProgressPrivate *priv = sysprof_cell_renderer_progress_get_instance_private (cellprogress);
|
||||
|
||||
priv->value = 0;
|
||||
priv->text = NULL;
|
||||
priv->label = NULL;
|
||||
priv->min_w = -1;
|
||||
priv->min_h = -1;
|
||||
priv->pulse = -1;
|
||||
priv->offset = 0;
|
||||
|
||||
priv->text_xalign = 0.5;
|
||||
priv->text_yalign = 0.5;
|
||||
|
||||
priv->orientation = GTK_ORIENTATION_HORIZONTAL,
|
||||
priv->inverted = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_cell_renderer_progress_new:
|
||||
*
|
||||
* Creates a new `SysprofCellRendererProgress`.
|
||||
*
|
||||
* Returns: the new cell renderer
|
||||
**/
|
||||
GtkCellRenderer*
|
||||
sysprof_cell_renderer_progress_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_CELL_RENDERER_PROGRESS, NULL);
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
/* gtkcellrendererprogress.h
|
||||
* Copyright (C) 2002 Naba Kumar <kh_naba@users.sourceforge.net>
|
||||
* modified by Jörgen Scheibengruber <mfcn@gmx.de>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2004. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CELL_RENDERER_PROGRESS (sysprof_cell_renderer_progress_get_type ())
|
||||
#define SYSPROF_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SYSPROF_TYPE_CELL_RENDERER_PROGRESS, SysprofCellRendererProgress))
|
||||
#define SYSPROF_IS_CELL_RENDERER_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SYSPROF_TYPE_CELL_RENDERER_PROGRESS))
|
||||
|
||||
typedef struct _SysprofCellRendererProgress SysprofCellRendererProgress;
|
||||
typedef struct _SysprofCellRendererProgressClass SysprofCellRendererProgressClass;
|
||||
typedef struct _SysprofCellRendererProgressPrivate SysprofCellRendererProgressPrivate;
|
||||
|
||||
struct _SysprofCellRendererProgress
|
||||
{
|
||||
GtkCellRenderer parent_instance;
|
||||
};
|
||||
|
||||
struct _SysprofCellRendererProgressClass
|
||||
{
|
||||
GtkCellRendererClass parent_class;
|
||||
};
|
||||
|
||||
GType sysprof_cell_renderer_progress_get_type (void) G_GNUC_CONST;
|
||||
GtkCellRenderer *sysprof_cell_renderer_progress_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,106 +0,0 @@
|
||||
/* sysprof-check.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-check"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-check.h"
|
||||
|
||||
static void
|
||||
sysprof_check_supported_ping_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusConnection *bus = (GDBusConnection *)object;
|
||||
g_autoptr(GVariant) reply = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GTask) task = user_data;
|
||||
|
||||
g_assert (G_IS_DBUS_CONNECTION (bus));
|
||||
g_assert (G_IS_ASYNC_RESULT (result));
|
||||
g_assert (G_IS_TASK (task));
|
||||
|
||||
if (!(reply = g_dbus_connection_call_finish (bus, result, &error)))
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_check_supported_bus_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GDBusConnection) bus = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GTask) task = user_data;
|
||||
|
||||
g_assert (G_IS_ASYNC_RESULT (result));
|
||||
g_assert (G_IS_TASK (task));
|
||||
|
||||
if (!(bus = g_bus_get_finish (result, &error)))
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
else
|
||||
g_dbus_connection_call (bus,
|
||||
"org.gnome.Sysprof3",
|
||||
"/org/gnome/Sysprof3",
|
||||
"org.freedesktop.DBus.Peer",
|
||||
"Ping",
|
||||
g_variant_new ("()"),
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
g_task_get_cancellable (task),
|
||||
sysprof_check_supported_ping_cb,
|
||||
g_object_ref (task));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_check_supported_async (GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_check_supported_async);
|
||||
|
||||
/* Get access to the System D-Bus and check to see if we can ping the
|
||||
* service that is found at org.gnome.Sysprof3.
|
||||
*/
|
||||
|
||||
g_bus_get (G_BUS_TYPE_SYSTEM,
|
||||
cancellable,
|
||||
sysprof_check_supported_bus_cb,
|
||||
g_steal_pointer (&task));
|
||||
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_check_supported_finish (GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_TASK (result), FALSE);
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
/* sysprof-check.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-version-macros.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_check_supported_async (GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_check_supported_finish (GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,157 +0,0 @@
|
||||
/* sysprof-color-cycle.c
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-color-cycle"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
|
||||
G_DEFINE_BOXED_TYPE (SysprofColorCycle, sysprof_color_cycle, sysprof_color_cycle_ref, sysprof_color_cycle_unref)
|
||||
|
||||
static const gchar *default_colors[] = {
|
||||
|
||||
"#1a5fb4", /* Blue 5 */
|
||||
"#26a269", /* Green 5 */
|
||||
"#e5a50a", /* Yellow 5 */
|
||||
"#c64600", /* Orange 5 */
|
||||
"#a51d2d", /* Red 5 */
|
||||
"#613583", /* Purple 5 */
|
||||
"#63452c", /* Brown 5 */
|
||||
|
||||
"#1c71d8", /* Blue 4 */
|
||||
"#2ec27e", /* Green 4 */
|
||||
"#f5c211", /* Yellow 4 */
|
||||
"#e66100", /* Orange 4 */
|
||||
"#c01c28", /* Red 4 */
|
||||
"#813d9c", /* Purple 4 */
|
||||
"#865e3c", /* Brown 4 */
|
||||
|
||||
"#3584e4", /* Blue 3 */
|
||||
"#33d17a", /* Green 3 */
|
||||
"#f6d32d", /* Yellow 3 */
|
||||
"#ff7800", /* Orange 3 */
|
||||
"#e01b24", /* Red 3 */
|
||||
"#9141ac", /* Purple 3 */
|
||||
"#986a44", /* Brown 3 */
|
||||
|
||||
"#62a0ea", /* Blue 2 */
|
||||
"#57e389", /* Green 2 */
|
||||
"#f8e45c", /* Yellow 2 */
|
||||
"#ffa348", /* Orange 2 */
|
||||
"#ed333b", /* Red 2 */
|
||||
"#c061cb", /* Purple 2 */
|
||||
"#b5835a", /* Brown 2 */
|
||||
|
||||
"#99c1f1", /* Blue 1 */
|
||||
"#8ff0a4", /* Green 1 */
|
||||
"#f9f06b", /* Yellow 1 */
|
||||
"#ffbe6f", /* Orange 1 */
|
||||
"#f66151", /* Red 1 */
|
||||
"#dc8add", /* Purple 1 */
|
||||
"#cdab8f", /* Brown 1 */
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
struct _SysprofColorCycle
|
||||
{
|
||||
volatile gint ref_count;
|
||||
GdkRGBA *colors;
|
||||
gsize n_colors;
|
||||
guint position;
|
||||
};
|
||||
|
||||
static void
|
||||
sysprof_color_cycle_destroy (SysprofColorCycle *self)
|
||||
{
|
||||
g_free (self->colors);
|
||||
g_slice_free (SysprofColorCycle, self);
|
||||
}
|
||||
|
||||
SysprofColorCycle *
|
||||
sysprof_color_cycle_new (void)
|
||||
{
|
||||
SysprofColorCycle *self;
|
||||
|
||||
self = g_slice_new0 (SysprofColorCycle);
|
||||
self->ref_count = 1;
|
||||
self->n_colors = g_strv_length ((gchar **)default_colors);
|
||||
self->colors = g_new0 (GdkRGBA, self->n_colors);
|
||||
|
||||
for (guint i = 0; default_colors[i]; i++)
|
||||
{
|
||||
if G_UNLIKELY (!gdk_rgba_parse (&self->colors[i], default_colors[i]))
|
||||
g_warning ("Failed to parse color %s into an RGBA", default_colors[i]);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
SysprofColorCycle *
|
||||
sysprof_color_cycle_ref (SysprofColorCycle *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
g_return_val_if_fail (self->ref_count > 0, NULL);
|
||||
g_atomic_int_inc (&self->ref_count);
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_color_cycle_unref (SysprofColorCycle *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->ref_count > 0);
|
||||
if (g_atomic_int_dec_and_test (&self->ref_count))
|
||||
sysprof_color_cycle_destroy (self);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_color_cycle_next (SysprofColorCycle *self,
|
||||
GdkRGBA *rgba)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->position < self->n_colors);
|
||||
|
||||
*rgba = self->colors[self->position];
|
||||
|
||||
/*
|
||||
* TODO: Adjust color HSV/etc
|
||||
*
|
||||
* We could simply adjust the brightness/etc after we dispatch
|
||||
* a color so that we get darker as we go.
|
||||
*/
|
||||
|
||||
self->position = (self->position + 1) % self->n_colors;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_color_cycle_reset (SysprofColorCycle *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
for (guint i = 0; default_colors[i]; i++)
|
||||
{
|
||||
if G_UNLIKELY (!gdk_rgba_parse (&self->colors[i], default_colors[i]))
|
||||
g_warning ("Failed to parse color %s into an RGBA", default_colors[i]);
|
||||
}
|
||||
|
||||
self->position = 0;
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
/* sysprof-color-cycle.h
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_COLOR_CYCLE (sysprof_color_cycle_get_type())
|
||||
|
||||
typedef struct _SysprofColorCycle SysprofColorCycle;
|
||||
|
||||
GType sysprof_color_cycle_get_type (void);
|
||||
SysprofColorCycle *sysprof_color_cycle_ref (SysprofColorCycle *self);
|
||||
void sysprof_color_cycle_unref (SysprofColorCycle *self);
|
||||
SysprofColorCycle *sysprof_color_cycle_new (void);
|
||||
void sysprof_color_cycle_reset (SysprofColorCycle *self);
|
||||
void sysprof_color_cycle_next (SysprofColorCycle *self,
|
||||
GdkRGBA *rgba);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SysprofColorCycle, sysprof_color_cycle_unref)
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,284 +0,0 @@
|
||||
/* sysprof-counters-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-counters-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-counters-aid.h"
|
||||
#include "sysprof-line-visualizer.h"
|
||||
#include "sysprof-marks-page.h"
|
||||
#include "sysprof-time-visualizer.h"
|
||||
|
||||
struct _SysprofCountersAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofCountersAid, sysprof_counters_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
static void
|
||||
on_group_activated_cb (SysprofVisualizerGroup *group,
|
||||
SysprofPage *page)
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
|
||||
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
|
||||
g_assert (SYSPROF_IS_PAGE (page));
|
||||
|
||||
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
|
||||
sysprof_display_set_visible_page (display, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_counters_aid_new:
|
||||
*
|
||||
* Create a new #SysprofCountersAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofCountersAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_counters_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_COUNTERS_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
}
|
||||
|
||||
static gchar *
|
||||
build_title (const SysprofCaptureCounter *ctr)
|
||||
{
|
||||
GString *str;
|
||||
|
||||
str = g_string_new (NULL);
|
||||
|
||||
if (ctr->category[0] != 0)
|
||||
{
|
||||
if (str->len)
|
||||
g_string_append_c (str, ' ');
|
||||
g_string_append (str, ctr->category);
|
||||
}
|
||||
|
||||
if (ctr->name[0] != 0)
|
||||
{
|
||||
if (str->len)
|
||||
g_string_append (str, " — ");
|
||||
g_string_append (str, ctr->name);
|
||||
}
|
||||
|
||||
if (ctr->description[0] != 0)
|
||||
{
|
||||
if (str->len)
|
||||
g_string_append_printf (str, " (%s)", ctr->description);
|
||||
else
|
||||
g_string_append (str, ctr->description);
|
||||
}
|
||||
|
||||
if (str->len == 0)
|
||||
/* this is untranslated on purpose */
|
||||
g_string_append_printf (str, "Counter %d", ctr->id);
|
||||
|
||||
return g_string_free (str, FALSE);
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_counters (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
GArray *counters = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (counters != NULL);
|
||||
|
||||
if (def->n_counters > 0)
|
||||
g_array_append_vals (counters, def->counters, def->n_counters);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *present = task_data;
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_COUNTERS_AID (source_object));
|
||||
g_assert (present != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
|
||||
sysprof_capture_cursor_foreach (present->cursor, collect_counters, counters);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&counters),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_COUNTERS_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_counters_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_counters_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_counters_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
Present *present;
|
||||
|
||||
g_assert (SYSPROF_IS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
present = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if ((counters = g_task_propagate_pointer (G_TASK (result), error)) && counters->len > 0)
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *group;
|
||||
SysprofVisualizer *combined;
|
||||
GtkWidget *page;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"has-page", TRUE,
|
||||
"title", _("Counters"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
combined = g_object_new (SYSPROF_TYPE_TIME_VISUALIZER,
|
||||
"title", _("Counters"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (group, combined, -1, TRUE);
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
g_autofree gchar *title = build_title (ctr);
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", title,
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
NULL);
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
rgba.alpha = .5;
|
||||
sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_time_visualizer_add_counter (SYSPROF_TIME_VISUALIZER (combined), ctr->id, &rgba);
|
||||
sysprof_visualizer_group_insert (group, SYSPROF_VISUALIZER (row), -1, TRUE);
|
||||
}
|
||||
|
||||
sysprof_display_add_group (present->display, group);
|
||||
|
||||
page = sysprof_marks_page_new (sysprof_display_get_zoom_manager (present->display),
|
||||
SYSPROF_MARKS_MODEL_COUNTERS);
|
||||
gtk_widget_show (page);
|
||||
|
||||
g_signal_connect_object (group,
|
||||
"group-activated",
|
||||
G_CALLBACK (on_group_activated_cb),
|
||||
page,
|
||||
0);
|
||||
sysprof_display_add_page (present->display, SYSPROF_PAGE (page));
|
||||
}
|
||||
|
||||
return counters != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_class_init (SysprofCountersAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_counters_aid_prepare;
|
||||
aid_class->present_async = sysprof_counters_aid_present_async;
|
||||
aid_class->present_finish = sysprof_counters_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_counters_aid_init (SysprofCountersAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Counters"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-counters-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_COUNTERS_AID (sysprof_counters_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofCountersAid, sysprof_counters_aid, SYSPROF, COUNTERS_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_counters_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,357 +0,0 @@
|
||||
/* sysprof-cpu-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-cpu-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-cpu-aid.h"
|
||||
#include "sysprof-line-visualizer.h"
|
||||
#include "sysprof-procs-visualizer.h"
|
||||
|
||||
struct _SysprofCpuAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
GArray *counters;
|
||||
guint has_processes : 1;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofCpuAid, sysprof_cpu_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_pointer (&p->counters, g_array_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_cpu_aid_new:
|
||||
*
|
||||
* Create a new #SysprofCpuAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofCpuAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_cpu_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_CPU_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
#ifdef __linux__
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_CPU_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
source = sysprof_hostinfo_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_info (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
Present *p = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (p != NULL);
|
||||
g_assert (p->counters != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF)
|
||||
{
|
||||
for (guint i = 0; i < def->n_counters; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *counter = &def->counters[i];
|
||||
|
||||
if (g_strcmp0 (counter->category, "CPU Percent") == 0 ||
|
||||
g_strcmp0 (counter->category, "CPU Frequency") == 0)
|
||||
g_array_append_vals (p->counters, counter, 1);
|
||||
}
|
||||
}
|
||||
else if (!p->has_processes &&
|
||||
(frame->type == SYSPROF_CAPTURE_FRAME_PROCESS ||
|
||||
frame->type == SYSPROF_CAPTURE_FRAME_EXIT))
|
||||
{
|
||||
p->has_processes = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *present = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_CPU_AID (source_object));
|
||||
g_assert (present != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
sysprof_capture_cursor_foreach (present->cursor, collect_info, present);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&present->counters),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = {
|
||||
SYSPROF_CAPTURE_FRAME_CTRDEF,
|
||||
SYSPROF_CAPTURE_FRAME_PROCESS,
|
||||
SYSPROF_CAPTURE_FRAME_EXIT,
|
||||
};
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_CPU_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
present.counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
|
||||
present.has_processes = FALSE;
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_cpu_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_cpu_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_cpu_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
Present *present;
|
||||
|
||||
g_assert (SYSPROF_IS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
present = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
g_autoptr(SysprofColorCycle) freq_cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *usage;
|
||||
SysprofVisualizerGroup *freq;
|
||||
SysprofVisualizer *freq_row = NULL;
|
||||
SysprofVisualizer *over_row = NULL;
|
||||
gboolean found_combined = FALSE;
|
||||
gboolean has_usage = FALSE;
|
||||
gboolean has_freq = FALSE;
|
||||
|
||||
usage = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"priority", -1000,
|
||||
"title", _("CPU Usage"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
freq = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"priority", -999,
|
||||
"title", _("CPU Frequency"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
freq_row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", _("CPU Frequency (All)"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (freq, freq_row, -1, FALSE);
|
||||
|
||||
over_row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", _("CPU Usage (All)"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_strcmp0 (ctr->category, "CPU Percent") == 0)
|
||||
{
|
||||
if (strstr (ctr->name, "Combined") != NULL)
|
||||
{
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
found_combined = TRUE;
|
||||
|
||||
gdk_rgba_parse (&rgba, "#1a5fb4");
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
/* Translators: CPU is the processor. */
|
||||
"title", _("CPU Usage (All)"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
rgba.alpha = 0.5;
|
||||
sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), 0, FALSE);
|
||||
has_usage = TRUE;
|
||||
}
|
||||
else if (g_str_has_prefix (ctr->name, "Total CPU "))
|
||||
{
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", ctr->name,
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (over_row), ctr->id, &rgba);
|
||||
rgba.alpha = 0.5;
|
||||
sysprof_line_visualizer_set_fill (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), -1, TRUE);
|
||||
has_usage = TRUE;
|
||||
}
|
||||
}
|
||||
else if (g_strcmp0 (ctr->category, "CPU Frequency") == 0)
|
||||
{
|
||||
if (g_str_has_prefix (ctr->name, "CPU "))
|
||||
{
|
||||
g_autofree gchar *title = g_strdup_printf ("%s Frequency", ctr->name);
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
|
||||
sysprof_color_cycle_next (freq_cycle, &rgba);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (freq_row), ctr->id, &rgba);
|
||||
sysprof_line_visualizer_set_dash (SYSPROF_LINE_VISUALIZER (freq_row), ctr->id, TRUE);
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_LINE_VISUALIZER,
|
||||
"title", title,
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
"y-lower", 0.0,
|
||||
"y-upper", 100.0,
|
||||
NULL);
|
||||
sysprof_line_visualizer_add_counter (SYSPROF_LINE_VISUALIZER (row), ctr->id, &rgba);
|
||||
sysprof_line_visualizer_set_dash (SYSPROF_LINE_VISUALIZER (row), ctr->id, TRUE);
|
||||
sysprof_visualizer_group_insert (freq, SYSPROF_VISUALIZER (row), -1, TRUE);
|
||||
|
||||
has_freq = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (present->has_processes)
|
||||
{
|
||||
GtkWidget *row;
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_PROCS_VISUALIZER,
|
||||
"title", _("Processes"),
|
||||
"height-request", 35,
|
||||
"visible", FALSE,
|
||||
NULL);
|
||||
sysprof_visualizer_group_insert (usage, SYSPROF_VISUALIZER (row), -1, TRUE);
|
||||
}
|
||||
|
||||
if (has_usage && !found_combined)
|
||||
sysprof_visualizer_group_insert (usage, over_row, 0, FALSE);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (over_row));
|
||||
|
||||
if (has_usage)
|
||||
sysprof_display_add_group (present->display, usage);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (usage));
|
||||
|
||||
if (has_freq)
|
||||
sysprof_display_add_group (present->display, freq);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (freq));
|
||||
}
|
||||
|
||||
return counters != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_class_init (SysprofCpuAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_cpu_aid_prepare;
|
||||
aid_class->present_async = sysprof_cpu_aid_present_async;
|
||||
aid_class->present_finish = sysprof_cpu_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_cpu_aid_init (SysprofCpuAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("CPU Usage"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-cpu-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CPU_AID (sysprof_cpu_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofCpuAid, sysprof_cpu_aid, SYSPROF, CPU_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_cpu_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,453 +0,0 @@
|
||||
/* sysprof-depth-visualizer.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-depth-visualizer"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "pointcache.h"
|
||||
#include "sysprof-depth-visualizer.h"
|
||||
|
||||
struct _SysprofDepthVisualizer
|
||||
{
|
||||
SysprofVisualizer parent_instance;
|
||||
SysprofCaptureReader *reader;
|
||||
PointCache *points;
|
||||
guint reload_source;
|
||||
guint mode;
|
||||
int last_width;
|
||||
int last_height;
|
||||
guint reloading : 1;
|
||||
guint needs_reload : 1;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureReader *reader;
|
||||
PointCache *pc;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
gint64 duration;
|
||||
guint max_n_addrs;
|
||||
guint mode;
|
||||
} State;
|
||||
|
||||
static void sysprof_depth_visualizer_reload (SysprofDepthVisualizer *self);
|
||||
|
||||
G_DEFINE_TYPE (SysprofDepthVisualizer, sysprof_depth_visualizer, SYSPROF_TYPE_VISUALIZER)
|
||||
|
||||
static void
|
||||
state_free (State *st)
|
||||
{
|
||||
g_clear_pointer (&st->reader, sysprof_capture_reader_unref);
|
||||
g_clear_pointer (&st->pc, point_cache_unref);
|
||||
g_slice_free (State, st);
|
||||
}
|
||||
|
||||
static bool
|
||||
discover_max_n_addr (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
|
||||
State *st = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
|
||||
g_assert (st != NULL);
|
||||
|
||||
st->max_n_addrs = MAX (st->max_n_addrs, sample->n_addrs);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
build_point_cache_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
const SysprofCaptureSample *sample = (const SysprofCaptureSample *)frame;
|
||||
State *st = user_data;
|
||||
gdouble x, y;
|
||||
gboolean has_kernel = FALSE;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_SAMPLE);
|
||||
g_assert (st != NULL);
|
||||
|
||||
x = (frame->time - st->begin_time) / (gdouble)st->duration;
|
||||
y = sample->n_addrs / (gdouble)st->max_n_addrs;
|
||||
|
||||
/* If this contains a context-switch (meaning we're going into the kernel
|
||||
* to do some work, use a negative value for Y so that we know later on
|
||||
* that we should draw it with a different color (after removing the negation
|
||||
* on the value.
|
||||
*
|
||||
* We skip past the first index, which is always a context switch as it is
|
||||
* our perf handler.
|
||||
*/
|
||||
for (guint i = 1; i < sample->n_addrs; i++)
|
||||
{
|
||||
SysprofAddressContext kind;
|
||||
|
||||
if (sysprof_address_is_context_switch (sample->addrs[i], &kind))
|
||||
{
|
||||
has_kernel = TRUE;
|
||||
y = -y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_kernel)
|
||||
point_cache_add_point_to_set (st->pc, 1, x, y);
|
||||
else
|
||||
point_cache_add_point_to_set (st->pc, 2, x, y);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_SAMPLE, };
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
SysprofCaptureCondition *condition;
|
||||
State *st = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (source_object));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
if (st->duration != 0)
|
||||
{
|
||||
cursor = sysprof_capture_cursor_new (st->reader);
|
||||
condition = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, discover_max_n_addr, st);
|
||||
sysprof_capture_cursor_reset (cursor);
|
||||
sysprof_capture_cursor_foreach (cursor, build_point_cache_cb, st);
|
||||
}
|
||||
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&st->pc),
|
||||
(GDestroyNotify) point_cache_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
apply_point_cache_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)object;
|
||||
PointCache *pc;
|
||||
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
self->reloading = FALSE;
|
||||
|
||||
if ((pc = g_task_propagate_pointer (G_TASK (result), NULL)))
|
||||
{
|
||||
g_clear_pointer (&self->points, point_cache_unref);
|
||||
self->points = g_steal_pointer (&pc);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
if (self->needs_reload)
|
||||
sysprof_depth_visualizer_reload (self);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_reload (SysprofDepthVisualizer *self)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
GtkAllocation alloc;
|
||||
State *st;
|
||||
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
|
||||
self->needs_reload = TRUE;
|
||||
|
||||
if (self->reloading)
|
||||
return;
|
||||
|
||||
self->reloading = TRUE;
|
||||
self->needs_reload = FALSE;
|
||||
|
||||
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
|
||||
|
||||
st = g_slice_new0 (State);
|
||||
st->reader = sysprof_capture_reader_ref (self->reader);
|
||||
st->pc = point_cache_new ();
|
||||
st->max_n_addrs = 0;
|
||||
st->begin_time = sysprof_capture_reader_get_start_time (self->reader);
|
||||
st->end_time = sysprof_capture_reader_get_end_time (self->reader);
|
||||
st->duration = st->end_time - st->begin_time;
|
||||
st->mode = self->mode;
|
||||
|
||||
point_cache_add_set (st->pc, 1);
|
||||
point_cache_add_set (st->pc, 2);
|
||||
|
||||
task = g_task_new (self, NULL, apply_point_cache_cb, NULL);
|
||||
g_task_set_source_tag (task, sysprof_depth_visualizer_reload);
|
||||
g_task_set_task_data (task, st, (GDestroyNotify) state_free);
|
||||
g_task_run_in_thread (task, sysprof_depth_visualizer_worker);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_set_reader (SysprofVisualizer *row,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)row;
|
||||
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
|
||||
if (self->reader != reader)
|
||||
{
|
||||
if (self->reader != NULL)
|
||||
{
|
||||
sysprof_capture_reader_unref (self->reader);
|
||||
self->reader = NULL;
|
||||
}
|
||||
|
||||
if (reader != NULL)
|
||||
{
|
||||
self->reader = sysprof_capture_reader_ref (reader);
|
||||
sysprof_depth_visualizer_reload (self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)widget;
|
||||
GtkAllocation alloc;
|
||||
GdkRectangle clip;
|
||||
const Point *points;
|
||||
cairo_t *cr;
|
||||
guint n_points = 0;
|
||||
GdkRGBA user;
|
||||
GdkRGBA system;
|
||||
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
g_assert (snapshot != NULL);
|
||||
|
||||
GTK_WIDGET_CLASS (sysprof_depth_visualizer_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
if (self->points == NULL)
|
||||
return;
|
||||
|
||||
gdk_rgba_parse (&user, "#1a5fb4");
|
||||
gdk_rgba_parse (&system, "#3584e4");
|
||||
|
||||
gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
|
||||
|
||||
/* FIXME: we should abstract visualizer drawing into regions so that we
|
||||
* can still know the region we're drawing.
|
||||
*/
|
||||
#if 0
|
||||
if (!gdk_cairo_get_clip_rectangle (cr, &clip))
|
||||
return;
|
||||
#else
|
||||
clip.x = alloc.x = 0;
|
||||
clip.y = alloc.y = 0;
|
||||
clip.width = alloc.width;
|
||||
clip.height = alloc.height;
|
||||
#endif
|
||||
|
||||
/* Draw user-space stacks */
|
||||
if (self->mode != SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY &&
|
||||
(points = point_cache_get_points (self->points, 1, &n_points)))
|
||||
{
|
||||
g_autofree SysprofVisualizerAbsolutePoint *out_points = NULL;
|
||||
|
||||
out_points = g_new (SysprofVisualizerAbsolutePoint, n_points);
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (widget),
|
||||
(const SysprofVisualizerRelativePoint *)points,
|
||||
n_points, out_points, n_points);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
gdk_cairo_set_source_rgba (cr, &user);
|
||||
|
||||
for (guint i = 0; i < n_points; i++)
|
||||
{
|
||||
gdouble x, y;
|
||||
|
||||
x = out_points[i].x;
|
||||
y = out_points[i].y;
|
||||
|
||||
if (x < clip.x)
|
||||
continue;
|
||||
|
||||
if (x > clip.x + clip.width)
|
||||
break;
|
||||
|
||||
for (guint j = i + 1; j < n_points; j++)
|
||||
{
|
||||
if (out_points[j].x != x)
|
||||
break;
|
||||
|
||||
y = MIN (y, out_points[j].y);
|
||||
}
|
||||
|
||||
x += alloc.x;
|
||||
|
||||
cairo_move_to (cr, (guint)x + .5, alloc.height);
|
||||
cairo_line_to (cr, (guint)x + .5, y);
|
||||
}
|
||||
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
/* Draw kernel-space stacks */
|
||||
if (self->mode != SYSPROF_DEPTH_VISUALIZER_USER_ONLY &&
|
||||
(points = point_cache_get_points (self->points, 2, &n_points)))
|
||||
{
|
||||
g_autofree SysprofVisualizerAbsolutePoint *out_points = NULL;
|
||||
|
||||
out_points = g_new (SysprofVisualizerAbsolutePoint, n_points);
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (widget),
|
||||
(const SysprofVisualizerRelativePoint *)points,
|
||||
n_points, out_points, n_points);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
gdk_cairo_set_source_rgba (cr, &system);
|
||||
|
||||
for (guint i = 0; i < n_points; i++)
|
||||
{
|
||||
gdouble x, y;
|
||||
|
||||
x = out_points[i].x;
|
||||
y = out_points[i].y;
|
||||
|
||||
if (x < clip.x)
|
||||
continue;
|
||||
|
||||
if (x > clip.x + clip.width)
|
||||
break;
|
||||
|
||||
for (guint j = i + 1; j < n_points; j++)
|
||||
{
|
||||
if (out_points[j].x != x)
|
||||
break;
|
||||
|
||||
y = MIN (y, out_points[j].y);
|
||||
}
|
||||
|
||||
x += alloc.x;
|
||||
|
||||
cairo_move_to (cr, (guint)x + .5, alloc.height);
|
||||
cairo_line_to (cr, (guint)x + .5, y);
|
||||
}
|
||||
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_depth_visualizer_do_reload (gpointer data)
|
||||
{
|
||||
SysprofDepthVisualizer *self = data;
|
||||
self->reload_source = 0;
|
||||
sysprof_depth_visualizer_reload (self);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_queue_reload (SysprofDepthVisualizer *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_DEPTH_VISUALIZER (self));
|
||||
|
||||
g_clear_handle_id (&self->reload_source, g_source_remove);
|
||||
self->reload_source = g_idle_add (sysprof_depth_visualizer_do_reload, self);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)widget;
|
||||
|
||||
if (width != self->last_width || height != self->last_height)
|
||||
{
|
||||
sysprof_depth_visualizer_queue_reload (SYSPROF_DEPTH_VISUALIZER (widget));
|
||||
self->last_width = width;
|
||||
self->last_height = height;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofDepthVisualizer *self = (SysprofDepthVisualizer *)object;
|
||||
|
||||
g_clear_pointer (&self->reader, sysprof_capture_reader_unref);
|
||||
g_clear_handle_id (&self->reload_source, g_source_remove);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_depth_visualizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_class_init (SysprofDepthVisualizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofVisualizerClass *row_class = SYSPROF_VISUALIZER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_depth_visualizer_finalize;
|
||||
|
||||
widget_class->snapshot = sysprof_depth_visualizer_snapshot;
|
||||
widget_class->size_allocate = sysprof_depth_visualizer_size_allocate;
|
||||
|
||||
row_class->set_reader = sysprof_depth_visualizer_set_reader;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_depth_visualizer_init (SysprofDepthVisualizer *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofVisualizer *
|
||||
sysprof_depth_visualizer_new (SysprofDepthVisualizerMode mode)
|
||||
{
|
||||
SysprofDepthVisualizer *self;
|
||||
|
||||
g_return_val_if_fail (mode == SYSPROF_DEPTH_VISUALIZER_COMBINED ||
|
||||
mode == SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY ||
|
||||
mode == SYSPROF_DEPTH_VISUALIZER_USER_ONLY,
|
||||
NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_DEPTH_VISUALIZER, NULL);
|
||||
self->mode = mode;
|
||||
|
||||
return SYSPROF_VISUALIZER (g_steal_pointer (&self));
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
/* sysprof-depth-visualizer.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-visualizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SYSPROF_DEPTH_VISUALIZER_COMBINED,
|
||||
SYSPROF_DEPTH_VISUALIZER_KERNEL_ONLY,
|
||||
SYSPROF_DEPTH_VISUALIZER_USER_ONLY,
|
||||
} SysprofDepthVisualizerMode;
|
||||
|
||||
#define SYSPROF_TYPE_DEPTH_VISUALIZER (sysprof_depth_visualizer_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDepthVisualizer, sysprof_depth_visualizer, SYSPROF, DEPTH_VISUALIZER, SysprofVisualizer)
|
||||
|
||||
SysprofVisualizer *sysprof_depth_visualizer_new (SysprofDepthVisualizerMode mode);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,325 +0,0 @@
|
||||
/* sysprof-details-page.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-details-page"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sysprof-mark-detail.h"
|
||||
#include "sysprof-details-page.h"
|
||||
#include "sysprof-ui-private.h"
|
||||
|
||||
struct _SysprofDetailsPage
|
||||
{
|
||||
GtkWidget parent_instance ;
|
||||
|
||||
/* Template Objects */
|
||||
|
||||
GListStore *marks_store;
|
||||
GtkSortListModel *mark_sort_model;
|
||||
GtkLabel *counters;
|
||||
GtkLabel *duration;
|
||||
GtkLabel *filename;
|
||||
GtkLabel *allocations;
|
||||
GtkLabel *forks;
|
||||
GtkLabel *marks;
|
||||
GtkLabel *processes;
|
||||
GtkLabel *samples;
|
||||
GtkLabel *start_time;
|
||||
GtkLabel *cpu_label;
|
||||
|
||||
guint next_row;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofDetailsPage, sysprof_details_page, GTK_TYPE_WIDGET)
|
||||
|
||||
#if GLIB_CHECK_VERSION(2, 56, 0)
|
||||
# define _g_date_time_new_from_iso8601 g_date_time_new_from_iso8601
|
||||
#else
|
||||
static GDateTime *
|
||||
_g_date_time_new_from_iso8601 (const gchar *str,
|
||||
GTimeZone *default_tz)
|
||||
{
|
||||
GTimeVal tv;
|
||||
|
||||
if (g_time_val_from_iso8601 (str, &tv))
|
||||
{
|
||||
g_autoptr(GDateTime) dt = g_date_time_new_from_timeval_utc (&tv);
|
||||
|
||||
if (default_tz)
|
||||
return g_date_time_to_timezone (dt, default_tz);
|
||||
else
|
||||
return g_steal_pointer (&dt);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
format_time (GObject *unused,
|
||||
gint64 time)
|
||||
{
|
||||
return time ? _sysprof_format_duration (time) : g_strdup("—");
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_dispose (GObject *object)
|
||||
{
|
||||
SysprofDetailsPage *self = (SysprofDetailsPage *)object;
|
||||
GtkWidget *child;
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
|
||||
gtk_widget_unparent (child);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_details_page_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_class_init (SysprofDetailsPageClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_details_page_dispose;
|
||||
|
||||
g_type_ensure (SYSPROF_TYPE_MARK_DETAIL);
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-details-page.ui");
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, allocations);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, counters);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, cpu_label);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, duration);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, filename);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, forks);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, marks);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, marks_store);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, mark_sort_model);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, processes);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, samples);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofDetailsPage, start_time);
|
||||
gtk_widget_class_bind_template_callback (widget_class, format_time);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_init (SysprofDetailsPage *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->next_row = 8;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
sysprof_details_page_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_DETAILS_PAGE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
update_cpu_info_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(SysprofDetailsPage) self = user_data;
|
||||
g_autofree gchar *str = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
if ((str = g_task_propagate_pointer (G_TASK (result), NULL)))
|
||||
gtk_label_set_label (self->cpu_label, str);
|
||||
}
|
||||
|
||||
static bool
|
||||
cpu_info_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
const SysprofCaptureFileChunk *fc = (gpointer)frame;
|
||||
const gchar *endptr;
|
||||
const gchar *line;
|
||||
gchar **str = user_data;
|
||||
|
||||
line = memmem ((gchar *)fc->data, fc->len, "model name", 10);
|
||||
|
||||
if (!line)
|
||||
return FALSE;
|
||||
|
||||
endptr = (gchar *)fc->data + fc->len;
|
||||
endptr = memchr (line, '\n', endptr - line);
|
||||
|
||||
if (endptr)
|
||||
{
|
||||
gchar *tmp = *str = g_strndup (line, endptr - line);
|
||||
for (; *tmp && *tmp != ':'; tmp++)
|
||||
*tmp = ' ';
|
||||
if (*tmp == ':')
|
||||
*tmp = ' ';
|
||||
g_strstrip (*str);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_update_cpu_info_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
SysprofCaptureCursor *cursor = task_data;
|
||||
gchar *str = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (cursor != NULL);
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, cpu_info_cb, &str);
|
||||
g_task_return_pointer (task, g_steal_pointer (&str), g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_details_page_update_cpu_info (SysprofDetailsPage *self,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
g_assert (reader != NULL);
|
||||
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor,
|
||||
sysprof_capture_condition_new_where_file ("/proc/cpuinfo"));
|
||||
|
||||
task = g_task_new (NULL, NULL, update_cpu_info_cb, g_object_ref (self));
|
||||
g_task_set_task_data (task,
|
||||
g_steal_pointer (&cursor),
|
||||
(GDestroyNotify) sysprof_capture_cursor_unref);
|
||||
g_task_run_in_thread (task, sysprof_details_page_update_cpu_info_worker);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_details_page_set_reader (SysprofDetailsPage *self,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
g_autoptr(GDateTime) dt = NULL;
|
||||
g_autoptr(GDateTime) local = NULL;
|
||||
g_autofree gchar *duration_str = NULL;
|
||||
const gchar *filename;
|
||||
const gchar *capture_at;
|
||||
SysprofCaptureStat st_buf;
|
||||
gint64 duration;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
g_return_if_fail (reader != NULL);
|
||||
|
||||
sysprof_details_page_update_cpu_info (self, reader);
|
||||
|
||||
if (!(filename = sysprof_capture_reader_get_filename (reader)))
|
||||
filename = _("Memory Capture");
|
||||
|
||||
gtk_label_set_label (self->filename, filename);
|
||||
|
||||
if ((capture_at = sysprof_capture_reader_get_time (reader)) &&
|
||||
(dt = _g_date_time_new_from_iso8601 (capture_at, NULL)) &&
|
||||
(local = g_date_time_to_local (dt)))
|
||||
{
|
||||
g_autofree gchar *str = g_date_time_format (local, "%x %X");
|
||||
gtk_label_set_label (self->start_time, str);
|
||||
}
|
||||
|
||||
duration = sysprof_capture_reader_get_end_time (reader) -
|
||||
sysprof_capture_reader_get_start_time (reader);
|
||||
duration_str = g_strdup_printf (_("%0.4lf seconds"), duration / (gdouble)SYSPROF_NSEC_PER_SEC);
|
||||
gtk_label_set_label (self->duration, duration_str);
|
||||
|
||||
if (sysprof_capture_reader_get_stat (reader, &st_buf))
|
||||
{
|
||||
#define SET_FRAME_COUNT(field, TYPE) \
|
||||
G_STMT_START { \
|
||||
g_autofree gchar *str = NULL; \
|
||||
str = g_strdup_printf ("%"G_GSIZE_FORMAT, st_buf.frame_count[TYPE]); \
|
||||
gtk_label_set_label (self->field, str); \
|
||||
} G_STMT_END
|
||||
|
||||
SET_FRAME_COUNT (samples, SYSPROF_CAPTURE_FRAME_SAMPLE);
|
||||
SET_FRAME_COUNT (marks, SYSPROF_CAPTURE_FRAME_MARK);
|
||||
SET_FRAME_COUNT (processes, SYSPROF_CAPTURE_FRAME_PROCESS);
|
||||
SET_FRAME_COUNT (forks, SYSPROF_CAPTURE_FRAME_FORK);
|
||||
SET_FRAME_COUNT (counters, SYSPROF_CAPTURE_FRAME_CTRSET);
|
||||
SET_FRAME_COUNT (allocations, SYSPROF_CAPTURE_FRAME_ALLOCATION);
|
||||
|
||||
#undef SET_FRAME_COUNT
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_details_page_add_mark (SysprofDetailsPage *self,
|
||||
const gchar *mark,
|
||||
gint64 min,
|
||||
gint64 max,
|
||||
gint64 avg,
|
||||
gint64 hits)
|
||||
{
|
||||
SysprofMarkDetail *detail;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
|
||||
detail = sysprof_mark_detail_new (mark, min, max, avg, hits);
|
||||
|
||||
g_list_store_append (self->marks_store, detail);
|
||||
/*gtk_list_store_append (self->marks_store, &iter);
|
||||
gtk_list_store_set (self->marks_store, &iter,
|
||||
0, mark,
|
||||
1, min ? _sysprof_format_duration (min) : "—",
|
||||
2, max ? _sysprof_format_duration (max) : "—",
|
||||
3, avg ? _sysprof_format_duration (avg) : "—",
|
||||
4, hits,
|
||||
5, detail,
|
||||
-1);*/
|
||||
g_object_unref (detail);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_details_page_add_marks (SysprofDetailsPage *self,
|
||||
const SysprofMarkStat *marks,
|
||||
guint n_marks)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DETAILS_PAGE (self));
|
||||
g_return_if_fail (marks != NULL || n_marks == 0);
|
||||
|
||||
if (marks == NULL || n_marks == 0)
|
||||
return;
|
||||
|
||||
/* Be reasonable */
|
||||
if (n_marks > 100)
|
||||
n_marks = 100;
|
||||
|
||||
for (guint i = 0; i < n_marks; i++)
|
||||
sysprof_details_page_add_mark (self,
|
||||
marks[i].name,
|
||||
marks[i].min,
|
||||
marks[i].max,
|
||||
marks[i].avg,
|
||||
marks[i].count);
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/* sysprof-details-page.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <sysprof-capture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
SYSPROF_ALIGNED_BEGIN (8)
|
||||
typedef struct
|
||||
{
|
||||
gchar name[152];
|
||||
guint64 count;
|
||||
gint64 max;
|
||||
gint64 min;
|
||||
gint64 avg;
|
||||
guint64 avg_count;
|
||||
} SysprofMarkStat
|
||||
SYSPROF_ALIGNED_END (8);
|
||||
|
||||
#define SYSPROF_TYPE_DETAILS_PAGE (sysprof_details_page_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDetailsPage, sysprof_details_page, SYSPROF, DETAILS_PAGE, GtkWidget)
|
||||
|
||||
GtkWidget *sysprof_details_page_new (void);
|
||||
void sysprof_details_page_set_reader (SysprofDetailsPage *self,
|
||||
SysprofCaptureReader *reader);
|
||||
void sysprof_details_page_add_marks (SysprofDetailsPage *self,
|
||||
const SysprofMarkStat *marks,
|
||||
guint n_marks);
|
||||
void sysprof_details_page_add_mark (SysprofDetailsPage *self,
|
||||
const gchar *mark,
|
||||
gint64 min,
|
||||
gint64 max,
|
||||
gint64 avg,
|
||||
gint64 hits);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,361 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="SysprofDetailsPage" parent="GtkWidget">
|
||||
<child>
|
||||
<object class="AdwPreferencesPage">
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="title" translatable="yes">Capture</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Location</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="filename">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Recorded At</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="start_time">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Duration</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="duration">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">CPU Model</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="cpu_label">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="title" translatable="yes">Statistics</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Stack Traces</property>
|
||||
<property name="subtitle" translatable="yes">Number of stack traces sampled for performance callgraphs</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="samples">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Marks</property>
|
||||
<property name="subtitle" translatable="yes">Number of marks seen</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="marks">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Processes</property>
|
||||
<property name="subtitle" translatable="yes">Number of processes seen</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="processes">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Forks</property>
|
||||
<property name="subtitle" translatable="yes">Number of times a process forked</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="forks">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Memory Allocations</property>
|
||||
<property name="subtitle" translatable="yes">Number of stack traces recorded for tracing memory allocations</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="allocations">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Counters</property>
|
||||
<property name="subtitle" translatable="yes">Number of recorded counter values</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="counters">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="title" translatable="yes">Statistics</property>
|
||||
<child>
|
||||
<object class="GtkColumnView" id="marks_view">
|
||||
<property name="width-request">500</property>
|
||||
<property name="height-request">100</property>
|
||||
<property name="model">
|
||||
<object class="GtkNoSelection">
|
||||
<property name="model">mark_sort_model</property>
|
||||
</object>
|
||||
</property>
|
||||
<style>
|
||||
<class name="data-table"/>
|
||||
<class name="card"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Mark</property>
|
||||
<property name="expand">true</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkStringSorter">
|
||||
<property name="expression">
|
||||
<lookup name="label" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<binding name="label">
|
||||
<lookup name="label" type="SysprofMarkDetail">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Hits</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkNumericSorter">
|
||||
<property name="expression">
|
||||
<lookup name="hits" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<lookup name="hits" type="SysprofMarkDetail">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Min</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkNumericSorter">
|
||||
<property name="expression">
|
||||
<lookup name="min" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<closure type="gchararray" function="format_time">
|
||||
<lookup name='min' type='SysprofMarkDetail'><lookup name='item'>GtkListItem</lookup></lookup>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Max</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkNumericSorter">
|
||||
<property name="expression">
|
||||
<lookup name="max" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<closure type="gchararray" function="format_time">
|
||||
<lookup name='max' type='SysprofMarkDetail'><lookup name='item'>GtkListItem</lookup></lookup>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Avg</property>
|
||||
<property name="sorter">
|
||||
<object class="GtkNumericSorter">
|
||||
<property name="expression">
|
||||
<lookup name="average" type="SysprofMarkDetail"/>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<closure type="gchararray" function="format_time">
|
||||
<lookup name='average' type='SysprofMarkDetail'><lookup name='item'>GtkListItem</lookup></lookup>
|
||||
</closure>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
<object class="GtkSortListModel" id="mark_sort_model">
|
||||
<property name="model">marks_store</property>
|
||||
<property name="incremental">true</property>
|
||||
<binding name="sorter">
|
||||
<lookup name="sorter">marks_view</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
<object class="GListStore" id="marks_store">
|
||||
</object>
|
||||
</interface>
|
||||
@ -1,269 +0,0 @@
|
||||
/* sysprof-diskstat-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-diskstat-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-duplex-visualizer.h"
|
||||
#include "sysprof-diskstat-aid.h"
|
||||
|
||||
struct _SysprofDiskstatAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofDiskstatAid, sysprof_diskstat_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_diskstat_aid_new:
|
||||
*
|
||||
* Create a new #SysprofDiskstatAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofDiskstatAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_diskstat_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_DISKSTAT_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DISKSTAT_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
source = sysprof_diskstat_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_diskstat_counters (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
GArray *counters = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (counters != NULL);
|
||||
|
||||
for (guint i = 0; i < def->n_counters; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *counter = &def->counters[i];
|
||||
|
||||
if (strcmp (counter->category, "Disk") == 0 &&
|
||||
(g_str_has_prefix (counter->name, "Total Reads") ||
|
||||
g_str_has_prefix (counter->name, "Total Writes")))
|
||||
g_array_append_vals (counters, counter, 1);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *present = task_data;
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_DISKSTAT_AID (source_object));
|
||||
g_assert (present != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
|
||||
sysprof_capture_cursor_foreach (present->cursor, collect_diskstat_counters, counters);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&counters),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
}
|
||||
|
||||
static guint
|
||||
find_other_id (GArray *counters,
|
||||
const gchar *name)
|
||||
{
|
||||
g_autofree gchar *other = NULL;
|
||||
|
||||
g_assert (counters);
|
||||
g_assert (name != NULL);
|
||||
g_assert (g_str_has_prefix (name, "Total Reads"));
|
||||
|
||||
other = g_strdup_printf ("Total Writes%s", name + strlen ("Total Reads"));
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *c = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_str_equal (c->name, other))
|
||||
return c->id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_DISKSTAT_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_diskstat_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_diskstat_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_diskstat_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
Present *present;
|
||||
|
||||
g_assert (SYSPROF_IS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
present = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *group;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"title", _("Disk"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_str_has_prefix (ctr->name, "Total Reads"))
|
||||
{
|
||||
g_autofree gchar *title = NULL;
|
||||
gboolean is_combined;
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
guint other_id;
|
||||
|
||||
if (!(other_id = find_other_id (counters, ctr->name)))
|
||||
continue;
|
||||
|
||||
is_combined = g_str_equal (ctr->description, "Combined");
|
||||
|
||||
if (is_combined)
|
||||
title = g_strdup ("Disk Reads/Writes (All)");
|
||||
else
|
||||
title = g_strdup_printf ("Disk Reads/Writes%s", ctr->name + strlen ("Total Reads"));
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_DUPLEX_VISUALIZER,
|
||||
"title", title,
|
||||
"height-request", 35,
|
||||
"visible", is_combined,
|
||||
NULL);
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
sysprof_duplex_visualizer_set_counters (SYSPROF_DUPLEX_VISUALIZER (row), ctr->id, other_id);
|
||||
sysprof_duplex_visualizer_set_colors (SYSPROF_DUPLEX_VISUALIZER (row), &rgba, &rgba);
|
||||
sysprof_duplex_visualizer_set_labels (SYSPROF_DUPLEX_VISUALIZER (row), _("Reads"), _("Writes"));
|
||||
sysprof_duplex_visualizer_set_use_diff (SYSPROF_DUPLEX_VISUALIZER (row), FALSE);
|
||||
sysprof_visualizer_group_insert (group, SYSPROF_VISUALIZER (row), is_combined ? 0 : -1, !is_combined);
|
||||
}
|
||||
}
|
||||
|
||||
if (counters->len > 0)
|
||||
sysprof_display_add_group (present->display, group);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (group));
|
||||
}
|
||||
|
||||
return counters != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_class_init (SysprofDiskstatAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_diskstat_aid_prepare;
|
||||
aid_class->present_async = sysprof_diskstat_aid_present_async;
|
||||
aid_class->present_finish = sysprof_diskstat_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_diskstat_aid_init (SysprofDiskstatAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Disk"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "drive-harddisk-system-symbolic");
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-diskstat-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DISKSTAT_AID (sysprof_diskstat_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDiskstatAid, sysprof_diskstat_aid, SYSPROF, DISKSTAT_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_diskstat_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,29 +0,0 @@
|
||||
/* sysprof-display-private.h
|
||||
*
|
||||
* Copyright 2021 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-display.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void _sysprof_display_destroy (SysprofDisplay *self);
|
||||
|
||||
G_END_DECLS
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,96 +0,0 @@
|
||||
/* sysprof-display.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "sysprof-page.h"
|
||||
#include "sysprof-visualizer-group.h"
|
||||
#include "sysprof-zoom-manager.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, GtkWidget)
|
||||
|
||||
struct _SysprofDisplayClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GtkWidget *sysprof_display_new (void);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GtkWidget *sysprof_display_new_for_profiler (SysprofProfiler *profiler);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
char *sysprof_display_dup_title (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofProfiler *sysprof_display_get_profiler (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_add_group (SysprofDisplay *self,
|
||||
SysprofVisualizerGroup *group);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_add_page (SysprofDisplay *self,
|
||||
SysprofPage *page);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofPage *sysprof_display_get_visible_page (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_set_visible_page (SysprofDisplay *self,
|
||||
SysprofPage *page);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofZoomManager *sysprof_display_get_zoom_manager (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_load_async (SysprofDisplay *self,
|
||||
SysprofCaptureReader *reader,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_display_load_finish (SysprofDisplay *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_display_is_empty (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_open (SysprofDisplay *self,
|
||||
GFile *file);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_save (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_display_get_can_save (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_display_stop_recording (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
gboolean sysprof_display_get_can_replay (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofDisplay *sysprof_display_replay (SysprofDisplay *self);
|
||||
SYSPROF_AVAILABLE_IN_3_38
|
||||
void sysprof_display_add_to_selection (SysprofDisplay *self,
|
||||
gint64 begin_time,
|
||||
gint64 end_time);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="SysprofDisplay" parent="GtkWidget">
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="hhomogeneous">0</property>
|
||||
<property name="vhomogeneous">0</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">assistant</property>
|
||||
<property name="child">
|
||||
<object class="SysprofProfilerAssistant" id="assistant">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">view</property>
|
||||
<property name="child">
|
||||
<object class="EggPaned">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="SysprofVisualizersFrame" id="visualizers">
|
||||
<property name="vexpand">false</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="pages">
|
||||
<property name="hhomogeneous">0</property>
|
||||
<property name="vhomogeneous">0</property>
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="title" translatable="yes">Details</property>
|
||||
<property name="name">details</property>
|
||||
<property name="child">
|
||||
<object class="SysprofDetailsPage" id="details">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">record</property>
|
||||
<property name="child">
|
||||
<object class="SysprofRecordingStateView" id="recording_view">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">failed</property>
|
||||
<property name="child">
|
||||
<object class="SysprofFailedStateView" id="failed_view">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,633 +0,0 @@
|
||||
/* sysprof-duplex-visualizer.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-duplex-visualizer"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pointcache.h"
|
||||
#include "sysprof-duplex-visualizer.h"
|
||||
|
||||
#define LABEL_HEIGHT_PX 10
|
||||
|
||||
struct _SysprofDuplexVisualizer
|
||||
{
|
||||
SysprofVisualizer parent_instance;
|
||||
|
||||
gint64 begin_time;
|
||||
gint64 duration;
|
||||
|
||||
guint rx_counter;
|
||||
guint tx_counter;
|
||||
|
||||
GdkRGBA rx_rgba;
|
||||
GdkRGBA tx_rgba;
|
||||
|
||||
gchar *rx_label;
|
||||
gchar *tx_label;
|
||||
|
||||
PointCache *cache;
|
||||
|
||||
guint rx_rgba_set : 1;
|
||||
guint tx_rgba_set : 1;
|
||||
guint use_diff : 1;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PointCache *cache;
|
||||
|
||||
gint64 begin_time;
|
||||
gint64 duration;
|
||||
|
||||
gint64 max_change;
|
||||
|
||||
/* Last value to convert to rate of change */
|
||||
gint64 last_rx_val;
|
||||
gint64 last_tx_val;
|
||||
|
||||
/* Counter IDs */
|
||||
guint rx;
|
||||
guint tx;
|
||||
|
||||
/* Do we need to subtract previous value */
|
||||
guint use_diff : 1;
|
||||
} Collect;
|
||||
|
||||
G_DEFINE_TYPE (SysprofDuplexVisualizer, sysprof_duplex_visualizer, SYSPROF_TYPE_VISUALIZER)
|
||||
|
||||
static bool
|
||||
collect_ranges_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer data)
|
||||
{
|
||||
Collect *state = data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (state != NULL);
|
||||
g_assert (state->cache != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
|
||||
{
|
||||
const SysprofCaptureCounterSet *set = (gconstpointer)frame;
|
||||
|
||||
for (guint i = 0; i < set->n_values; i++)
|
||||
{
|
||||
const SysprofCaptureCounterValues *values = &set->values[i];
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (values->ids); j++)
|
||||
{
|
||||
gint64 v64 = values->values[j].v64;
|
||||
guint id = values->ids[j];
|
||||
gint64 max_change = 0;
|
||||
|
||||
if (id == 0)
|
||||
break;
|
||||
|
||||
if (id == state->rx)
|
||||
{
|
||||
if (state->last_rx_val != G_MININT64)
|
||||
max_change = v64 - state->last_rx_val;
|
||||
state->last_rx_val = v64;
|
||||
}
|
||||
else if (id == state->tx)
|
||||
{
|
||||
if (state->last_tx_val != G_MININT64)
|
||||
max_change = v64 - state->last_tx_val;
|
||||
state->last_tx_val = v64;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (max_change > state->max_change)
|
||||
state->max_change = max_change;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_values_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer data)
|
||||
{
|
||||
Collect *state = data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (state != NULL);
|
||||
g_assert (state->cache != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
|
||||
{
|
||||
const SysprofCaptureCounterSet *set = (gconstpointer)frame;
|
||||
gdouble x = (frame->time - state->begin_time) / (gdouble)state->duration;
|
||||
|
||||
for (guint i = 0; i < set->n_values; i++)
|
||||
{
|
||||
const SysprofCaptureCounterValues *values = &set->values[i];
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (values->ids); j++)
|
||||
{
|
||||
gint64 v64 = values->values[j].v64;
|
||||
guint id = values->ids[j];
|
||||
gint64 val = v64;
|
||||
gdouble y = 0.5;
|
||||
|
||||
if (id == 0)
|
||||
break;
|
||||
|
||||
if (id == state->rx)
|
||||
{
|
||||
if (state->use_diff)
|
||||
{
|
||||
if (state->last_rx_val == G_MININT64)
|
||||
val = 0;
|
||||
else
|
||||
val -= state->last_rx_val;
|
||||
}
|
||||
|
||||
/* RX goes upward from half point */
|
||||
if (state->max_change != 0)
|
||||
y += (gdouble)val / (gdouble)state->max_change / 2.0;
|
||||
|
||||
state->last_rx_val = v64;
|
||||
}
|
||||
else if (id == state->tx)
|
||||
{
|
||||
if (state->use_diff)
|
||||
{
|
||||
if (state->last_tx_val == G_MININT64)
|
||||
val = 0;
|
||||
else
|
||||
val -= state->last_tx_val;
|
||||
}
|
||||
|
||||
/* TX goes downward from half point */
|
||||
if (state->max_change != 0)
|
||||
y -= (gdouble)val / (gdouble)state->max_change / 2.0;
|
||||
|
||||
state->last_tx_val = v64;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
point_cache_add_point_to_set (state->cache, id, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
SysprofCaptureCursor *cursor = task_data;
|
||||
SysprofDuplexVisualizer *self = source_object;
|
||||
Collect state = {0};
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_assert (cursor != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
state.cache = point_cache_new ();
|
||||
state.begin_time = self->begin_time;
|
||||
state.duration = self->duration;
|
||||
state.rx = g_atomic_int_get (&self->rx_counter);
|
||||
state.tx = g_atomic_int_get (&self->tx_counter);
|
||||
state.last_rx_val = G_MININT64;
|
||||
state.last_tx_val = G_MININT64;
|
||||
state.max_change = 0;
|
||||
state.use_diff = self->use_diff;
|
||||
|
||||
point_cache_add_set (state.cache, state.rx);
|
||||
point_cache_add_set (state.cache, state.tx);
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, collect_ranges_cb, &state);
|
||||
sysprof_capture_cursor_reset (cursor);
|
||||
|
||||
/* Give just a bit of overhead */
|
||||
state.max_change *= 1.1;
|
||||
|
||||
/* Reset for calculations */
|
||||
state.last_rx_val = G_MININT64;
|
||||
state.last_tx_val = G_MININT64;
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, collect_values_cb, &state);
|
||||
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&state.cache),
|
||||
(GDestroyNotify) point_cache_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
load_data_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)object;
|
||||
g_autoptr(PointCache) pc = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
if ((pc = g_task_propagate_pointer (G_TASK (result), NULL)))
|
||||
{
|
||||
g_clear_pointer (&self->cache, point_cache_unref);
|
||||
self->cache = g_steal_pointer (&pc);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_set_reader (SysprofVisualizer *visualizer,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)visualizer;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
SysprofCaptureCondition *c;
|
||||
guint counters[2];
|
||||
|
||||
g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_assert (reader != NULL);
|
||||
|
||||
self->begin_time = sysprof_capture_reader_get_start_time (reader);
|
||||
self->duration = sysprof_capture_reader_get_end_time (reader)
|
||||
- sysprof_capture_reader_get_start_time (reader);
|
||||
|
||||
counters[0] = self->rx_counter;
|
||||
counters[1] = self->tx_counter;
|
||||
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
c = sysprof_capture_condition_new_where_counter_in (G_N_ELEMENTS (counters), counters);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&c));
|
||||
|
||||
task = g_task_new (self, NULL, load_data_cb, NULL);
|
||||
g_task_set_source_tag (task, sysprof_duplex_visualizer_set_reader);
|
||||
g_task_set_task_data (task,
|
||||
g_steal_pointer (&cursor),
|
||||
(GDestroyNotify)sysprof_capture_cursor_unref);
|
||||
g_task_run_in_thread (task, sysprof_duplex_visualizer_worker);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
static const gdouble dashes[] = { 1.0, 2.0 };
|
||||
SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)widget;
|
||||
PangoFontDescription *font_desc;
|
||||
GtkStyleContext *style_context;
|
||||
PangoLayout *layout;
|
||||
cairo_t *cr;
|
||||
GtkAllocation alloc;
|
||||
GdkRGBA fg;
|
||||
guint mid;
|
||||
|
||||
g_assert (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_assert (snapshot != NULL);
|
||||
|
||||
/* FIXME: This should all be drawn offscreen and then drawn to the snapshot
|
||||
* using GdkMemoryTexture so that we can avoid extra GPU uploads.
|
||||
*/
|
||||
|
||||
gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
mid = alloc.height / 2;
|
||||
|
||||
GTK_WIDGET_CLASS (sysprof_duplex_visualizer_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
|
||||
|
||||
style_context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_get_color (style_context, &fg);
|
||||
fg.alpha *= 0.4;
|
||||
|
||||
/* Draw our center line */
|
||||
cairo_save (cr);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
|
||||
cairo_move_to (cr, 0, mid);
|
||||
cairo_line_to (cr, alloc.width, mid);
|
||||
gdk_cairo_set_source_rgba (cr, &fg);
|
||||
cairo_stroke (cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
if (self->cache != NULL)
|
||||
{
|
||||
g_autofree SysprofVisualizerAbsolutePoint *points = NULL;
|
||||
const Point *fpoints;
|
||||
guint n_fpoints = 0;
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
if (self->rx_rgba_set)
|
||||
gdk_cairo_set_source_rgba (cr, &self->rx_rgba);
|
||||
|
||||
fpoints = point_cache_get_points (self->cache, self->rx_counter, &n_fpoints);
|
||||
|
||||
if (n_fpoints > 0)
|
||||
{
|
||||
GdkRGBA rgba = self->rx_rgba;
|
||||
gdouble last_x;
|
||||
gdouble last_y;
|
||||
guint p;
|
||||
|
||||
points = g_realloc_n (points, n_fpoints, sizeof *points);
|
||||
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
|
||||
(const SysprofVisualizerRelativePoint *)fpoints,
|
||||
n_fpoints,
|
||||
points,
|
||||
n_fpoints);
|
||||
|
||||
/* Skip past data that we won't see anyway */
|
||||
#if 0
|
||||
for (p = 0; p < n_fpoints; p++)
|
||||
{
|
||||
if (points[p].x >= clip.x)
|
||||
break;
|
||||
}
|
||||
|
||||
if (p >= n_fpoints)
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* But get at least one data point to anchor out of view */
|
||||
if (p > 0)
|
||||
p--;
|
||||
|
||||
last_x = points[p].x;
|
||||
last_y = points[p].y;
|
||||
|
||||
cairo_move_to (cr, last_x, mid);
|
||||
cairo_line_to (cr, last_x, last_y);
|
||||
|
||||
for (guint i = p + 1; i < n_fpoints; i++)
|
||||
{
|
||||
cairo_curve_to (cr,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
last_y,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
points[i].y,
|
||||
points[i].x,
|
||||
points[i].y);
|
||||
|
||||
last_x = points[i].x;
|
||||
last_y = points[i].y;
|
||||
|
||||
#if 0
|
||||
if (points[i].x > clip.x + clip.width)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
cairo_line_to (cr, last_x, mid);
|
||||
cairo_close_path (cr);
|
||||
cairo_stroke_preserve (cr);
|
||||
rgba.alpha *= 0.5;
|
||||
gdk_cairo_set_source_rgba (cr, &rgba);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
/* AND NOW Tx */
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
if (self->tx_rgba_set)
|
||||
gdk_cairo_set_source_rgba (cr, &self->tx_rgba);
|
||||
|
||||
fpoints = point_cache_get_points (self->cache, self->tx_counter, &n_fpoints);
|
||||
|
||||
if (n_fpoints > 0)
|
||||
{
|
||||
GdkRGBA rgba = self->tx_rgba;
|
||||
gdouble last_x;
|
||||
gdouble last_y;
|
||||
guint p;
|
||||
|
||||
points = g_realloc_n (points, n_fpoints, sizeof *points);
|
||||
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
|
||||
(const SysprofVisualizerRelativePoint *)fpoints,
|
||||
n_fpoints,
|
||||
points,
|
||||
n_fpoints);
|
||||
|
||||
#if 0
|
||||
/* Skip past data that we won't see anyway */
|
||||
for (p = 0; p < n_fpoints; p++)
|
||||
{
|
||||
if (points[p].x >= clip.x)
|
||||
break;
|
||||
}
|
||||
|
||||
if (p >= n_fpoints)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
/* But get at least one data point to anchor out of view */
|
||||
if (p > 0)
|
||||
p--;
|
||||
|
||||
last_x = points[p].x;
|
||||
last_y = points[p].y;
|
||||
|
||||
cairo_move_to (cr, last_x, mid);
|
||||
cairo_line_to (cr, last_x, last_y);
|
||||
|
||||
for (guint i = p + 1; i < n_fpoints; i++)
|
||||
{
|
||||
cairo_curve_to (cr,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
last_y,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
points[i].y,
|
||||
points[i].x,
|
||||
points[i].y);
|
||||
|
||||
last_x = points[i].x;
|
||||
last_y = points[i].y;
|
||||
|
||||
#if 0
|
||||
if (points[i].x > clip.x + clip.width)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
cairo_line_to (cr, last_x, mid);
|
||||
cairo_close_path (cr);
|
||||
cairo_stroke_preserve (cr);
|
||||
rgba.alpha *= 0.5;
|
||||
gdk_cairo_set_source_rgba (cr, &rgba);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, "");
|
||||
|
||||
font_desc = pango_font_description_new ();
|
||||
pango_font_description_set_family_static (font_desc, "Monospace");
|
||||
pango_font_description_set_absolute_size (font_desc, LABEL_HEIGHT_PX * PANGO_SCALE);
|
||||
pango_layout_set_font_description (layout, font_desc);
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &fg);
|
||||
|
||||
cairo_move_to (cr, 2, 2);
|
||||
if (self->rx_label != NULL)
|
||||
pango_layout_set_text (layout, self->rx_label, -1);
|
||||
else
|
||||
pango_layout_set_text (layout, "RX", 2);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
cairo_move_to (cr, 2, mid + 2);
|
||||
if (self->tx_label != NULL)
|
||||
pango_layout_set_text (layout, self->tx_label, -1);
|
||||
else
|
||||
pango_layout_set_text (layout, "TX", 2);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
pango_font_description_free (font_desc);
|
||||
g_object_unref (layout);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofDuplexVisualizer *self = (SysprofDuplexVisualizer *)object;
|
||||
|
||||
g_clear_pointer (&self->cache, point_cache_unref);
|
||||
g_clear_pointer (&self->rx_label, g_free);
|
||||
g_clear_pointer (&self->tx_label, g_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_duplex_visualizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_class_init (SysprofDuplexVisualizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_duplex_visualizer_finalize;
|
||||
|
||||
widget_class->snapshot = sysprof_duplex_visualizer_snapshot;
|
||||
|
||||
visualizer_class->set_reader = sysprof_duplex_visualizer_set_reader;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_duplex_visualizer_init (SysprofDuplexVisualizer *self)
|
||||
{
|
||||
self->use_diff = TRUE;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
sysprof_duplex_visualizer_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_DUPLEX_VISUALIZER, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_duplex_visualizer_set_counters (SysprofDuplexVisualizer *self,
|
||||
guint rx_counter,
|
||||
guint tx_counter)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
g_return_if_fail (rx_counter != 0);
|
||||
g_return_if_fail (tx_counter != 0);
|
||||
|
||||
self->rx_counter = rx_counter;
|
||||
self->tx_counter = tx_counter;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_duplex_visualizer_set_colors (SysprofDuplexVisualizer *self,
|
||||
const GdkRGBA *rx_rgba,
|
||||
const GdkRGBA *tx_rgba)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
|
||||
if (rx_rgba)
|
||||
self->rx_rgba = *rx_rgba;
|
||||
self->rx_rgba_set = !!rx_rgba;
|
||||
|
||||
if (tx_rgba)
|
||||
self->tx_rgba = *tx_rgba;
|
||||
self->tx_rgba_set = !!tx_rgba;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
gboolean
|
||||
sysprof_duplex_visualizer_get_use_diff (SysprofDuplexVisualizer *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self), FALSE);
|
||||
|
||||
return self->use_diff;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_duplex_visualizer_set_use_diff (SysprofDuplexVisualizer *self,
|
||||
gboolean use_diff)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
|
||||
self->use_diff = !!use_diff;
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_duplex_visualizer_set_labels (SysprofDuplexVisualizer *self,
|
||||
const gchar *rx_label,
|
||||
const gchar *tx_label)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_DUPLEX_VISUALIZER (self));
|
||||
|
||||
if (g_strcmp0 (rx_label, self->rx_label) != 0)
|
||||
{
|
||||
g_free (self->rx_label);
|
||||
self->rx_label = g_strdup (rx_label);
|
||||
}
|
||||
|
||||
if (g_strcmp0 (tx_label, self->tx_label) != 0)
|
||||
{
|
||||
g_free (self->tx_label);
|
||||
self->tx_label = g_strdup (tx_label);
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
/* sysprof-duplex-visualizer.h
|
||||
*
|
||||
* Copyright 2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-visualizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_DUPLEX_VISUALIZER (sysprof_duplex_visualizer_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofDuplexVisualizer, sysprof_duplex_visualizer, SYSPROF, DUPLEX_VISUALIZER, SysprofVisualizer)
|
||||
|
||||
GtkWidget *sysprof_duplex_visualizer_new (void);
|
||||
gboolean sysprof_duplex_visualizer_get_use_diff (SysprofDuplexVisualizer *self);
|
||||
void sysprof_duplex_visualizer_set_use_diff (SysprofDuplexVisualizer *self,
|
||||
gboolean use_diff);
|
||||
void sysprof_duplex_visualizer_set_labels (SysprofDuplexVisualizer *self,
|
||||
const gchar *rx_label,
|
||||
const gchar *tx_label);
|
||||
void sysprof_duplex_visualizer_set_counters (SysprofDuplexVisualizer *self,
|
||||
guint rx_counter,
|
||||
guint tx_counter);
|
||||
void sysprof_duplex_visualizer_set_colors (SysprofDuplexVisualizer *self,
|
||||
const GdkRGBA *rx_rgba,
|
||||
const GdkRGBA *tx_rgba);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,277 +0,0 @@
|
||||
/* sysprof-environ-editor-row.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-environ-editor-row"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-environ-editor-row.h"
|
||||
|
||||
struct _SysprofEnvironEditorRow
|
||||
{
|
||||
GtkListBoxRow parent_instance;
|
||||
|
||||
SysprofEnvironVariable *variable;
|
||||
|
||||
GtkEntry *key_entry;
|
||||
GtkEntry *value_entry;
|
||||
GtkButton *delete_button;
|
||||
|
||||
GBinding *key_binding;
|
||||
GBinding *value_binding;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_VARIABLE,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
enum {
|
||||
DELETE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofEnvironEditorRow, sysprof_environ_editor_row, GTK_TYPE_LIST_BOX_ROW)
|
||||
|
||||
static GParamSpec *properties [LAST_PROP];
|
||||
static guint signals [LAST_SIGNAL];
|
||||
|
||||
static gboolean
|
||||
null_safe_mapping (GBinding *binding,
|
||||
const GValue *from_value,
|
||||
GValue *to_value,
|
||||
gpointer user_data)
|
||||
{
|
||||
const gchar *str = g_value_get_string (from_value);
|
||||
g_value_set_string (to_value, str ?: "");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_connect (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_VARIABLE (self->variable));
|
||||
|
||||
self->key_binding =
|
||||
g_object_bind_property_full (self->variable, "key", self->key_entry, "text",
|
||||
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
|
||||
null_safe_mapping, NULL, NULL, NULL);
|
||||
|
||||
self->value_binding =
|
||||
g_object_bind_property_full (self->variable, "value", self->value_entry, "text",
|
||||
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
|
||||
null_safe_mapping, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_disconnect (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_VARIABLE (self->variable));
|
||||
|
||||
g_clear_pointer (&self->key_binding, g_binding_unbind);
|
||||
g_clear_pointer (&self->value_binding, g_binding_unbind);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_button_clicked (GtkButton *button,
|
||||
SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_assert (GTK_IS_BUTTON (button));
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
|
||||
g_signal_emit (self, signals [DELETE], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
key_entry_activate (GtkWidget *entry,
|
||||
SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_assert (GTK_IS_ENTRY (entry));
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (self->value_entry));
|
||||
}
|
||||
|
||||
static void
|
||||
value_entry_activate (GtkWidget *entry,
|
||||
SysprofEnvironEditorRow *self)
|
||||
{
|
||||
GtkWidget *parent;
|
||||
|
||||
g_assert (GTK_IS_ENTRY (entry));
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (self));
|
||||
parent = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_LIST_BOX);
|
||||
g_signal_emit_by_name (parent, "move-cursor", GTK_MOVEMENT_DISPLAY_LINES, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_dispose (GObject *object)
|
||||
{
|
||||
SysprofEnvironEditorRow *self = (SysprofEnvironEditorRow *)object;
|
||||
|
||||
if (self->variable != NULL)
|
||||
{
|
||||
sysprof_environ_editor_row_disconnect (self);
|
||||
g_clear_object (&self->variable);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (sysprof_environ_editor_row_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironEditorRow *self = SYSPROF_ENVIRON_EDITOR_ROW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_VARIABLE:
|
||||
g_value_set_object (value, sysprof_environ_editor_row_get_variable (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironEditorRow *self = SYSPROF_ENVIRON_EDITOR_ROW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_VARIABLE:
|
||||
sysprof_environ_editor_row_set_variable (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_class_init (SysprofEnvironEditorRowClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_environ_editor_row_dispose;
|
||||
object_class->get_property = sysprof_environ_editor_row_get_property;
|
||||
object_class->set_property = sysprof_environ_editor_row_set_property;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-environ-editor-row.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofEnvironEditorRow, delete_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofEnvironEditorRow, key_entry);
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofEnvironEditorRow, value_entry);
|
||||
|
||||
properties [PROP_VARIABLE] =
|
||||
g_param_spec_object ("variable",
|
||||
"Variable",
|
||||
"Variable",
|
||||
SYSPROF_TYPE_ENVIRON_VARIABLE,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, properties);
|
||||
|
||||
signals [DELETE] =
|
||||
g_signal_new ("delete",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_init (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
g_signal_connect (self->delete_button,
|
||||
"clicked",
|
||||
G_CALLBACK (delete_button_clicked),
|
||||
self);
|
||||
|
||||
g_signal_connect (self->key_entry,
|
||||
"activate",
|
||||
G_CALLBACK (key_entry_activate),
|
||||
self);
|
||||
|
||||
g_signal_connect (self->value_entry,
|
||||
"activate",
|
||||
G_CALLBACK (value_entry_activate),
|
||||
self);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_environ_editor_row_get_variable:
|
||||
*
|
||||
* Returns: (transfer none) (nullable): An #SysprofEnvironVariable.
|
||||
*/
|
||||
SysprofEnvironVariable *
|
||||
sysprof_environ_editor_row_get_variable (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON_EDITOR_ROW (self), NULL);
|
||||
|
||||
return self->variable;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_editor_row_set_variable (SysprofEnvironEditorRow *self,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
g_return_if_fail (!variable || SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
if (variable != self->variable)
|
||||
{
|
||||
if (self->variable != NULL)
|
||||
{
|
||||
sysprof_environ_editor_row_disconnect (self);
|
||||
g_clear_object (&self->variable);
|
||||
}
|
||||
|
||||
if (variable != NULL)
|
||||
{
|
||||
self->variable = g_object_ref (variable);
|
||||
sysprof_environ_editor_row_connect (self);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_VARIABLE]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_editor_row_start_editing (SysprofEnvironEditorRow *self)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_EDITOR_ROW (self));
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (self->key_entry));
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
/* ide-environ-editor-row.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "sysprof-environ-variable.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ENVIRON_EDITOR_ROW (sysprof_environ_editor_row_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofEnvironEditorRow, sysprof_environ_editor_row, SYSPROF, ENVIRON_EDITOR_ROW, GtkListBoxRow)
|
||||
|
||||
SysprofEnvironVariable *sysprof_environ_editor_row_get_variable (SysprofEnvironEditorRow *self);
|
||||
void sysprof_environ_editor_row_set_variable (SysprofEnvironEditorRow *self,
|
||||
SysprofEnvironVariable *variable);
|
||||
void sysprof_environ_editor_row_start_editing (SysprofEnvironEditorRow *self);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="SysprofEnvironEditorRow" parent="GtkListBoxRow">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="key_entry">
|
||||
<property name="margin-start">3</property>
|
||||
<property name="has-frame">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="eq_label">
|
||||
<property name="label">=</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="value_entry">
|
||||
<property name="hexpand">True</property>
|
||||
<property name="has-frame">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="delete_button">
|
||||
<property name="tooltip-text" translatable="yes">Remove environment variable</property>
|
||||
<property name="icon-name">list-remove-symbolic</property>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,343 +0,0 @@
|
||||
/* sysprof-environ-editor.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-environ-editor"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-environ-editor.h"
|
||||
#include "sysprof-environ-editor-row.h"
|
||||
#include "sysprof-theme-manager.h"
|
||||
|
||||
struct _SysprofEnvironEditor
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
GtkListBox *list_box;
|
||||
SysprofEnviron *environ;
|
||||
GtkWidget *dummy_row;
|
||||
SysprofEnvironVariable *dummy;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofEnvironEditor, sysprof_environ_editor, GTK_TYPE_WIDGET)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ENVIRON,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_delete_row (SysprofEnvironEditor *self,
|
||||
SysprofEnvironEditorRow *row)
|
||||
{
|
||||
SysprofEnvironVariable *variable;
|
||||
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR_ROW (row));
|
||||
|
||||
variable = sysprof_environ_editor_row_get_variable (row);
|
||||
sysprof_environ_remove (self->environ, variable);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
sysprof_environ_editor_create_dummy_row (SysprofEnvironEditor *self)
|
||||
{
|
||||
GtkWidget *row;
|
||||
GtkWidget *label;
|
||||
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
|
||||
label = g_object_new (GTK_TYPE_LABEL,
|
||||
"label", _("New environment variable…"),
|
||||
"margin-start", 6,
|
||||
"margin-end", 6,
|
||||
"margin-top", 6,
|
||||
"margin-bottom", 6,
|
||||
"visible", TRUE,
|
||||
"xalign", 0.0f,
|
||||
NULL);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
|
||||
|
||||
row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
|
||||
"child", label,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
sysprof_environ_editor_create_row (gpointer item,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofEnvironVariable *variable = item;
|
||||
SysprofEnvironEditor *self = user_data;
|
||||
SysprofEnvironEditorRow *row;
|
||||
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_ENVIRON_EDITOR_ROW,
|
||||
"variable", variable,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
g_signal_connect_object (row,
|
||||
"delete",
|
||||
G_CALLBACK (sysprof_environ_editor_delete_row),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
|
||||
return GTK_WIDGET (row);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_disconnect (SysprofEnvironEditor *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON (self->environ));
|
||||
|
||||
gtk_list_box_bind_model (self->list_box, NULL, NULL, NULL, NULL);
|
||||
g_clear_object (&self->dummy);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_connect (SysprofEnvironEditor *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON (self->environ));
|
||||
|
||||
gtk_list_box_bind_model (self->list_box,
|
||||
G_LIST_MODEL (self->environ),
|
||||
sysprof_environ_editor_create_row, self, NULL);
|
||||
|
||||
self->dummy_row = sysprof_environ_editor_create_dummy_row (self);
|
||||
gtk_list_box_append (self->list_box, self->dummy_row);
|
||||
}
|
||||
|
||||
static void
|
||||
find_row_cb (GtkWidget *widget,
|
||||
gpointer data)
|
||||
{
|
||||
struct {
|
||||
SysprofEnvironVariable *variable;
|
||||
SysprofEnvironEditorRow *row;
|
||||
} *lookup = data;
|
||||
|
||||
g_assert (lookup != NULL);
|
||||
g_assert (GTK_IS_LIST_BOX_ROW (widget));
|
||||
|
||||
if (SYSPROF_IS_ENVIRON_EDITOR_ROW (widget))
|
||||
{
|
||||
SysprofEnvironVariable *variable;
|
||||
|
||||
variable = sysprof_environ_editor_row_get_variable (SYSPROF_ENVIRON_EDITOR_ROW (widget));
|
||||
|
||||
if (variable == lookup->variable)
|
||||
lookup->row = SYSPROF_ENVIRON_EDITOR_ROW (widget);
|
||||
}
|
||||
}
|
||||
|
||||
static SysprofEnvironEditorRow *
|
||||
find_row (SysprofEnvironEditor *self,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
struct {
|
||||
SysprofEnvironVariable *variable;
|
||||
SysprofEnvironEditorRow *row;
|
||||
} lookup = { variable, NULL };
|
||||
|
||||
g_assert (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_assert (SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self->list_box));
|
||||
child;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
find_row_cb (child, &lookup);
|
||||
|
||||
return lookup.row;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_row_activated (SysprofEnvironEditor *self,
|
||||
GtkListBoxRow *row,
|
||||
GtkListBox *list_box)
|
||||
{
|
||||
g_assert (GTK_IS_LIST_BOX (list_box));
|
||||
g_assert (GTK_IS_LIST_BOX_ROW (row));
|
||||
|
||||
if (self->environ == NULL)
|
||||
return;
|
||||
|
||||
if (self->dummy_row == GTK_WIDGET (row))
|
||||
{
|
||||
g_autoptr(SysprofEnvironVariable) variable = NULL;
|
||||
|
||||
variable = sysprof_environ_variable_new (NULL, NULL);
|
||||
sysprof_environ_append (self->environ, variable);
|
||||
sysprof_environ_editor_row_start_editing (find_row (self, variable));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_dispose (GObject *object)
|
||||
{
|
||||
SysprofEnvironEditor *self = (SysprofEnvironEditor *)object;
|
||||
|
||||
if (self->list_box)
|
||||
{
|
||||
gtk_widget_unparent (GTK_WIDGET (self->list_box));
|
||||
self->list_box = NULL;
|
||||
}
|
||||
|
||||
g_clear_object (&self->environ);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_environ_editor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironEditor *self = SYSPROF_ENVIRON_EDITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ENVIRON:
|
||||
g_value_set_object (value, sysprof_environ_editor_get_environ (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironEditor *self = SYSPROF_ENVIRON_EDITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ENVIRON:
|
||||
sysprof_environ_editor_set_environ (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_class_init (SysprofEnvironEditorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofThemeManager *theme_manager = sysprof_theme_manager_get_default ();
|
||||
|
||||
object_class->dispose = sysprof_environ_editor_dispose;
|
||||
object_class->get_property = sysprof_environ_editor_get_property;
|
||||
object_class->set_property = sysprof_environ_editor_set_property;
|
||||
|
||||
properties [PROP_ENVIRON] =
|
||||
g_param_spec_object ("environ",
|
||||
"Environment",
|
||||
"Environment",
|
||||
SYSPROF_TYPE_ENVIRON,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
|
||||
sysprof_theme_manager_register_resource (theme_manager, NULL, NULL, "/org/gnome/sysprof/css/SysprofEnvironEditor-shared.css");
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_editor_init (SysprofEnvironEditor *self)
|
||||
{
|
||||
self->list_box = GTK_LIST_BOX (gtk_list_box_new ());
|
||||
gtk_widget_set_parent (GTK_WIDGET (self->list_box), GTK_WIDGET (self));
|
||||
|
||||
gtk_list_box_set_selection_mode (self->list_box, GTK_SELECTION_NONE);
|
||||
|
||||
gtk_widget_add_css_class (GTK_WIDGET (self), "environ-editor");
|
||||
|
||||
g_signal_connect_object (self->list_box,
|
||||
"row-activated",
|
||||
G_CALLBACK (sysprof_environ_editor_row_activated),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
sysprof_environ_editor_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ENVIRON_EDITOR, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_editor_set_environ (SysprofEnvironEditor *self,
|
||||
SysprofEnviron *environ_)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_EDITOR (self));
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (environ_));
|
||||
|
||||
if (self->environ != environ_)
|
||||
{
|
||||
if (self->environ != NULL)
|
||||
{
|
||||
sysprof_environ_editor_disconnect (self);
|
||||
g_clear_object (&self->environ);
|
||||
}
|
||||
|
||||
if (environ_ != NULL)
|
||||
{
|
||||
self->environ = g_object_ref (environ_);
|
||||
sysprof_environ_editor_connect (self);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ENVIRON]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_environ_editor_get_environ:
|
||||
*
|
||||
* Returns: (nullable) (transfer none): An #SysprofEnviron or %NULL.
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofEnviron *
|
||||
sysprof_environ_editor_get_environ (SysprofEnvironEditor *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON_EDITOR (self), NULL);
|
||||
|
||||
return self->environ;
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
/* sysprof-environ-editor.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "sysprof-environ.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ENVIRON_EDITOR (sysprof_environ_editor_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofEnvironEditor, sysprof_environ_editor, SYSPROF, ENVIRON_EDITOR, GtkWidget)
|
||||
|
||||
GtkWidget *sysprof_environ_editor_new (void);
|
||||
SysprofEnviron *sysprof_environ_editor_get_environ (SysprofEnvironEditor *self);
|
||||
void sysprof_environ_editor_set_environ (SysprofEnvironEditor *self,
|
||||
SysprofEnviron *environ);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,185 +0,0 @@
|
||||
/* sysprof-environ-variable.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-environ-variable"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-environ-variable.h"
|
||||
|
||||
struct _SysprofEnvironVariable
|
||||
{
|
||||
GObject parent_instance;
|
||||
gchar *key;
|
||||
gchar *value;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofEnvironVariable, sysprof_environ_variable, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_KEY,
|
||||
PROP_VALUE,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *properties [LAST_PROP];
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_finalize (GObject *object)
|
||||
{
|
||||
SysprofEnvironVariable *self = (SysprofEnvironVariable *)object;
|
||||
|
||||
g_clear_pointer (&self->key, g_free);
|
||||
g_clear_pointer (&self->value, g_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_environ_variable_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironVariable *self = SYSPROF_ENVIRON_VARIABLE(object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_KEY:
|
||||
g_value_set_string (value, self->key);
|
||||
break;
|
||||
|
||||
case PROP_VALUE:
|
||||
g_value_set_string (value, self->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofEnvironVariable *self = SYSPROF_ENVIRON_VARIABLE(object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_KEY:
|
||||
sysprof_environ_variable_set_key (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_VALUE:
|
||||
sysprof_environ_variable_set_value (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_class_init (SysprofEnvironVariableClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_environ_variable_finalize;
|
||||
object_class->get_property = sysprof_environ_variable_get_property;
|
||||
object_class->set_property = sysprof_environ_variable_set_property;
|
||||
|
||||
properties [PROP_KEY] =
|
||||
g_param_spec_string ("key",
|
||||
"Key",
|
||||
"The key for the environment variable",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_VALUE] =
|
||||
g_param_spec_string ("value",
|
||||
"Value",
|
||||
"The value for the environment variable",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_init (SysprofEnvironVariable *self)
|
||||
{
|
||||
}
|
||||
|
||||
const gchar *
|
||||
sysprof_environ_variable_get_key (SysprofEnvironVariable *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self), NULL);
|
||||
|
||||
return self->key;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_variable_set_key (SysprofEnvironVariable *self,
|
||||
const gchar *key)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self));
|
||||
|
||||
if (g_strcmp0 (key, self->key) != 0)
|
||||
{
|
||||
g_free (self->key);
|
||||
self->key = g_strdup (key);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_KEY]);
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
sysprof_environ_variable_get_value (SysprofEnvironVariable *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self), NULL);
|
||||
|
||||
return self->value;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_variable_set_value (SysprofEnvironVariable *self,
|
||||
const gchar *value)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (self));
|
||||
|
||||
if (g_strcmp0 (value, self->value) != 0)
|
||||
{
|
||||
g_free (self->value);
|
||||
self->value = g_strdup (value);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_VALUE]);
|
||||
}
|
||||
}
|
||||
|
||||
SysprofEnvironVariable *
|
||||
sysprof_environ_variable_new (const gchar *key,
|
||||
const gchar *value)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ENVIRON_VARIABLE,
|
||||
"key", key,
|
||||
"value", value,
|
||||
NULL);
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
/* sysprof-environ-variable.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ENVIRON_VARIABLE (sysprof_environ_variable_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofEnvironVariable, sysprof_environ_variable, SYSPROF, ENVIRON_VARIABLE, GObject)
|
||||
|
||||
SysprofEnvironVariable *sysprof_environ_variable_new (const gchar *key,
|
||||
const gchar *value);
|
||||
const gchar *sysprof_environ_variable_get_key (SysprofEnvironVariable *self);
|
||||
void sysprof_environ_variable_set_key (SysprofEnvironVariable *self,
|
||||
const gchar *key);
|
||||
const gchar *sysprof_environ_variable_get_value (SysprofEnvironVariable *self);
|
||||
void sysprof_environ_variable_set_value (SysprofEnvironVariable *self,
|
||||
const gchar *value);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,379 +0,0 @@
|
||||
/* sysprof-environ.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-environ"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sysprof-environ.h"
|
||||
#include "sysprof-environ-variable.h"
|
||||
|
||||
struct _SysprofEnviron
|
||||
{
|
||||
GObject parent_instance;
|
||||
GPtrArray *variables;
|
||||
};
|
||||
|
||||
static void list_model_iface_init (GListModelInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (SysprofEnviron, sysprof_environ, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals [LAST_SIGNAL];
|
||||
|
||||
static void
|
||||
sysprof_environ_finalize (GObject *object)
|
||||
{
|
||||
SysprofEnviron *self = (SysprofEnviron *)object;
|
||||
|
||||
g_clear_pointer (&self->variables, g_ptr_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_environ_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_class_init (SysprofEnvironClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_environ_finalize;
|
||||
|
||||
signals [CHANGED] =
|
||||
g_signal_new ("changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
g_signal_set_va_marshaller (signals [CHANGED],
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
g_cclosure_marshal_VOID__VOIDv);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_items_changed (SysprofEnviron *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON (self));
|
||||
|
||||
g_signal_emit (self, signals [CHANGED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_init (SysprofEnviron *self)
|
||||
{
|
||||
self->variables = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
g_signal_connect (self,
|
||||
"items-changed",
|
||||
G_CALLBACK (sysprof_environ_items_changed),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static GType
|
||||
sysprof_environ_get_item_type (GListModel *model)
|
||||
{
|
||||
return SYSPROF_TYPE_ENVIRON_VARIABLE;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_environ_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofEnviron *self = (SysprofEnviron *)model;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
|
||||
g_return_val_if_fail (position < self->variables->len, NULL);
|
||||
|
||||
return g_object_ref (g_ptr_array_index (self->variables, position));
|
||||
}
|
||||
|
||||
static guint
|
||||
sysprof_environ_get_n_items (GListModel *model)
|
||||
{
|
||||
SysprofEnviron *self = (SysprofEnviron *)model;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), 0);
|
||||
|
||||
return self->variables->len;
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_n_items = sysprof_environ_get_n_items;
|
||||
iface->get_item = sysprof_environ_get_item;
|
||||
iface->get_item_type = sysprof_environ_get_item_type;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_environ_variable_notify (SysprofEnviron *self,
|
||||
GParamSpec *pspec,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
g_assert (SYSPROF_IS_ENVIRON (self));
|
||||
|
||||
g_signal_emit (self, signals [CHANGED], 0);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_setenv (SysprofEnviron *self,
|
||||
const gchar *key,
|
||||
const gchar *value)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (self));
|
||||
g_return_if_fail (key != NULL);
|
||||
|
||||
for (i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
|
||||
const gchar *var_key = sysprof_environ_variable_get_key (var);
|
||||
|
||||
if (g_strcmp0 (key, var_key) == 0)
|
||||
{
|
||||
if (value == NULL)
|
||||
{
|
||||
g_ptr_array_remove_index (self->variables, i);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
sysprof_environ_variable_set_value (var, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (value != NULL)
|
||||
{
|
||||
SysprofEnvironVariable *var;
|
||||
guint position = self->variables->len;
|
||||
|
||||
var = g_object_new (SYSPROF_TYPE_ENVIRON_VARIABLE,
|
||||
"key", key,
|
||||
"value", value,
|
||||
NULL);
|
||||
g_signal_connect_object (var,
|
||||
"notify",
|
||||
G_CALLBACK (sysprof_environ_variable_notify),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_ptr_array_add (self->variables, var);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const gchar *
|
||||
sysprof_environ_getenv (SysprofEnviron *self,
|
||||
const gchar *key)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
|
||||
g_return_val_if_fail (key != NULL, NULL);
|
||||
|
||||
for (i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
|
||||
const gchar *var_key = sysprof_environ_variable_get_key (var);
|
||||
|
||||
if (g_strcmp0 (key, var_key) == 0)
|
||||
return sysprof_environ_variable_get_value (var);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_environ_get_environ:
|
||||
* @self: An #SysprofEnviron
|
||||
*
|
||||
* Gets the environment as a set of key=value pairs, suitable for use
|
||||
* in various GLib process functions.
|
||||
*
|
||||
* Returns: (transfer full): A newly allocated string array.
|
||||
*
|
||||
* Since: 3.32
|
||||
*/
|
||||
gchar **
|
||||
sysprof_environ_get_environ (SysprofEnviron *self)
|
||||
{
|
||||
GPtrArray *ar;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
|
||||
|
||||
ar = g_ptr_array_new ();
|
||||
|
||||
for (i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
|
||||
const gchar *key = sysprof_environ_variable_get_key (var);
|
||||
const gchar *value = sysprof_environ_variable_get_value (var);
|
||||
|
||||
if (value == NULL)
|
||||
value = "";
|
||||
|
||||
if (key != NULL)
|
||||
g_ptr_array_add (ar, g_strdup_printf ("%s=%s", key, value));
|
||||
}
|
||||
|
||||
g_ptr_array_add (ar, NULL);
|
||||
|
||||
return (gchar **)g_ptr_array_free (ar, FALSE);
|
||||
}
|
||||
|
||||
SysprofEnviron *
|
||||
sysprof_environ_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_ENVIRON, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_remove (SysprofEnviron *self,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (self));
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
for (i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *item = g_ptr_array_index (self->variables, i);
|
||||
|
||||
if (item == variable)
|
||||
{
|
||||
g_ptr_array_remove_index (self->variables, i);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_append (SysprofEnviron *self,
|
||||
SysprofEnvironVariable *variable)
|
||||
{
|
||||
guint position;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (self));
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON_VARIABLE (variable));
|
||||
|
||||
position = self->variables->len;
|
||||
|
||||
g_signal_connect_object (variable,
|
||||
"notify",
|
||||
G_CALLBACK (sysprof_environ_variable_notify),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_ptr_array_add (self->variables, g_object_ref (variable));
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_environ_copy:
|
||||
* @self: An #SysprofEnviron
|
||||
*
|
||||
* Copies the contents of #SysprofEnviron into a newly allocated #SysprofEnviron.
|
||||
*
|
||||
* Returns: (transfer full): An #SysprofEnviron.
|
||||
*
|
||||
* Since: 3.32
|
||||
*/
|
||||
SysprofEnviron *
|
||||
sysprof_environ_copy (SysprofEnviron *self)
|
||||
{
|
||||
g_autoptr(SysprofEnviron) copy = NULL;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ENVIRON (self), NULL);
|
||||
|
||||
copy = sysprof_environ_new ();
|
||||
sysprof_environ_copy_into (self, copy, TRUE);
|
||||
|
||||
return g_steal_pointer (©);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_environ_copy_into (SysprofEnviron *self,
|
||||
SysprofEnviron *dest,
|
||||
gboolean replace)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (self));
|
||||
g_return_if_fail (SYSPROF_IS_ENVIRON (dest));
|
||||
|
||||
for (guint i = 0; i < self->variables->len; i++)
|
||||
{
|
||||
SysprofEnvironVariable *var = g_ptr_array_index (self->variables, i);
|
||||
const gchar *key = sysprof_environ_variable_get_key (var);
|
||||
const gchar *value = sysprof_environ_variable_get_value (var);
|
||||
|
||||
if (replace || sysprof_environ_getenv (dest, key) == NULL)
|
||||
sysprof_environ_setenv (dest, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_environ_parse:
|
||||
* @pair: the KEY=VALUE pair
|
||||
* @key: (out) (optional): a location for a @key
|
||||
* @value: (out) (optional): a location for a @value
|
||||
*
|
||||
* Parses a KEY=VALUE style key-pair into @key and @value.
|
||||
*
|
||||
* Returns: %TRUE if @pair was successfully parsed
|
||||
*
|
||||
* Since: 3.32
|
||||
*/
|
||||
gboolean
|
||||
ide_environ_parse (const gchar *pair,
|
||||
gchar **key,
|
||||
gchar **value)
|
||||
{
|
||||
const gchar *eq;
|
||||
|
||||
g_return_val_if_fail (pair != NULL, FALSE);
|
||||
|
||||
if (key != NULL)
|
||||
*key = NULL;
|
||||
|
||||
if (value != NULL)
|
||||
*value = NULL;
|
||||
|
||||
if ((eq = strchr (pair, '=')))
|
||||
{
|
||||
if (key != NULL)
|
||||
*key = g_strndup (pair, eq - pair);
|
||||
|
||||
if (value != NULL)
|
||||
*value = g_strdup (eq + 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/* sysprof-environ.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-environ-variable.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_ENVIRON (sysprof_environ_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofEnviron, sysprof_environ, SYSPROF, ENVIRON, GObject)
|
||||
|
||||
gboolean ide_environ_parse (const gchar *pair,
|
||||
gchar **key,
|
||||
gchar **value);
|
||||
SysprofEnviron *sysprof_environ_new (void);
|
||||
void sysprof_environ_setenv (SysprofEnviron *self,
|
||||
const gchar *key,
|
||||
const gchar *value);
|
||||
const gchar *sysprof_environ_getenv (SysprofEnviron *self,
|
||||
const gchar *key);
|
||||
gchar **sysprof_environ_get_environ (SysprofEnviron *self);
|
||||
void sysprof_environ_append (SysprofEnviron *self,
|
||||
SysprofEnvironVariable *variable);
|
||||
void sysprof_environ_remove (SysprofEnviron *self,
|
||||
SysprofEnvironVariable *variable);
|
||||
SysprofEnviron *sysprof_environ_copy (SysprofEnviron *self);
|
||||
void sysprof_environ_copy_into (SysprofEnviron *self,
|
||||
SysprofEnviron *dest,
|
||||
gboolean replace);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,62 +0,0 @@
|
||||
/* sysprof-failed-state-view.c
|
||||
*
|
||||
* Copyright 2016-2019 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 "sysprof-failed-state-view.h"
|
||||
|
||||
G_DEFINE_TYPE (SysprofFailedStateView, sysprof_failed_state_view, GTK_TYPE_WIDGET)
|
||||
|
||||
GtkWidget *
|
||||
sysprof_failed_state_view_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_FAILED_STATE_VIEW, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_failed_state_view_dispose (GObject *object)
|
||||
{
|
||||
SysprofFailedStateView *self = (SysprofFailedStateView *)object;
|
||||
GtkWidget *child;
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self))))
|
||||
gtk_widget_unparent (child);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_failed_state_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_failed_state_view_class_init (SysprofFailedStateViewClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_failed_state_view_dispose;
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
gtk_widget_class_set_template_from_resource (widget_class,
|
||||
"/org/gnome/sysprof/ui/sysprof-failed-state-view.ui");
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_failed_state_view_init (SysprofFailedStateView *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
/* sysprof-failed-state-view.h
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_FAILED_STATE_VIEW (sysprof_failed_state_view_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofFailedStateView, sysprof_failed_state_view, SYSPROF, FAILED_STATE_VIEW, GtkWidget)
|
||||
|
||||
struct _SysprofFailedStateViewClass
|
||||
{
|
||||
GtkWidgetClass parent;
|
||||
};
|
||||
|
||||
GtkWidget *sysprof_failed_state_view_new (void);
|
||||
void sysprof_failed_state_view_set_profiler (SysprofFailedStateView *self,
|
||||
SysprofProfiler *profiler);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,47 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<interface>
|
||||
<template class="SysprofFailedStateView" parent="GtkWidget">
|
||||
<property name="vexpand">true</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-top">36</property>
|
||||
<property name="margin-bottom">36</property>
|
||||
<property name="margin-start">36</property>
|
||||
<property name="margin-end">36</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">12</property>
|
||||
<child type="center">
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">computer-fail-symbolic</property>
|
||||
<property name="pixel-size">256</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Ouch, that hurt!</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<attributes>
|
||||
<attribute name="scale" value="2"/>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Something unexpectedly went wrong while trying to profile your system.</property>
|
||||
<property name="use-markup">true</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,909 +0,0 @@
|
||||
/* sysprof-line-visualizer.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-line-visualizer"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "pointcache.h"
|
||||
#include "sysprof-line-visualizer.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/*
|
||||
* Our reader as assigned by the visualizer system.
|
||||
*/
|
||||
SysprofCaptureReader *reader;
|
||||
|
||||
/*
|
||||
* An array of LineInfo which contains information about the counters
|
||||
* we need to render.
|
||||
*/
|
||||
GArray *lines;
|
||||
|
||||
/*
|
||||
* This is our set of cached points to render. Once it is assigned here,
|
||||
* it is immutable (and therefore may be shared with worker processes
|
||||
* that are rendering the points).
|
||||
*/
|
||||
PointCache *cache;
|
||||
|
||||
/* The format for units (such as mHz, Watts, etc). */
|
||||
gchar *units;
|
||||
|
||||
/*
|
||||
* Range of the scale for lower and upper.
|
||||
*/
|
||||
gdouble y_lower;
|
||||
gdouble y_upper;
|
||||
|
||||
/*
|
||||
* If we have a new counter discovered or the reader is set, we might
|
||||
* want to delay loading until we return to the main loop. This can
|
||||
* help us avoid doing duplicate work.
|
||||
*/
|
||||
guint queued_load;
|
||||
|
||||
guint y_lower_set : 1;
|
||||
guint y_upper_set : 1;
|
||||
} SysprofLineVisualizerPrivate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint id;
|
||||
guint type;
|
||||
gdouble line_width;
|
||||
GdkRGBA foreground;
|
||||
GdkRGBA background;
|
||||
guint use_default_style : 1;
|
||||
guint fill : 1;
|
||||
guint use_dash : 1;
|
||||
} LineInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
GArray *lines;
|
||||
PointCache *cache;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
gdouble y_lower;
|
||||
gdouble y_upper;
|
||||
guint y_lower_set : 1;
|
||||
guint y_upper_set : 1;
|
||||
} LoadData;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (SysprofLineVisualizer, sysprof_line_visualizer, SYSPROF_TYPE_VISUALIZER)
|
||||
|
||||
static void sysprof_line_visualizer_load_data_async (SysprofLineVisualizer *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
static PointCache *sysprof_line_visualizer_load_data_finish (SysprofLineVisualizer *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_Y_LOWER,
|
||||
PROP_Y_UPPER,
|
||||
PROP_UNITS,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
static const gdouble dashes[] = { 1.0, 2.0 };
|
||||
|
||||
static void
|
||||
load_data_free (gpointer data)
|
||||
{
|
||||
LoadData *load = data;
|
||||
|
||||
if (load != NULL)
|
||||
{
|
||||
g_clear_pointer (&load->lines, g_array_unref);
|
||||
g_clear_pointer (&load->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_pointer (&load->cache, point_cache_unref);
|
||||
g_slice_free (LoadData, load);
|
||||
}
|
||||
}
|
||||
|
||||
static GArray *
|
||||
copy_array (GArray *ar)
|
||||
{
|
||||
GArray *ret;
|
||||
|
||||
ret = g_array_sized_new (FALSE, FALSE, g_array_get_element_size (ar), ar->len);
|
||||
g_array_set_size (ret, ar->len);
|
||||
memcpy (ret->data, ar->data, ar->len * g_array_get_element_size (ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
static PangoAttrList *attrs = NULL;
|
||||
SysprofLineVisualizer *self = (SysprofLineVisualizer *)widget;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
g_autofree gchar *upper = NULL;
|
||||
GtkStyleContext *style_context;
|
||||
PangoLayout *layout;
|
||||
cairo_t *cr;
|
||||
GtkAllocation alloc;
|
||||
GdkRectangle clip;
|
||||
GdkRGBA foreground;
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (widget));
|
||||
g_assert (snapshot != NULL);
|
||||
|
||||
gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
GTK_WIDGET_CLASS (sysprof_line_visualizer_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
if (priv->cache == NULL)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
if (!gdk_cairo_get_clip_rectangle (cr, &clip))
|
||||
return ret;
|
||||
#else
|
||||
clip.x = 0;
|
||||
clip.y = 0;
|
||||
clip.width = alloc.width;
|
||||
clip.height = alloc.height;
|
||||
#endif
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
|
||||
|
||||
style_context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_get_color (style_context, &foreground);
|
||||
|
||||
for (guint line = 0; line < priv->lines->len; line++)
|
||||
{
|
||||
g_autofree SysprofVisualizerAbsolutePoint *points = NULL;
|
||||
const LineInfo *line_info = &g_array_index (priv->lines, LineInfo, line);
|
||||
const Point *fpoints;
|
||||
guint n_fpoints = 0;
|
||||
GdkRGBA color;
|
||||
|
||||
fpoints = point_cache_get_points (priv->cache, line_info->id, &n_fpoints);
|
||||
|
||||
if (n_fpoints > 0)
|
||||
{
|
||||
gdouble last_x = 0;
|
||||
gdouble last_y = 0;
|
||||
guint p;
|
||||
|
||||
points = g_new0 (SysprofVisualizerAbsolutePoint, n_fpoints);
|
||||
|
||||
sysprof_visualizer_translate_points (SYSPROF_VISUALIZER (self),
|
||||
(const SysprofVisualizerRelativePoint *)fpoints,
|
||||
n_fpoints,
|
||||
points,
|
||||
n_fpoints);
|
||||
|
||||
for (p = 0; p < n_fpoints; p++)
|
||||
{
|
||||
if (points[p].x >= clip.x)
|
||||
break;
|
||||
}
|
||||
|
||||
if (p >= n_fpoints)
|
||||
goto cleanup;
|
||||
|
||||
if (p > 0)
|
||||
p--;
|
||||
|
||||
last_x = points[p].x;
|
||||
last_y = points[p].y;
|
||||
|
||||
if (line_info->fill)
|
||||
{
|
||||
cairo_move_to (cr, last_x, alloc.height);
|
||||
cairo_line_to (cr, last_x, last_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_move_to (cr, last_x, last_y);
|
||||
}
|
||||
|
||||
for (guint i = p + 1; i < n_fpoints; i++)
|
||||
{
|
||||
cairo_curve_to (cr,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
last_y,
|
||||
last_x + ((points[i].x - last_x) / 2),
|
||||
points[i].y,
|
||||
points[i].x,
|
||||
points[i].y);
|
||||
|
||||
last_x = points[i].x;
|
||||
last_y = points[i].y;
|
||||
|
||||
if (points[i].x > clip.x + clip.width)
|
||||
break;
|
||||
}
|
||||
|
||||
if (line_info->fill)
|
||||
{
|
||||
cairo_line_to (cr, last_x, alloc.height);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
|
||||
cairo_set_line_width (cr, line_info->line_width);
|
||||
|
||||
if (line_info->use_dash)
|
||||
cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
|
||||
|
||||
if (line_info->fill)
|
||||
{
|
||||
gdk_cairo_set_source_rgba (cr, &line_info->background);
|
||||
cairo_fill_preserve (cr);
|
||||
}
|
||||
|
||||
if (line_info->use_default_style)
|
||||
color = foreground;
|
||||
else
|
||||
color = line_info->foreground;
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &color);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!attrs)
|
||||
{
|
||||
attrs = pango_attr_list_new ();
|
||||
pango_attr_list_insert (attrs, pango_attr_scale_new (0.666));
|
||||
}
|
||||
|
||||
if (priv->y_upper != 100.0)
|
||||
{
|
||||
if (priv->units)
|
||||
upper = g_strdup_printf ("%lg %s", priv->y_upper, priv->units);
|
||||
else
|
||||
upper = g_strdup_printf ("%lg", priv->y_upper);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, upper);
|
||||
pango_layout_set_attributes (layout, attrs);
|
||||
cairo_move_to (cr, 2, 2);
|
||||
foreground.alpha *= 0.5;
|
||||
gdk_cairo_set_source_rgba (cr, &foreground);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
g_clear_object (&layout);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_load_data_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofLineVisualizer *self = (SysprofLineVisualizer *)object;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(PointCache) cache = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
cache = sysprof_line_visualizer_load_data_finish (self, result, &error);
|
||||
|
||||
if (cache == NULL)
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->cache, point_cache_unref);
|
||||
priv->cache = g_steal_pointer (&cache);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_line_visualizer_do_reload (gpointer data)
|
||||
{
|
||||
SysprofLineVisualizer *self = data;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
priv->queued_load = 0;
|
||||
|
||||
if (priv->reader != NULL)
|
||||
{
|
||||
sysprof_line_visualizer_load_data_async (self,
|
||||
NULL,
|
||||
sysprof_line_visualizer_load_data_cb,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_queue_reload (SysprofLineVisualizer *self)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
if (priv->queued_load == 0)
|
||||
priv->queued_load = g_idle_add_full (G_PRIORITY_LOW,
|
||||
sysprof_line_visualizer_do_reload,
|
||||
self,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_set_reader (SysprofVisualizer *row,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
SysprofLineVisualizer *self = (SysprofLineVisualizer *)row;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
if (priv->reader != reader)
|
||||
{
|
||||
if (priv->reader != NULL)
|
||||
{
|
||||
sysprof_capture_reader_unref (priv->reader);
|
||||
priv->reader = NULL;
|
||||
}
|
||||
|
||||
if (reader != NULL)
|
||||
priv->reader = sysprof_capture_reader_ref (reader);
|
||||
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofLineVisualizer *self = (SysprofLineVisualizer *)object;
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->units, g_free);
|
||||
g_clear_pointer (&priv->lines, g_array_unref);
|
||||
g_clear_pointer (&priv->cache, point_cache_unref);
|
||||
g_clear_pointer (&priv->reader, sysprof_capture_reader_unref);
|
||||
|
||||
g_clear_handle_id (&priv->queued_load, g_source_remove);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_line_visualizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofLineVisualizer *self = SYSPROF_LINE_VISUALIZER (object);
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_Y_LOWER:
|
||||
g_value_set_double (value, priv->y_lower);
|
||||
break;
|
||||
|
||||
case PROP_Y_UPPER:
|
||||
g_value_set_double (value, priv->y_upper);
|
||||
break;
|
||||
|
||||
case PROP_UNITS:
|
||||
g_value_set_string (value, priv->units);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofLineVisualizer *self = SYSPROF_LINE_VISUALIZER (object);
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_Y_LOWER:
|
||||
priv->y_lower = g_value_get_double (value);
|
||||
priv->y_lower_set = TRUE;
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
case PROP_Y_UPPER:
|
||||
priv->y_upper = g_value_get_double (value);
|
||||
priv->y_upper_set = TRUE;
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
case PROP_UNITS:
|
||||
g_free (priv->units);
|
||||
priv->units = g_value_dup_string (value);
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_class_init (SysprofLineVisualizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_line_visualizer_finalize;
|
||||
object_class->get_property = sysprof_line_visualizer_get_property;
|
||||
object_class->set_property = sysprof_line_visualizer_set_property;
|
||||
|
||||
widget_class->snapshot = sysprof_line_visualizer_snapshot;
|
||||
|
||||
visualizer_class->set_reader = sysprof_line_visualizer_set_reader;
|
||||
|
||||
properties [PROP_Y_LOWER] =
|
||||
g_param_spec_double ("y-lower",
|
||||
"Y Lower",
|
||||
"The lowest Y value for the visualizer",
|
||||
-G_MAXDOUBLE,
|
||||
G_MAXDOUBLE,
|
||||
0.0,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_Y_UPPER] =
|
||||
g_param_spec_double ("y-upper",
|
||||
"Y Upper",
|
||||
"The highest Y value for the visualizer",
|
||||
-G_MAXDOUBLE,
|
||||
G_MAXDOUBLE,
|
||||
100.0,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_UNITS] =
|
||||
g_param_spec_string ("units",
|
||||
"Units",
|
||||
"The format for units (mHz, Watts, etc)",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_init (SysprofLineVisualizer *self)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
priv->lines = g_array_new (FALSE, FALSE, sizeof (LineInfo));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_add_counter (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
LineInfo line_info = { 0 };
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
g_assert (priv->lines != NULL);
|
||||
|
||||
line_info.id = counter_id;
|
||||
line_info.line_width = 1.0;
|
||||
line_info.type = SYSPROF_CAPTURE_COUNTER_DOUBLE;
|
||||
|
||||
if (color != NULL)
|
||||
{
|
||||
line_info.foreground = *color;
|
||||
line_info.use_default_style = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gdk_rgba_parse (&line_info.foreground, "#000");
|
||||
line_info.use_default_style = TRUE;
|
||||
}
|
||||
|
||||
g_array_append_val (priv->lines, line_info);
|
||||
|
||||
if (SYSPROF_LINE_VISUALIZER_GET_CLASS (self)->counter_added)
|
||||
SYSPROF_LINE_VISUALIZER_GET_CLASS (self)->counter_added (self, counter_id);
|
||||
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_clear (SysprofLineVisualizer *self)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
if (priv->lines->len > 0)
|
||||
g_array_remove_range (priv->lines, 0, priv->lines->len);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
contains_id (GArray *ar,
|
||||
guint id)
|
||||
{
|
||||
for (guint i = 0; i < ar->len; i++)
|
||||
{
|
||||
const LineInfo *info = &g_array_index (ar, LineInfo, i);
|
||||
|
||||
if (info->id == id)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline guint8
|
||||
counter_type (LoadData *load,
|
||||
guint counter_id)
|
||||
{
|
||||
for (guint i = 0; i < load->lines->len; i++)
|
||||
{
|
||||
const LineInfo *info = &g_array_index (load->lines, LineInfo, i);
|
||||
|
||||
if (info->id == counter_id)
|
||||
return info->type;
|
||||
}
|
||||
|
||||
return SYSPROF_CAPTURE_COUNTER_DOUBLE;
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
calc_x (gint64 lower,
|
||||
gint64 upper,
|
||||
gint64 value)
|
||||
{
|
||||
return (gdouble)(value - lower) / (gdouble)(upper - lower);
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
calc_y_double (gdouble lower,
|
||||
gdouble upper,
|
||||
gdouble value)
|
||||
{
|
||||
return (value - lower) / (upper - lower);
|
||||
}
|
||||
|
||||
static inline gdouble
|
||||
calc_y_int64 (gint64 lower,
|
||||
gint64 upper,
|
||||
gint64 value)
|
||||
{
|
||||
return (gdouble)(value - lower) / (gdouble)(upper - lower);
|
||||
}
|
||||
|
||||
static bool
|
||||
sysprof_line_visualizer_load_data_frame_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
LoadData *load = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET ||
|
||||
frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (load != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
|
||||
{
|
||||
const SysprofCaptureCounterSet *set = (SysprofCaptureCounterSet *)frame;
|
||||
gdouble x = calc_x (load->begin_time, load->end_time, frame->time);
|
||||
|
||||
for (guint i = 0; i < set->n_values; i++)
|
||||
{
|
||||
const SysprofCaptureCounterValues *group = &set->values[i];
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (group->ids); j++)
|
||||
{
|
||||
guint counter_id = group->ids[j];
|
||||
|
||||
if (counter_id != 0 && contains_id (load->lines, counter_id))
|
||||
{
|
||||
gdouble y;
|
||||
|
||||
if (counter_type (load, counter_id) == SYSPROF_CAPTURE_COUNTER_DOUBLE)
|
||||
y = calc_y_double (load->y_lower, load->y_upper, group->values[j].vdbl);
|
||||
else
|
||||
y = calc_y_int64 (load->y_lower, load->y_upper, group->values[j].v64);
|
||||
|
||||
point_cache_add_point_to_set (load->cache, counter_id, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
sysprof_line_visualizer_load_data_range_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
LoadData *load = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET ||
|
||||
frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (load != NULL);
|
||||
g_assert (load->y_upper_set == FALSE ||
|
||||
load->y_lower_set == FALSE);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF)
|
||||
{
|
||||
const SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
|
||||
for (guint i = 0; i < def->n_counters; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &def->counters[i];
|
||||
|
||||
for (guint j = 0; j < load->lines->len; j++)
|
||||
{
|
||||
LineInfo *info = &g_array_index (load->lines, LineInfo, j);
|
||||
|
||||
if (info->id == ctr->id)
|
||||
{
|
||||
info->type = ctr->type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
|
||||
{
|
||||
const SysprofCaptureCounterSet *set = (SysprofCaptureCounterSet *)frame;
|
||||
|
||||
for (guint i = 0; i < set->n_values; i++)
|
||||
{
|
||||
const SysprofCaptureCounterValues *group = &set->values[i];
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (group->ids); j++)
|
||||
{
|
||||
guint counter_id = group->ids[j];
|
||||
|
||||
if (counter_id != 0 && contains_id (load->lines, counter_id))
|
||||
{
|
||||
gdouble y;
|
||||
|
||||
if (counter_type (load, counter_id) == SYSPROF_CAPTURE_COUNTER_DOUBLE)
|
||||
y = group->values[j].vdbl;
|
||||
else
|
||||
y = group->values[j].v64;
|
||||
|
||||
if (!load->y_upper_set)
|
||||
load->y_upper = MAX (load->y_upper, y);
|
||||
|
||||
if (!load->y_lower_set)
|
||||
load->y_lower = MIN (load->y_lower, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_load_data_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
LoadData *load = task_data;
|
||||
g_autoptr(GArray) counter_ids = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (source_object));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
counter_ids = g_array_new (FALSE, FALSE, sizeof (guint));
|
||||
|
||||
for (guint i = 0; i < load->lines->len; i++)
|
||||
{
|
||||
const LineInfo *line_info = &g_array_index (load->lines, LineInfo, i);
|
||||
g_array_append_val (counter_ids, line_info->id);
|
||||
}
|
||||
|
||||
sysprof_capture_cursor_add_condition (load->cursor,
|
||||
sysprof_capture_condition_new_where_counter_in (counter_ids->len,
|
||||
(guint *)(gpointer)counter_ids->data));
|
||||
|
||||
/* If y boundaries are not set, we need to discover them by scaning the data. */
|
||||
if (!load->y_lower_set || !load->y_upper_set)
|
||||
{
|
||||
sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_load_data_range_cb, load);
|
||||
sysprof_capture_cursor_reset (load->cursor);
|
||||
|
||||
/* Add extra boundary for some space above the graph line */
|
||||
if (G_MAXDOUBLE - load->y_upper > (load->y_upper * .25))
|
||||
load->y_upper = load->y_upper + ((load->y_upper - load->y_lower) * .25);
|
||||
}
|
||||
|
||||
sysprof_capture_cursor_foreach (load->cursor, sysprof_line_visualizer_load_data_frame_cb, load);
|
||||
g_task_return_pointer (task, g_steal_pointer (&load->cache), (GDestroyNotify)point_cache_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_line_visualizer_load_data_async (SysprofLineVisualizer *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
g_autoptr(GTask) task = NULL;
|
||||
LoadData *load;
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_priority (task, G_PRIORITY_LOW);
|
||||
g_task_set_source_tag (task, sysprof_line_visualizer_load_data_async);
|
||||
|
||||
if (priv->reader == NULL)
|
||||
{
|
||||
g_task_return_new_error (task,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"No data loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
load = g_slice_new0 (LoadData);
|
||||
load->cache = point_cache_new ();
|
||||
load->y_lower = priv->y_lower_set ? priv->y_lower : G_MAXDOUBLE;
|
||||
load->y_upper = priv->y_upper_set ? priv->y_upper : -G_MAXDOUBLE;
|
||||
load->y_lower_set = priv->y_lower_set;
|
||||
load->y_upper_set = priv->y_upper_set;
|
||||
load->begin_time = sysprof_capture_reader_get_start_time (priv->reader);
|
||||
load->end_time = sysprof_capture_reader_get_end_time (priv->reader);
|
||||
load->cursor = sysprof_capture_cursor_new (priv->reader);
|
||||
load->lines = copy_array (priv->lines);
|
||||
|
||||
for (guint i = 0; i < load->lines->len; i++)
|
||||
{
|
||||
const LineInfo *line_info = &g_array_index (load->lines, LineInfo, i);
|
||||
|
||||
point_cache_add_set (load->cache, line_info->id);
|
||||
}
|
||||
|
||||
g_task_set_task_data (task, load, load_data_free);
|
||||
g_task_run_in_thread (task, sysprof_line_visualizer_load_data_worker);
|
||||
}
|
||||
|
||||
static PointCache *
|
||||
sysprof_line_visualizer_load_data_finish (SysprofLineVisualizer *self,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
LoadData *state;
|
||||
|
||||
g_assert (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
state = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if (!priv->y_lower_set && priv->y_lower != state->y_lower)
|
||||
{
|
||||
priv->y_lower = state->y_lower;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_Y_LOWER]);
|
||||
}
|
||||
|
||||
if (!priv->y_upper_set && priv->y_upper != state->y_upper)
|
||||
{
|
||||
priv->y_upper = state->y_upper;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_Y_UPPER]);
|
||||
}
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (result), error);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_set_line_width (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
gdouble width)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
for (guint i = 0; i < priv->lines->len; i++)
|
||||
{
|
||||
LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
|
||||
|
||||
if (info->id == counter_id)
|
||||
{
|
||||
info->line_width = width;
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_set_fill (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
for (guint i = 0; i < priv->lines->len; i++)
|
||||
{
|
||||
LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
|
||||
|
||||
if (info->id == counter_id)
|
||||
{
|
||||
info->fill = !!color;
|
||||
if (color != NULL)
|
||||
info->background = *color;
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_line_visualizer_set_dash (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
gboolean use_dash)
|
||||
{
|
||||
SysprofLineVisualizerPrivate *priv = sysprof_line_visualizer_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_LINE_VISUALIZER (self));
|
||||
|
||||
for (guint i = 0; i < priv->lines->len; i++)
|
||||
{
|
||||
LineInfo *info = &g_array_index (priv->lines, LineInfo, i);
|
||||
|
||||
if (info->id == counter_id)
|
||||
{
|
||||
info->use_dash = !!use_dash;
|
||||
sysprof_line_visualizer_queue_reload (self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
/* sysprof-line-visualizer.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-visualizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_LINE_VISUALIZER (sysprof_line_visualizer_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofLineVisualizer, sysprof_line_visualizer, SYSPROF, LINE_VISUALIZER, SysprofVisualizer)
|
||||
|
||||
struct _SysprofLineVisualizerClass
|
||||
{
|
||||
SysprofVisualizerClass parent_class;
|
||||
|
||||
void (*counter_added) (SysprofLineVisualizer *self,
|
||||
guint counter_id);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
GtkWidget *sysprof_line_visualizer_new (void);
|
||||
void sysprof_line_visualizer_clear (SysprofLineVisualizer *self);
|
||||
void sysprof_line_visualizer_add_counter (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
const GdkRGBA *color);
|
||||
void sysprof_line_visualizer_set_line_width (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
gdouble width);
|
||||
void sysprof_line_visualizer_set_fill (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
const GdkRGBA *color);
|
||||
void sysprof_line_visualizer_set_dash (SysprofLineVisualizer *self,
|
||||
guint counter_id,
|
||||
gboolean use_dash);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,422 +0,0 @@
|
||||
/* sysprof-log-model.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-log-model"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sysprof-log-model.h"
|
||||
|
||||
struct _SysprofLogModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
GStringChunk *chunks;
|
||||
GArray *items;
|
||||
gint64 begin_time;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 time;
|
||||
const gchar *domain;
|
||||
const gchar *message;
|
||||
guint16 severity;
|
||||
} Item;
|
||||
|
||||
static gint
|
||||
sysprof_log_model_get_n_columns (GtkTreeModel *model)
|
||||
{
|
||||
return SYSPROF_LOG_MODEL_COLUMN_LAST;
|
||||
}
|
||||
|
||||
static GType
|
||||
sysprof_log_model_get_column_type (GtkTreeModel *model,
|
||||
gint column)
|
||||
{
|
||||
switch (column)
|
||||
{
|
||||
case SYSPROF_LOG_MODEL_COLUMN_TIME:
|
||||
return G_TYPE_INT64;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_SEVERITY:
|
||||
case SYSPROF_LOG_MODEL_COLUMN_DOMAIN:
|
||||
case SYSPROF_LOG_MODEL_COLUMN_MESSAGE:
|
||||
case SYSPROF_LOG_MODEL_COLUMN_TIME_STRING:
|
||||
return G_TYPE_STRING;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static GtkTreePath *
|
||||
sysprof_log_model_get_path (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
gint off;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (model));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
off = GPOINTER_TO_INT (iter->user_data);
|
||||
|
||||
return gtk_tree_path_new_from_indices (off, -1);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_log_model_get_iter (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreePath *path)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
gint off;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
g_assert (path != NULL);
|
||||
|
||||
memset (iter, 0, sizeof *iter);
|
||||
|
||||
if (gtk_tree_path_get_depth (path) != 1)
|
||||
return FALSE;
|
||||
|
||||
off = gtk_tree_path_get_indices (path)[0];
|
||||
iter->user_data = GINT_TO_POINTER (off);
|
||||
|
||||
return off >= 0 && off < self->items->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_log_model_iter_next (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
gint off;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
off = GPOINTER_TO_INT (iter->user_data);
|
||||
off++;
|
||||
iter->user_data = GINT_TO_POINTER (off);
|
||||
|
||||
return off < self->items->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_log_model_iter_nth_child (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreeIter *parent,
|
||||
gint n)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
if (parent != NULL)
|
||||
return FALSE;
|
||||
|
||||
iter->user_data = GINT_TO_POINTER (n);
|
||||
|
||||
return n < self->items->len;
|
||||
}
|
||||
|
||||
static gint
|
||||
sysprof_log_model_iter_n_children (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
|
||||
return iter ? 0 : self->items->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_log_model_iter_has_child (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GtkTreeModelFlags
|
||||
sysprof_log_model_get_flags (GtkTreeModel *model)
|
||||
{
|
||||
return GTK_TREE_MODEL_LIST_ONLY;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_get_value (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
gint column,
|
||||
GValue *value)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)model;
|
||||
const Item *item;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
g_assert (column < SYSPROF_LOG_MODEL_COLUMN_LAST);
|
||||
|
||||
item = &g_array_index (self->items, Item, GPOINTER_TO_INT (iter->user_data));
|
||||
|
||||
switch (column)
|
||||
{
|
||||
case SYSPROF_LOG_MODEL_COLUMN_TIME_STRING:
|
||||
{
|
||||
gint64 offset = item->time - self->begin_time;
|
||||
gint min = offset / SYSPROF_NSEC_PER_SEC / 60L;
|
||||
gint seconds = ((offset - (min * SYSPROF_NSEC_PER_SEC)) / SYSPROF_NSEC_PER_SEC) % 60;
|
||||
gint msec = (offset % SYSPROF_NSEC_PER_SEC) / (SYSPROF_NSEC_PER_SEC / 1000L);
|
||||
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
g_value_take_string (value,
|
||||
g_strdup_printf ("%02d:%02d.%03d", min, seconds, msec));
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_TIME:
|
||||
g_value_init (value, G_TYPE_INT64);
|
||||
g_value_set_int64 (value, item->time);
|
||||
break;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_SEVERITY:
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
switch (item->severity)
|
||||
{
|
||||
case G_LOG_LEVEL_MESSAGE:
|
||||
g_value_set_static_string (value, _("Message"));
|
||||
break;
|
||||
case G_LOG_LEVEL_INFO:
|
||||
g_value_set_static_string (value, _("Info"));
|
||||
break;
|
||||
case G_LOG_LEVEL_CRITICAL:
|
||||
g_value_set_static_string (value, _("Critical"));
|
||||
break;
|
||||
case G_LOG_LEVEL_ERROR:
|
||||
g_value_set_static_string (value, _("Error"));
|
||||
break;
|
||||
case G_LOG_LEVEL_DEBUG:
|
||||
g_value_set_static_string (value, _("Debug"));
|
||||
break;
|
||||
case G_LOG_LEVEL_WARNING:
|
||||
g_value_set_static_string (value, _("Warning"));
|
||||
break;
|
||||
default:
|
||||
g_value_set_static_string (value, "");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_DOMAIN:
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
g_value_set_string (value, item->domain);
|
||||
break;
|
||||
|
||||
case SYSPROF_LOG_MODEL_COLUMN_MESSAGE:
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
g_value_set_string (value, item->message);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tree_model_iface_init (GtkTreeModelIface *iface)
|
||||
{
|
||||
iface->get_n_columns = sysprof_log_model_get_n_columns;
|
||||
iface->get_column_type = sysprof_log_model_get_column_type;
|
||||
iface->get_iter = sysprof_log_model_get_iter;
|
||||
iface->get_path = sysprof_log_model_get_path;
|
||||
iface->iter_next = sysprof_log_model_iter_next;
|
||||
iface->iter_n_children = sysprof_log_model_iter_n_children;
|
||||
iface->iter_nth_child = sysprof_log_model_iter_nth_child;
|
||||
iface->iter_has_child = sysprof_log_model_iter_has_child;
|
||||
iface->get_flags = sysprof_log_model_get_flags;
|
||||
iface->get_value = sysprof_log_model_get_value;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (SysprofLogModel, sysprof_log_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, tree_model_iface_init))
|
||||
|
||||
static void
|
||||
sysprof_log_model_finalize (GObject *object)
|
||||
{
|
||||
SysprofLogModel *self = (SysprofLogModel *)object;
|
||||
|
||||
g_clear_pointer (&self->items, g_array_unref);
|
||||
g_clear_pointer (&self->chunks, g_string_chunk_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_log_model_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_class_init (SysprofLogModelClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_log_model_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_init (SysprofLogModel *self)
|
||||
{
|
||||
self->chunks = g_string_chunk_new (4096*16);
|
||||
self->items = g_array_new (FALSE, FALSE, sizeof (Item));
|
||||
}
|
||||
|
||||
static bool
|
||||
cursor_foreach_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofLogModel *self = user_data;
|
||||
SysprofCaptureLog *log = (SysprofCaptureLog *)frame;
|
||||
Item item;
|
||||
|
||||
g_assert (SYSPROF_IS_LOG_MODEL (self));
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_LOG);
|
||||
|
||||
item.time = frame->time;
|
||||
item.severity = log->severity;
|
||||
item.domain = g_string_chunk_insert_const (self->chunks, log->domain);
|
||||
item.message = g_string_chunk_insert_const (self->chunks, log->message);
|
||||
|
||||
g_array_append_val (self->items, item);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
item_compare (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const Item *ia = a;
|
||||
const Item *ib = b;
|
||||
|
||||
if (ia->time < ib->time)
|
||||
return -1;
|
||||
else if (ia->time > ib->time)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_new_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
g_autoptr(SysprofLogModel) self = NULL;
|
||||
SysprofCaptureCursor *cursor = task_data;
|
||||
SysprofCaptureReader *reader;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_LOG_MODEL, NULL);
|
||||
|
||||
reader = sysprof_capture_cursor_get_reader (cursor);
|
||||
self->begin_time = sysprof_capture_reader_get_start_time (reader);
|
||||
|
||||
sysprof_capture_cursor_foreach (cursor, cursor_foreach_cb, self);
|
||||
g_array_sort (self->items, item_compare);
|
||||
|
||||
g_task_return_pointer (task, g_steal_pointer (&self), g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_log_model_selection_foreach_cb (SysprofSelection *selection,
|
||||
gint64 begin,
|
||||
gint64 end,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCondition **condition = user_data;
|
||||
SysprofCaptureCondition *c;
|
||||
|
||||
g_assert (SYSPROF_IS_SELECTION (selection));
|
||||
g_assert (condition != NULL);
|
||||
|
||||
c = sysprof_capture_condition_new_where_time_between (begin, end);
|
||||
|
||||
if (*condition != NULL)
|
||||
*condition = sysprof_capture_condition_new_or (g_steal_pointer (&c),
|
||||
g_steal_pointer (condition));
|
||||
else
|
||||
*condition = g_steal_pointer (&c);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_log_model_new_async (SysprofCaptureReader *reader,
|
||||
SysprofSelection *selection,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = {
|
||||
SYSPROF_CAPTURE_FRAME_LOG,
|
||||
};
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
SysprofCaptureCondition *c;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_return_if_fail (reader != NULL);
|
||||
g_return_if_fail (!selection || SYSPROF_IS_SELECTION (selection));
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
c = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
|
||||
|
||||
if (selection)
|
||||
{
|
||||
SysprofCaptureCondition *condition = NULL;
|
||||
|
||||
sysprof_selection_foreach (selection,
|
||||
sysprof_log_model_selection_foreach_cb,
|
||||
&condition);
|
||||
if (condition)
|
||||
c = sysprof_capture_condition_new_and (c, g_steal_pointer (&condition));
|
||||
}
|
||||
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&c));
|
||||
|
||||
task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_log_model_new_async);
|
||||
g_task_set_task_data (task,
|
||||
g_steal_pointer (&cursor),
|
||||
(GDestroyNotify) sysprof_capture_cursor_unref);
|
||||
g_task_run_in_thread (task, sysprof_log_model_new_worker);
|
||||
}
|
||||
|
||||
SysprofLogModel *
|
||||
sysprof_log_model_new_finish (GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_TASK (result), NULL);
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (result), error);
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
/* sysprof-log-model.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sysprof.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SYSPROF_LOG_MODEL_COLUMN_TIME,
|
||||
SYSPROF_LOG_MODEL_COLUMN_SEVERITY,
|
||||
SYSPROF_LOG_MODEL_COLUMN_DOMAIN,
|
||||
SYSPROF_LOG_MODEL_COLUMN_MESSAGE,
|
||||
SYSPROF_LOG_MODEL_COLUMN_TIME_STRING,
|
||||
SYSPROF_LOG_MODEL_COLUMN_LAST
|
||||
} SysprofLogModelColumn;
|
||||
|
||||
#define SYSPROF_TYPE_LOG_MODEL (sysprof_log_model_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofLogModel, sysprof_log_model, SYSPROF, LOG_MODEL, GObject)
|
||||
|
||||
void sysprof_log_model_new_async (SysprofCaptureReader *reader,
|
||||
SysprofSelection *selection,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SysprofLogModel *sysprof_log_model_new_finish (GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,237 +0,0 @@
|
||||
/* sysprof-logs-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-logs-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-logs-aid.h"
|
||||
#include "sysprof-logs-page.h"
|
||||
#include "sysprof-mark-visualizer.h"
|
||||
|
||||
struct _SysprofLogsAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
SysprofCaptureCursor *cursor;
|
||||
GArray *log_marks;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofLogsAid, sysprof_logs_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->log_marks, g_array_unref);
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
static void
|
||||
on_group_activated_cb (SysprofVisualizerGroup *group,
|
||||
SysprofPage *page)
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
|
||||
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
|
||||
g_assert (SYSPROF_IS_PAGE (page));
|
||||
|
||||
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
|
||||
sysprof_display_set_visible_page (display, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_logs_aid_new:
|
||||
*
|
||||
* Create a new #SysprofLogsAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofLogsAid
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_logs_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_LOGS_AID, NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
find_marks_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
Present *p = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (p != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_LOG)
|
||||
{
|
||||
SysprofMarkTimeSpan span = { frame->time, frame->time };
|
||||
g_array_append_val (p->log_marks, span);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_span (const SysprofMarkTimeSpan *a,
|
||||
const SysprofMarkTimeSpan *b)
|
||||
{
|
||||
if (a->kind < b->kind)
|
||||
return -1;
|
||||
|
||||
if (b->kind < a->kind)
|
||||
return 1;
|
||||
|
||||
if (a->begin < b->begin)
|
||||
return -1;
|
||||
|
||||
if (b->begin < a->begin)
|
||||
return 1;
|
||||
|
||||
if (b->end > a->end)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_logs_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *p = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (p != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (p->display));
|
||||
g_assert (p->cursor != NULL);
|
||||
g_assert (SYSPROF_IS_LOGS_AID (source_object));
|
||||
|
||||
sysprof_capture_cursor_foreach (p->cursor, find_marks_cb, p);
|
||||
g_array_sort (p->log_marks, (GCompareFunc)compare_span);
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_logs_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType logs[] = {
|
||||
SYSPROF_CAPTURE_FRAME_LOG,
|
||||
};
|
||||
SysprofLogsAid *self = (SysprofLogsAid *)aid;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present p = {0};
|
||||
|
||||
g_assert (SYSPROF_IS_LOGS_AID (self));
|
||||
|
||||
p.display = g_object_ref (display);
|
||||
p.log_marks = g_array_new (FALSE, FALSE, sizeof (SysprofMarkTimeSpan));
|
||||
p.cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (p.cursor,
|
||||
sysprof_capture_condition_new_where_type_in (1, logs));
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_logs_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &p),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_logs_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_logs_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
Present *p;
|
||||
|
||||
g_assert (SYSPROF_IS_LOGS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
p = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if (p->log_marks->len > 0)
|
||||
{
|
||||
g_autoptr(GHashTable) items = NULL;
|
||||
SysprofVisualizerGroup *group;
|
||||
SysprofVisualizer *marks;
|
||||
SysprofPage *page;
|
||||
|
||||
items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
|
||||
(GDestroyNotify) g_array_unref);
|
||||
g_hash_table_insert (items, g_strdup (_("Logs")), g_array_ref (p->log_marks));
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"title", _("Logs"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
marks = sysprof_mark_visualizer_new (items);
|
||||
sysprof_visualizer_set_title (marks, _("Logs"));
|
||||
gtk_widget_show (GTK_WIDGET (marks));
|
||||
sysprof_visualizer_group_insert (group, marks, 0, FALSE);
|
||||
sysprof_display_add_group (p->display, group);
|
||||
|
||||
page = g_object_new (SYSPROF_TYPE_LOGS_PAGE,
|
||||
"title", _("Logs"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
sysprof_display_add_page (p->display, page);
|
||||
|
||||
g_signal_connect_object (group,
|
||||
"group-activated",
|
||||
G_CALLBACK (on_group_activated_cb),
|
||||
page,
|
||||
0);
|
||||
}
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_logs_aid_class_init (SysprofLogsAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->present_async = sysprof_logs_aid_present_async;
|
||||
aid_class->present_finish = sysprof_logs_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_logs_aid_init (SysprofLogsAid *self)
|
||||
{
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-logs-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_LOGS_AID (sysprof_logs_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofLogsAid, sysprof_logs_aid, SYSPROF, LOGS_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_logs_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,116 +0,0 @@
|
||||
/* sysprof-logs-page.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-logs-page"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-log-model.h"
|
||||
#include "sysprof-logs-page.h"
|
||||
|
||||
struct _SysprofLogsPage
|
||||
{
|
||||
SysprofPage parent_instance;
|
||||
|
||||
/* Template Widgets */
|
||||
GtkTreeView *tree_view;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofLogsPage, sysprof_logs_page, SYSPROF_TYPE_PAGE)
|
||||
|
||||
static void
|
||||
sysprof_logs_page_load_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofLogsPage *self;
|
||||
g_autoptr(SysprofLogModel) model = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GTask) task = user_data;
|
||||
|
||||
g_assert (G_IS_ASYNC_RESULT (result));
|
||||
g_assert (G_IS_TASK (task));
|
||||
|
||||
if (!(model = sysprof_log_model_new_finish (result, &error)))
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
gtk_tree_view_set_model (self->tree_view, GTK_TREE_MODEL (model));
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_logs_page_load_async (SysprofPage *page,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofSelection *selection,
|
||||
SysprofCaptureCondition *filter,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofLogsPage *self = (SysprofLogsPage *)page;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_LOGS_PAGE (self));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (!selection || SYSPROF_IS_SELECTION (selection));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_logs_page_load_async);
|
||||
|
||||
sysprof_log_model_new_async (reader,
|
||||
selection,
|
||||
cancellable,
|
||||
sysprof_logs_page_load_cb,
|
||||
g_steal_pointer (&task));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_logs_page_load_finish (SysprofPage *page,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_assert (SYSPROF_IS_LOGS_PAGE (page));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_logs_page_class_init (SysprofLogsPageClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofPageClass *page_class = SYSPROF_PAGE_CLASS (klass);
|
||||
|
||||
page_class->load_async = sysprof_logs_page_load_async;
|
||||
page_class->load_finish = sysprof_logs_page_load_finish;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-logs-page.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, SysprofLogsPage, tree_view);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_logs_page_init (SysprofLogsPage *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
/* sysprof-logs-page.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-page.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_LOGS_PAGE (sysprof_logs_page_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofLogsPage, sysprof_logs_page, SYSPROF, LOGS_PAGE, SysprofPage)
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,73 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="SysprofLogsPage" parent="SysprofPage">
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<child>
|
||||
<object class="GtkTreeView" id="tree_view">
|
||||
<property name="tooltip-column">3</property>
|
||||
<property name="headers-visible">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="expand">false</property>
|
||||
<property name="title" translatable="yes">Time</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="xalign">0.0</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">4</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="expand">false</property>
|
||||
<property name="title" translatable="yes">Severity</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="xalign">0.0</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="expand">false</property>
|
||||
<property name="resizable">true</property>
|
||||
<property name="title" translatable="yes">Domain</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="xalign">0.0</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn">
|
||||
<property name="expand">true</property>
|
||||
<property name="title" translatable="yes">Message</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="ellipsize">end</property>
|
||||
<property name="xalign">0.0</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">3</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,208 +0,0 @@
|
||||
/* sysprof-mark-detail.c
|
||||
*
|
||||
* Copyright 2022 Corentin Noël <corentin.noel@collabora.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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-mark-detail"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-mark-detail.h"
|
||||
|
||||
struct _SysprofMarkDetail
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
gchar *label;
|
||||
gint64 min;
|
||||
gint64 max;
|
||||
gint64 average;
|
||||
gint64 hits;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofMarkDetail, sysprof_mark_detail, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_LABEL,
|
||||
PROP_MIN,
|
||||
PROP_MAX,
|
||||
PROP_AVERAGE,
|
||||
PROP_HITS,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
/**
|
||||
* sysprof_mark_detail_new:
|
||||
*
|
||||
* Create a new #SysprofMarkDetail.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofMarkDetail
|
||||
*/
|
||||
SysprofMarkDetail *
|
||||
sysprof_mark_detail_new (const gchar *mark,
|
||||
gint64 min,
|
||||
gint64 max,
|
||||
gint64 avg,
|
||||
gint64 hits)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_MARK_DETAIL,
|
||||
"label", mark,
|
||||
"min", min,
|
||||
"max", max,
|
||||
"average", avg,
|
||||
"hits", hits,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_detail_finalize (GObject *object)
|
||||
{
|
||||
SysprofMarkDetail *self = (SysprofMarkDetail *)object;
|
||||
|
||||
g_clear_pointer (&self->label, g_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_mark_detail_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_detail_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofMarkDetail *self = SYSPROF_MARK_DETAIL(object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_LABEL:
|
||||
g_value_set_string (value, self->label);
|
||||
break;
|
||||
|
||||
case PROP_MIN:
|
||||
g_value_set_int64 (value, self->min);
|
||||
break;
|
||||
|
||||
case PROP_MAX:
|
||||
g_value_set_int64 (value, self->max);
|
||||
break;
|
||||
|
||||
case PROP_AVERAGE:
|
||||
g_value_set_int64 (value, self->average);
|
||||
break;
|
||||
|
||||
case PROP_HITS:
|
||||
g_value_set_int64 (value, self->hits);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_detail_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofMarkDetail *self = SYSPROF_MARK_DETAIL(object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_LABEL:
|
||||
g_assert(self->label == NULL);
|
||||
self->label = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_MIN:
|
||||
self->min = g_value_get_int64 (value);
|
||||
break;
|
||||
|
||||
case PROP_MAX:
|
||||
self->max = g_value_get_int64 (value);
|
||||
break;
|
||||
|
||||
case PROP_AVERAGE:
|
||||
self->average = g_value_get_int64 (value);
|
||||
break;
|
||||
|
||||
case PROP_HITS:
|
||||
self->hits = g_value_get_int64 (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_detail_class_init (SysprofMarkDetailClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_mark_detail_finalize;
|
||||
object_class->get_property = sysprof_mark_detail_get_property;
|
||||
object_class->set_property = sysprof_mark_detail_set_property;
|
||||
|
||||
properties [PROP_LABEL] =
|
||||
g_param_spec_string ("label",
|
||||
"Label",
|
||||
"The label of the mark",
|
||||
NULL,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_MIN] =
|
||||
g_param_spec_int64 ("min",
|
||||
"Min",
|
||||
"The minimal timespan",
|
||||
0, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_MAX] =
|
||||
g_param_spec_int64 ("max",
|
||||
"max",
|
||||
"The maximal timespan",
|
||||
0, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_AVERAGE] =
|
||||
g_param_spec_int64 ("average",
|
||||
"Average",
|
||||
"The average timespan",
|
||||
0, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_HITS] =
|
||||
g_param_spec_int64 ("hits",
|
||||
"Hits",
|
||||
"The number of hits",
|
||||
0, G_MAXINT64, 0,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_detail_init (SysprofMarkDetail *self)
|
||||
{
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
/* sysprof-mark-detail.h
|
||||
*
|
||||
* Copyright 2022 Corentin Noël <corentin.noel@collabora.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_MARK_DETAIL (sysprof_mark_detail_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofMarkDetail, sysprof_mark_detail, SYSPROF, MARK_DETAIL, GObject)
|
||||
|
||||
SysprofMarkDetail *sysprof_mark_detail_new (const gchar *mark,
|
||||
gint64 min,
|
||||
gint64 max,
|
||||
gint64 avg,
|
||||
gint64 hits);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,276 +0,0 @@
|
||||
/* sysprof-mark-visualizer.c
|
||||
*
|
||||
* Copyright 2018-2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-mark-visualizer"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-mark-visualizer.h"
|
||||
|
||||
#define RECT_HEIGHT (4)
|
||||
#define RECT_MIN_WIDTH (3)
|
||||
#define RECT_OVERLAP (-1)
|
||||
|
||||
struct _SysprofMarkVisualizer
|
||||
{
|
||||
SysprofVisualizer parent_instance;
|
||||
GHashTable *spans_by_group;
|
||||
GHashTable *rgba_by_group;
|
||||
GHashTable *rgba_by_kind;
|
||||
GHashTable *row_by_kind;
|
||||
guint x_is_dirty : 1;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofMarkVisualizer, sysprof_mark_visualizer, SYSPROF_TYPE_VISUALIZER)
|
||||
|
||||
static void
|
||||
reset_positions (SysprofMarkVisualizer *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
|
||||
|
||||
self->x_is_dirty = TRUE;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
SysprofVisualizer *
|
||||
sysprof_mark_visualizer_new (GHashTable *groups)
|
||||
{
|
||||
SysprofMarkVisualizer *self;
|
||||
guint n_items;
|
||||
gint height;
|
||||
|
||||
g_return_val_if_fail (groups != NULL, NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_MARK_VISUALIZER, NULL);
|
||||
self->spans_by_group = g_hash_table_ref (groups);
|
||||
|
||||
reset_positions (self);
|
||||
|
||||
n_items = g_hash_table_size (groups);
|
||||
height = MAX (35, n_items * (RECT_HEIGHT - RECT_OVERLAP));
|
||||
gtk_widget_set_size_request (GTK_WIDGET (self), -1, height);
|
||||
|
||||
return SYSPROF_VISUALIZER (g_steal_pointer (&self));
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_visualizer_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)widget;
|
||||
SysprofVisualizer *vis = (SysprofVisualizer *)widget;
|
||||
static const GdkRGBA black = {0,0,0,1};
|
||||
const GdkRGBA *rgba = &black;
|
||||
GHashTableIter iter;
|
||||
GtkAllocation alloc;
|
||||
gpointer k, v;
|
||||
int n_groups = 0;
|
||||
int y = 0;
|
||||
|
||||
g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
|
||||
g_assert (snapshot != NULL);
|
||||
|
||||
GTK_WIDGET_CLASS (sysprof_mark_visualizer_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
if (self->spans_by_group == NULL)
|
||||
return;
|
||||
|
||||
gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
/* Pre-calculate all time slots so we can join later */
|
||||
if (self->x_is_dirty)
|
||||
{
|
||||
g_hash_table_iter_init (&iter, self->spans_by_group);
|
||||
while (g_hash_table_iter_next (&iter, &k, &v))
|
||||
{
|
||||
const GArray *spans = v;
|
||||
|
||||
for (guint i = 0; i < spans->len; i++)
|
||||
{
|
||||
SysprofMarkTimeSpan *span = &g_array_index (spans, SysprofMarkTimeSpan, i);
|
||||
|
||||
span->x = sysprof_visualizer_get_x_for_time (vis, span->begin);
|
||||
span->x2 = sysprof_visualizer_get_x_for_time (vis, span->end);
|
||||
}
|
||||
}
|
||||
|
||||
self->x_is_dirty = FALSE;
|
||||
}
|
||||
|
||||
n_groups = g_hash_table_size (self->spans_by_group);
|
||||
|
||||
g_hash_table_iter_init (&iter, self->spans_by_group);
|
||||
while (g_hash_table_iter_next (&iter, &k, &v))
|
||||
{
|
||||
SysprofMarkTimeSpan *span;
|
||||
const gchar *group = k;
|
||||
const GArray *spans = v;
|
||||
const GdkRGBA *kindrgba;
|
||||
const GdkRGBA *grouprgba;
|
||||
|
||||
if ((grouprgba = g_hash_table_lookup (self->rgba_by_group, group)))
|
||||
rgba = grouprgba;
|
||||
|
||||
for (guint i = 0; i < spans->len; i++)
|
||||
{
|
||||
gint x1, x2;
|
||||
|
||||
span = &g_array_index (spans, SysprofMarkTimeSpan, i);
|
||||
|
||||
if (n_groups == 1)
|
||||
{
|
||||
rgba = &black;
|
||||
if ((kindrgba = g_hash_table_lookup (self->rgba_by_kind, GUINT_TO_POINTER (span->kind))))
|
||||
rgba = kindrgba;
|
||||
else if ((grouprgba = g_hash_table_lookup (self->rgba_by_group, group)))
|
||||
rgba = grouprgba;
|
||||
}
|
||||
|
||||
x1 = span->x;
|
||||
x2 = x1 + RECT_MIN_WIDTH;
|
||||
|
||||
if (span->x2 > x2)
|
||||
x2 = span->x2;
|
||||
|
||||
/* If we are limited to one group, we might need to get the row
|
||||
* height for the kind of span this is.
|
||||
*/
|
||||
if (n_groups == 1)
|
||||
{
|
||||
gint row = GPOINTER_TO_INT (g_hash_table_lookup (self->row_by_kind, GUINT_TO_POINTER (span->kind)));
|
||||
y = row * (RECT_HEIGHT - RECT_OVERLAP);
|
||||
}
|
||||
|
||||
for (guint j = i + 1; j < spans->len; j++)
|
||||
{
|
||||
const SysprofMarkTimeSpan *next = &g_array_index (spans, SysprofMarkTimeSpan, j);
|
||||
|
||||
/* Don't join this if we are about to draw a different kind */
|
||||
if (n_groups == 1 && next->kind != span->kind)
|
||||
break;
|
||||
|
||||
if (next->x <= x2)
|
||||
{
|
||||
x2 = MAX (x2, next->x2);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_snapshot_append_color (snapshot, rgba, &GRAPHENE_RECT_INIT (x1, y, x2 - x1, RECT_HEIGHT));
|
||||
}
|
||||
|
||||
y += RECT_HEIGHT + RECT_OVERLAP;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_visualizer_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)widget;
|
||||
|
||||
g_assert (SYSPROF_IS_MARK_VISUALIZER (self));
|
||||
|
||||
GTK_WIDGET_CLASS (sysprof_mark_visualizer_parent_class)->size_allocate (widget, width, height, baseline);
|
||||
|
||||
reset_positions (self);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_visualizer_finalize (GObject *object)
|
||||
{
|
||||
SysprofMarkVisualizer *self = (SysprofMarkVisualizer *)object;
|
||||
|
||||
g_clear_pointer (&self->spans_by_group, g_hash_table_unref);
|
||||
g_clear_pointer (&self->rgba_by_group, g_hash_table_unref);
|
||||
g_clear_pointer (&self->rgba_by_kind, g_hash_table_unref);
|
||||
g_clear_pointer (&self->row_by_kind, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_mark_visualizer_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_visualizer_class_init (SysprofMarkVisualizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_mark_visualizer_finalize;
|
||||
|
||||
widget_class->snapshot = sysprof_mark_visualizer_snapshot;
|
||||
widget_class->size_allocate = sysprof_mark_visualizer_size_allocate;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_mark_visualizer_init (SysprofMarkVisualizer *self)
|
||||
{
|
||||
self->rgba_by_kind = g_hash_table_new_full (NULL, NULL, NULL, g_free);
|
||||
self->row_by_kind = g_hash_table_new (NULL, NULL);
|
||||
self->rgba_by_group = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_mark_visualizer_set_group_rgba (SysprofMarkVisualizer *self,
|
||||
const gchar *group,
|
||||
const GdkRGBA *rgba)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_MARK_VISUALIZER (self));
|
||||
g_return_if_fail (group != NULL);
|
||||
|
||||
g_hash_table_insert (self->rgba_by_group,
|
||||
g_strdup (group),
|
||||
g_memdup2 (rgba, sizeof *rgba));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_mark_visualizer_set_kind_rgba (SysprofMarkVisualizer *self,
|
||||
GHashTable *rgba_by_kind)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_MARK_VISUALIZER (self));
|
||||
|
||||
if (rgba_by_kind != self->rgba_by_kind)
|
||||
{
|
||||
g_hash_table_remove_all (self->row_by_kind);
|
||||
|
||||
g_clear_pointer (&self->rgba_by_kind, g_hash_table_unref);
|
||||
|
||||
if (rgba_by_kind)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
guint row = 0;
|
||||
gpointer k;
|
||||
|
||||
self->rgba_by_kind = g_hash_table_ref (rgba_by_kind);
|
||||
|
||||
g_hash_table_iter_init (&iter, rgba_by_kind);
|
||||
while (g_hash_table_iter_next (&iter, &k, NULL))
|
||||
g_hash_table_insert (self->row_by_kind, k, GUINT_TO_POINTER (row++));
|
||||
|
||||
gtk_widget_set_size_request (GTK_WIDGET (self),
|
||||
-1,
|
||||
MAX (35, row * (RECT_HEIGHT - RECT_OVERLAP)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
/* sysprof-mark-visualizer.h
|
||||
*
|
||||
* Copyright 2018-2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-visualizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 begin;
|
||||
gint64 end;
|
||||
guint kind;
|
||||
gint x;
|
||||
gint x2;
|
||||
} SysprofMarkTimeSpan;
|
||||
|
||||
#define SYSPROF_TYPE_MARK_VISUALIZER (sysprof_mark_visualizer_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofMarkVisualizer, sysprof_mark_visualizer, SYSPROF, MARK_VISUALIZER, SysprofVisualizer)
|
||||
|
||||
SysprofVisualizer *sysprof_mark_visualizer_new (GHashTable *groups);
|
||||
void sysprof_mark_visualizer_set_group_rgba (SysprofMarkVisualizer *self,
|
||||
const gchar *group,
|
||||
const GdkRGBA *rgba);
|
||||
void sysprof_mark_visualizer_set_kind_rgba (SysprofMarkVisualizer *self,
|
||||
GHashTable *rgba_by_kind);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,490 +0,0 @@
|
||||
/* sysprof-marks-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-marks-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-marks-aid.h"
|
||||
#include "sysprof-marks-page.h"
|
||||
#include "sysprof-mark-visualizer.h"
|
||||
|
||||
struct _SysprofMarksAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
SysprofCaptureCursor *cursor;
|
||||
GHashTable *categories;
|
||||
GHashTable *kinds;
|
||||
guint last_kind;
|
||||
guint has_marks : 1;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofMarksAid, sysprof_marks_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
rgb_to_hls (gdouble *r,
|
||||
gdouble *g,
|
||||
gdouble *b)
|
||||
{
|
||||
gdouble min;
|
||||
gdouble max;
|
||||
gdouble red;
|
||||
gdouble green;
|
||||
gdouble blue;
|
||||
gdouble h, l, s;
|
||||
gdouble delta;
|
||||
|
||||
red = *r;
|
||||
green = *g;
|
||||
blue = *b;
|
||||
if (red > green)
|
||||
{
|
||||
if (red > blue)
|
||||
max = red;
|
||||
else
|
||||
max = blue;
|
||||
if (green < blue)
|
||||
min = green;
|
||||
else
|
||||
min = blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (green > blue)
|
||||
max = green;
|
||||
else
|
||||
max = blue;
|
||||
if (red < blue)
|
||||
min = red;
|
||||
else
|
||||
min = blue;
|
||||
}
|
||||
l = (max + min) / 2;
|
||||
s = 0;
|
||||
h = 0;
|
||||
if (max != min)
|
||||
{
|
||||
if (l <= 0.5)
|
||||
s = (max - min) / (max + min);
|
||||
else
|
||||
s = (max - min) / (2 - max - min);
|
||||
delta = max - min;
|
||||
if (red == max)
|
||||
h = (green - blue) / delta;
|
||||
else if (green == max)
|
||||
h = 2 + (blue - red) / delta;
|
||||
else if (blue == max)
|
||||
h = 4 + (red - green) / delta;
|
||||
h *= 60;
|
||||
if (h < 0.0)
|
||||
h += 360;
|
||||
}
|
||||
*r = h;
|
||||
*g = l;
|
||||
*b = s;
|
||||
}
|
||||
|
||||
static void
|
||||
hls_to_rgb (gdouble *h,
|
||||
gdouble *l,
|
||||
gdouble *s)
|
||||
{
|
||||
gdouble hue;
|
||||
gdouble lightness;
|
||||
gdouble saturation;
|
||||
gdouble m1, m2;
|
||||
gdouble r, g, b;
|
||||
|
||||
lightness = *l;
|
||||
saturation = *s;
|
||||
if (lightness <= 0.5)
|
||||
m2 = lightness * (1 + saturation);
|
||||
else
|
||||
m2 = lightness + saturation - lightness * saturation;
|
||||
m1 = 2 * lightness - m2;
|
||||
if (saturation == 0)
|
||||
{
|
||||
*h = lightness;
|
||||
*l = lightness;
|
||||
*s = lightness;
|
||||
}
|
||||
else
|
||||
{
|
||||
hue = *h + 120;
|
||||
while (hue > 360)
|
||||
hue -= 360;
|
||||
while (hue < 0)
|
||||
hue += 360;
|
||||
if (hue < 60)
|
||||
r = m1 + (m2 - m1) * hue / 60;
|
||||
else if (hue < 180)
|
||||
r = m2;
|
||||
else if (hue < 240)
|
||||
r = m1 + (m2 - m1) * (240 - hue) / 60;
|
||||
else
|
||||
r = m1;
|
||||
hue = *h;
|
||||
while (hue > 360)
|
||||
hue -= 360;
|
||||
while (hue < 0)
|
||||
hue += 360;
|
||||
if (hue < 60)
|
||||
g = m1 + (m2 - m1) * hue / 60;
|
||||
else if (hue < 180)
|
||||
g = m2;
|
||||
else if (hue < 240)
|
||||
g = m1 + (m2 - m1) * (240 - hue) / 60;
|
||||
else
|
||||
g = m1;
|
||||
hue = *h - 120;
|
||||
while (hue > 360)
|
||||
hue -= 360;
|
||||
while (hue < 0)
|
||||
hue += 360;
|
||||
if (hue < 60)
|
||||
b = m1 + (m2 - m1) * hue / 60;
|
||||
else if (hue < 180)
|
||||
b = m2;
|
||||
else if (hue < 240)
|
||||
b = m1 + (m2 - m1) * (240 - hue) / 60;
|
||||
else
|
||||
b = m1;
|
||||
*h = r;
|
||||
*l = g;
|
||||
*s = b;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rgba_shade (const GdkRGBA *rgba,
|
||||
GdkRGBA *dst,
|
||||
gdouble k)
|
||||
{
|
||||
gdouble red;
|
||||
gdouble green;
|
||||
gdouble blue;
|
||||
|
||||
red = rgba->red;
|
||||
green = rgba->green;
|
||||
blue = rgba->blue;
|
||||
|
||||
rgb_to_hls (&red, &green, &blue);
|
||||
|
||||
green *= k;
|
||||
|
||||
if (green > 1.0)
|
||||
green = 1.0;
|
||||
else if (green < 0.0)
|
||||
green = 0.0;
|
||||
|
||||
blue *= k;
|
||||
|
||||
if (blue > 1.0)
|
||||
blue = 1.0;
|
||||
else if (blue < 0.0)
|
||||
blue = 0.0;
|
||||
|
||||
hls_to_rgb (&red, &green, &blue);
|
||||
|
||||
dst->red = red;
|
||||
dst->green = green;
|
||||
dst->blue = blue;
|
||||
dst->alpha = rgba->alpha;
|
||||
}
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->categories, g_hash_table_unref);
|
||||
g_clear_pointer (&p->kinds, g_hash_table_unref);
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
static void
|
||||
on_group_activated_cb (SysprofVisualizerGroup *group,
|
||||
SysprofPage *page)
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
|
||||
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
|
||||
g_assert (SYSPROF_IS_PAGE (page));
|
||||
|
||||
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
|
||||
sysprof_display_set_visible_page (display, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_marks_aid_new:
|
||||
*
|
||||
* Create a new #SysprofMarksAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofMarksAid
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_marks_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_MARKS_AID, NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
find_marks_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
Present *p = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (p != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_MARK)
|
||||
{
|
||||
const SysprofCaptureMark *mark = (const SysprofCaptureMark *)frame;
|
||||
SysprofMarkTimeSpan span = { frame->time, frame->time + mark->duration };
|
||||
gchar joined[64];
|
||||
gpointer kptr;
|
||||
GArray *items;
|
||||
|
||||
p->has_marks = TRUE;
|
||||
|
||||
if G_UNLIKELY (!(items = g_hash_table_lookup (p->categories, mark->group)))
|
||||
{
|
||||
items = g_array_new (FALSE, FALSE, sizeof (SysprofMarkTimeSpan));
|
||||
g_hash_table_insert (p->categories, g_strdup (mark->group), items);
|
||||
}
|
||||
|
||||
g_snprintf (joined, sizeof joined, "%s:%s", mark->group, mark->name);
|
||||
|
||||
if G_UNLIKELY (!(kptr = g_hash_table_lookup (p->kinds, joined)))
|
||||
{
|
||||
p->last_kind++;
|
||||
kptr = GINT_TO_POINTER (p->last_kind);
|
||||
g_hash_table_insert (p->kinds, g_strdup (joined), kptr);
|
||||
}
|
||||
|
||||
span.kind = GPOINTER_TO_INT (kptr);
|
||||
|
||||
g_array_append_val (items, span);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_span (const SysprofMarkTimeSpan *a,
|
||||
const SysprofMarkTimeSpan *b)
|
||||
{
|
||||
if (a->kind < b->kind)
|
||||
return -1;
|
||||
|
||||
if (b->kind < a->kind)
|
||||
return 1;
|
||||
|
||||
if (a->begin < b->begin)
|
||||
return -1;
|
||||
|
||||
if (b->begin < a->begin)
|
||||
return 1;
|
||||
|
||||
if (b->end > a->end)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *p = task_data;
|
||||
GHashTableIter iter;
|
||||
gpointer k, v;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (p != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (p->display));
|
||||
g_assert (p->cursor != NULL);
|
||||
g_assert (SYSPROF_IS_MARKS_AID (source_object));
|
||||
|
||||
sysprof_capture_cursor_foreach (p->cursor, find_marks_cb, p);
|
||||
|
||||
g_hash_table_iter_init (&iter, p->categories);
|
||||
while (g_hash_table_iter_next (&iter, &k, &v))
|
||||
{
|
||||
GArray *spans = v;
|
||||
|
||||
g_array_sort (spans, (GCompareFunc)compare_span);
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType marks[] = {
|
||||
SYSPROF_CAPTURE_FRAME_MARK,
|
||||
};
|
||||
SysprofMarksAid *self = (SysprofMarksAid *)aid;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present p = {0};
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_AID (self));
|
||||
|
||||
p.display = g_object_ref (display);
|
||||
p.categories = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
|
||||
(GDestroyNotify) g_array_unref);
|
||||
p.kinds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
p.cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (p.cursor,
|
||||
sysprof_capture_condition_new_where_type_in (1, marks));
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_marks_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &p),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_marks_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_marks_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
Present *p;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
p = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if (p->has_marks)
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *group;
|
||||
SysprofVisualizer *marks;
|
||||
SysprofPage *page;
|
||||
GHashTableIter iter;
|
||||
gpointer k, v;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"has-page", TRUE,
|
||||
"title", _("Timings"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
marks = sysprof_mark_visualizer_new (p->categories);
|
||||
sysprof_visualizer_set_title (marks, _("Timings"));
|
||||
gtk_widget_show (GTK_WIDGET (marks));
|
||||
|
||||
g_hash_table_iter_init (&iter, p->categories);
|
||||
while (g_hash_table_iter_next (&iter, &k, &v))
|
||||
{
|
||||
g_autoptr(GHashTable) seen = g_hash_table_new_full (NULL, NULL, NULL, g_free);
|
||||
g_autoptr(GHashTable) scoped = NULL;
|
||||
SysprofVisualizer *scoped_vis;
|
||||
GArray *spans = v;
|
||||
const gchar *name = k;
|
||||
GdkRGBA rgba;
|
||||
GdkRGBA kind_rgba;
|
||||
gdouble ratio;
|
||||
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
sysprof_mark_visualizer_set_group_rgba (SYSPROF_MARK_VISUALIZER (marks), name, &rgba);
|
||||
|
||||
/* Now make a scoped row just for this group */
|
||||
scoped = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
|
||||
(GDestroyNotify)g_array_unref);
|
||||
g_hash_table_insert (scoped, g_strdup (name), g_array_ref (spans));
|
||||
|
||||
scoped_vis = sysprof_mark_visualizer_new (scoped);
|
||||
sysprof_visualizer_set_title (scoped_vis, name);
|
||||
sysprof_mark_visualizer_set_group_rgba (SYSPROF_MARK_VISUALIZER (scoped_vis), name, &rgba);
|
||||
sysprof_visualizer_group_insert (group, scoped_vis, -1, TRUE);
|
||||
|
||||
ratio = .4 / p->last_kind;
|
||||
|
||||
for (guint i = 0; i < spans->len; i++)
|
||||
{
|
||||
const SysprofMarkTimeSpan *span = &g_array_index (spans, SysprofMarkTimeSpan, i);
|
||||
|
||||
if (!g_hash_table_contains (seen, GUINT_TO_POINTER (span->kind)))
|
||||
{
|
||||
rgba_shade (&rgba, &kind_rgba, 1 + (ratio * span->kind));
|
||||
g_hash_table_insert (seen,
|
||||
GUINT_TO_POINTER (span->kind),
|
||||
g_memdup2 (&kind_rgba, sizeof kind_rgba));
|
||||
}
|
||||
}
|
||||
|
||||
sysprof_mark_visualizer_set_kind_rgba (SYSPROF_MARK_VISUALIZER (scoped_vis), seen);
|
||||
}
|
||||
|
||||
page = g_object_new (SYSPROF_TYPE_MARKS_PAGE,
|
||||
"zoom-manager", sysprof_display_get_zoom_manager (p->display),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
g_signal_connect_object (group,
|
||||
"group-activated",
|
||||
G_CALLBACK (on_group_activated_cb),
|
||||
page,
|
||||
0);
|
||||
|
||||
sysprof_visualizer_group_insert (group, marks, 0, FALSE);
|
||||
sysprof_display_add_group (p->display, group);
|
||||
sysprof_display_add_page (p->display, page);
|
||||
}
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_aid_class_init (SysprofMarksAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->present_async = sysprof_marks_aid_present_async;
|
||||
aid_class->present_finish = sysprof_marks_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_aid_init (SysprofMarksAid *self)
|
||||
{
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-marks-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_MARKS_AID (sysprof_marks_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofMarksAid, sysprof_marks_aid, SYSPROF, MARKS_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_marks_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,592 +0,0 @@
|
||||
/* sysprof-marks-model.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-marks-model"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sysprof-marks-model.h"
|
||||
|
||||
struct _SysprofMarksModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
GStringChunk *chunks;
|
||||
GHashTable *counters;
|
||||
GArray *items;
|
||||
gint64 max_end_time;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
const gchar *group;
|
||||
const gchar *name;
|
||||
const gchar *message;
|
||||
SysprofCaptureCounterValue value;
|
||||
guint is_counter : 1;
|
||||
guint counter_type : 8;
|
||||
} Item;
|
||||
|
||||
static void
|
||||
counter_free (gpointer data)
|
||||
{
|
||||
g_slice_free (SysprofCaptureCounter, data);
|
||||
}
|
||||
|
||||
static gint
|
||||
sysprof_marks_model_get_n_columns (GtkTreeModel *model)
|
||||
{
|
||||
return SYSPROF_MARKS_MODEL_COLUMN_LAST;
|
||||
}
|
||||
|
||||
static GType
|
||||
sysprof_marks_model_get_column_type (GtkTreeModel *model,
|
||||
gint column)
|
||||
{
|
||||
switch (column)
|
||||
{
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_GROUP:
|
||||
return G_TYPE_STRING;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_NAME:
|
||||
return G_TYPE_STRING;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME:
|
||||
return G_TYPE_INT64;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_END_TIME:
|
||||
return G_TYPE_INT64;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_DURATION:
|
||||
return G_TYPE_DOUBLE;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_TEXT:
|
||||
return G_TYPE_STRING;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static GtkTreePath *
|
||||
sysprof_marks_model_get_path (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
gint off;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_MODEL (model));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
off = GPOINTER_TO_INT (iter->user_data);
|
||||
|
||||
return gtk_tree_path_new_from_indices (off, -1);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_marks_model_get_iter (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreePath *path)
|
||||
{
|
||||
SysprofMarksModel *self = (SysprofMarksModel *)model;
|
||||
gint off;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
g_assert (path != NULL);
|
||||
|
||||
memset (iter, 0, sizeof *iter);
|
||||
|
||||
if (gtk_tree_path_get_depth (path) != 1)
|
||||
return FALSE;
|
||||
|
||||
off = gtk_tree_path_get_indices (path)[0];
|
||||
iter->user_data = GINT_TO_POINTER (off);
|
||||
|
||||
return off >= 0 && off < self->items->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_marks_model_iter_next (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
SysprofMarksModel *self = (SysprofMarksModel *)model;
|
||||
gint off;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
off = GPOINTER_TO_INT (iter->user_data);
|
||||
off++;
|
||||
iter->user_data = GINT_TO_POINTER (off);
|
||||
|
||||
return off < self->items->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_marks_model_iter_nth_child (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreeIter *parent,
|
||||
gint n)
|
||||
{
|
||||
SysprofMarksModel *self = (SysprofMarksModel *)model;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
if (parent != NULL)
|
||||
return FALSE;
|
||||
|
||||
iter->user_data = GINT_TO_POINTER (n);
|
||||
|
||||
return n < self->items->len;
|
||||
}
|
||||
|
||||
static gint
|
||||
sysprof_marks_model_iter_n_children (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
SysprofMarksModel *self = (SysprofMarksModel *)model;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_MODEL (self));
|
||||
|
||||
return iter ? 0 : self->items->len;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_marks_model_iter_has_child (GtkTreeModel *model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GtkTreeModelFlags
|
||||
sysprof_marks_model_get_flags (GtkTreeModel *model)
|
||||
{
|
||||
return GTK_TREE_MODEL_LIST_ONLY;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_model_get_value (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
gint column,
|
||||
GValue *value)
|
||||
{
|
||||
SysprofMarksModel *self = (SysprofMarksModel *)model;
|
||||
const Item *item;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_MODEL (self));
|
||||
g_assert (iter != NULL);
|
||||
g_assert (column < SYSPROF_MARKS_MODEL_COLUMN_LAST);
|
||||
|
||||
item = &g_array_index (self->items, Item, GPOINTER_TO_INT (iter->user_data));
|
||||
|
||||
switch (column)
|
||||
{
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_GROUP:
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
g_value_set_string (value, item->group);
|
||||
break;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_NAME:
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
g_value_set_string (value, item->name);
|
||||
break;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME:
|
||||
g_value_init (value, G_TYPE_INT64);
|
||||
g_value_set_int64 (value, item->begin_time);
|
||||
break;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_END_TIME:
|
||||
g_value_init (value, G_TYPE_INT64);
|
||||
g_value_set_int64 (value, item->end_time);
|
||||
break;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_DURATION:
|
||||
g_value_init (value, G_TYPE_DOUBLE);
|
||||
if (item->end_time)
|
||||
g_value_set_double (value, (item->end_time - item->begin_time) / (double)(G_USEC_PER_SEC * 1000));
|
||||
break;
|
||||
|
||||
case SYSPROF_MARKS_MODEL_COLUMN_TEXT:
|
||||
g_value_init (value, G_TYPE_STRING);
|
||||
if (item->is_counter)
|
||||
{
|
||||
gchar *val = NULL;
|
||||
|
||||
if (item->counter_type == SYSPROF_CAPTURE_COUNTER_DOUBLE)
|
||||
val = g_strdup_printf ("%s — %s = %.4lf", item->group, item->name, item->value.vdbl);
|
||||
else if (item->counter_type == SYSPROF_CAPTURE_COUNTER_INT64)
|
||||
val = g_strdup_printf ("%s — %s = %"G_GINT64_FORMAT, item->group, item->name, item->value.v64);
|
||||
|
||||
g_value_take_string (value, g_steal_pointer (&val));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item->message && item->message[0])
|
||||
g_value_take_string (value, g_strdup_printf ("%s — %s", item->name, item->message));
|
||||
else
|
||||
g_value_set_string (value, item->name);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tree_model_iface_init (GtkTreeModelIface *iface)
|
||||
{
|
||||
iface->get_n_columns = sysprof_marks_model_get_n_columns;
|
||||
iface->get_column_type = sysprof_marks_model_get_column_type;
|
||||
iface->get_iter = sysprof_marks_model_get_iter;
|
||||
iface->get_path = sysprof_marks_model_get_path;
|
||||
iface->iter_next = sysprof_marks_model_iter_next;
|
||||
iface->iter_n_children = sysprof_marks_model_iter_n_children;
|
||||
iface->iter_nth_child = sysprof_marks_model_iter_nth_child;
|
||||
iface->iter_has_child = sysprof_marks_model_iter_has_child;
|
||||
iface->get_flags = sysprof_marks_model_get_flags;
|
||||
iface->get_value = sysprof_marks_model_get_value;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (SysprofMarksModel, sysprof_marks_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, tree_model_iface_init))
|
||||
|
||||
static void
|
||||
sysprof_marks_model_finalize (GObject *object)
|
||||
{
|
||||
SysprofMarksModel *self = (SysprofMarksModel *)object;
|
||||
|
||||
g_clear_pointer (&self->counters, g_hash_table_unref);
|
||||
g_clear_pointer (&self->items, g_array_unref);
|
||||
g_clear_pointer (&self->chunks, g_string_chunk_free);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_marks_model_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_model_class_init (SysprofMarksModelClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_marks_model_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_model_init (SysprofMarksModel *self)
|
||||
{
|
||||
self->counters = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, counter_free);
|
||||
self->chunks = g_string_chunk_new (4096*16);
|
||||
self->items = g_array_new (FALSE, FALSE, sizeof (Item));
|
||||
}
|
||||
|
||||
static bool
|
||||
cursor_foreach_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofMarksModel *self = user_data;
|
||||
Item item;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_MODEL (self));
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_MARK ||
|
||||
frame->type == SYSPROF_CAPTURE_FRAME_CTRSET ||
|
||||
frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF ||
|
||||
frame->type == SYSPROF_CAPTURE_FRAME_FORK);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_MARK)
|
||||
{
|
||||
SysprofCaptureMark *mark = (SysprofCaptureMark *)frame;
|
||||
|
||||
item.begin_time = frame->time;
|
||||
item.end_time = item.begin_time + mark->duration;
|
||||
item.group = g_string_chunk_insert_const (self->chunks, mark->group);
|
||||
item.name = g_string_chunk_insert_const (self->chunks, mark->name);
|
||||
item.message = g_string_chunk_insert_const (self->chunks, mark->message);
|
||||
item.value.v64 = 0;
|
||||
item.is_counter = FALSE;
|
||||
item.counter_type = 0;
|
||||
|
||||
if G_LIKELY (item.end_time > self->max_end_time)
|
||||
self->max_end_time = item.end_time;
|
||||
|
||||
g_array_append_val (self->items, item);
|
||||
}
|
||||
else if (frame->type == SYSPROF_CAPTURE_FRAME_FORK)
|
||||
{
|
||||
SysprofCaptureFork *fk = (SysprofCaptureFork *)frame;
|
||||
g_autofree gchar *message = g_strdup_printf ("PID: %d, Child PID: %d", frame->pid, fk->child_pid);
|
||||
|
||||
item.begin_time = frame->time;
|
||||
item.end_time = item.begin_time;
|
||||
item.group = g_string_chunk_insert_const (self->chunks, "fork");
|
||||
item.name = g_string_chunk_insert_const (self->chunks, "Fork");
|
||||
item.message = g_string_chunk_insert_const (self->chunks, message);
|
||||
item.value.v64 = 0;
|
||||
item.is_counter = FALSE;
|
||||
item.counter_type = 0;
|
||||
|
||||
g_array_append_val (self->items, item);
|
||||
}
|
||||
else if (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF)
|
||||
{
|
||||
SysprofCaptureCounterDefine *ctrdef = (SysprofCaptureCounterDefine *)frame;
|
||||
|
||||
for (guint i = 0; i < ctrdef->n_counters; i++)
|
||||
{
|
||||
SysprofCaptureCounter *ctr = &ctrdef->counters[i];
|
||||
|
||||
g_hash_table_insert (self->counters,
|
||||
GUINT_TO_POINTER ((guint)ctr->id),
|
||||
g_slice_dup (SysprofCaptureCounter, ctr));
|
||||
}
|
||||
}
|
||||
else if (frame->type == SYSPROF_CAPTURE_FRAME_CTRSET)
|
||||
{
|
||||
SysprofCaptureCounterSet *ctrset = (SysprofCaptureCounterSet *)frame;
|
||||
|
||||
for (guint i = 0; i < ctrset->n_values; i++)
|
||||
{
|
||||
SysprofCaptureCounterValues *values = &ctrset->values[i];
|
||||
|
||||
for (guint j = 0; j < G_N_ELEMENTS (values->ids); j++)
|
||||
{
|
||||
guint32 id = values->ids[j];
|
||||
SysprofCaptureCounter *ctr = NULL;
|
||||
|
||||
if (id == 0)
|
||||
break;
|
||||
|
||||
if ((ctr = g_hash_table_lookup (self->counters, GUINT_TO_POINTER (id))))
|
||||
{
|
||||
item.begin_time = frame->time;
|
||||
item.end_time = frame->time;
|
||||
item.group = ctr->category;
|
||||
item.name = ctr->name;
|
||||
item.message = NULL;
|
||||
item.is_counter = TRUE;
|
||||
item.counter_type = ctr->type;
|
||||
|
||||
memcpy (&item.value, &values->values[j], sizeof item.value);
|
||||
|
||||
g_array_append_val (self->items, item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
item_compare (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const Item *ia = a;
|
||||
const Item *ib = b;
|
||||
|
||||
if (ia->begin_time < ib->begin_time)
|
||||
return -1;
|
||||
else if (ia->begin_time > ib->begin_time)
|
||||
return 1;
|
||||
|
||||
/* Sort items with longer duration first, as they might be
|
||||
* "overarching" marks containing other marks.
|
||||
*/
|
||||
if (ia->end_time > ib->end_time)
|
||||
return -1;
|
||||
else if (ib->end_time > ia->end_time)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_model_new_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
g_autoptr(SysprofMarksModel) self = NULL;
|
||||
SysprofCaptureCursor *cursor = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_MARKS_MODEL, NULL);
|
||||
sysprof_capture_cursor_foreach (cursor, cursor_foreach_cb, self);
|
||||
g_array_sort (self->items, item_compare);
|
||||
|
||||
g_task_return_pointer (task, g_steal_pointer (&self), g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_model_selection_foreach_cb (SysprofSelection *selection,
|
||||
gint64 begin,
|
||||
gint64 end,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCondition **condition = user_data;
|
||||
SysprofCaptureCondition *c;
|
||||
|
||||
g_assert (SYSPROF_IS_SELECTION (selection));
|
||||
g_assert (condition != NULL);
|
||||
|
||||
c = sysprof_capture_condition_new_where_time_between (begin, end);
|
||||
|
||||
if (*condition != NULL)
|
||||
*condition = sysprof_capture_condition_new_or (g_steal_pointer (&c),
|
||||
g_steal_pointer (condition));
|
||||
else
|
||||
*condition = g_steal_pointer (&c);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_marks_model_new_async (SysprofCaptureReader *reader,
|
||||
SysprofMarksModelKind kind,
|
||||
SysprofSelection *selection,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType ctrset[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
SysprofCaptureCondition *c;
|
||||
|
||||
g_return_if_fail (reader != NULL);
|
||||
g_return_if_fail (!selection || SYSPROF_IS_SELECTION (selection));
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
|
||||
if (kind == SYSPROF_MARKS_MODEL_BOTH)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = {
|
||||
SYSPROF_CAPTURE_FRAME_CTRSET,
|
||||
SYSPROF_CAPTURE_FRAME_MARK,
|
||||
};
|
||||
|
||||
c = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
|
||||
}
|
||||
else if (kind == SYSPROF_MARKS_MODEL_MARKS)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = {
|
||||
SYSPROF_CAPTURE_FRAME_MARK,
|
||||
SYSPROF_CAPTURE_FRAME_FORK,
|
||||
};
|
||||
|
||||
c = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
|
||||
}
|
||||
else if (kind == SYSPROF_MARKS_MODEL_COUNTERS)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRSET };
|
||||
|
||||
c = sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (types), types);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_task_report_new_error (NULL, callback, user_data,
|
||||
sysprof_marks_model_new_async,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_INVAL,
|
||||
"Invalid arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selection)
|
||||
{
|
||||
SysprofCaptureCondition *condition = NULL;
|
||||
|
||||
sysprof_selection_foreach (selection,
|
||||
sysprof_marks_model_selection_foreach_cb,
|
||||
&condition);
|
||||
if (condition)
|
||||
c = sysprof_capture_condition_new_and (c, g_steal_pointer (&condition));
|
||||
}
|
||||
|
||||
if (kind & SYSPROF_MARKS_MODEL_COUNTERS)
|
||||
{
|
||||
c = sysprof_capture_condition_new_or (
|
||||
sysprof_capture_condition_new_where_type_in (G_N_ELEMENTS (ctrset), ctrset),
|
||||
g_steal_pointer (&c));
|
||||
}
|
||||
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&c));
|
||||
|
||||
task = g_task_new (NULL, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_marks_model_new_async);
|
||||
g_task_set_task_data (task,
|
||||
g_steal_pointer (&cursor),
|
||||
(GDestroyNotify) sysprof_capture_cursor_unref);
|
||||
g_task_run_in_thread (task, sysprof_marks_model_new_worker);
|
||||
}
|
||||
|
||||
SysprofMarksModel *
|
||||
sysprof_marks_model_new_finish (GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_TASK (result), NULL);
|
||||
|
||||
return g_task_propagate_pointer (G_TASK (result), error);
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_marks_model_get_range (SysprofMarksModel *self,
|
||||
gint64 *begin_time,
|
||||
gint64 *end_time)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_MARKS_MODEL (self));
|
||||
|
||||
if (begin_time != NULL)
|
||||
{
|
||||
*begin_time = 0;
|
||||
|
||||
if (self->items->len > 0)
|
||||
*begin_time = g_array_index (self->items, Item, 0).begin_time;
|
||||
}
|
||||
|
||||
if (end_time != NULL)
|
||||
*end_time = self->max_end_time;
|
||||
}
|
||||
|
||||
GType
|
||||
sysprof_marks_model_kind_get_type (void)
|
||||
{
|
||||
static GType type_id;
|
||||
|
||||
if (g_once_init_enter (&type_id))
|
||||
{
|
||||
static const GEnumValue values[] = {
|
||||
{ SYSPROF_MARKS_MODEL_MARKS, "SYSPROF_MARKS_MODEL_MARKS", "marks" },
|
||||
{ SYSPROF_MARKS_MODEL_COUNTERS, "SYSPROF_MARKS_MODEL_COUNTERS", "counters" },
|
||||
{ SYSPROF_MARKS_MODEL_BOTH, "SYSPROF_MARKS_MODEL_BOTH", "both" },
|
||||
{ 0 },
|
||||
};
|
||||
GType _type_id = g_enum_register_static ("SysprofMarksModelKind", values);
|
||||
g_once_init_leave (&type_id, _type_id);
|
||||
}
|
||||
|
||||
return type_id;
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
/* sysprof-marks-model.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_MARKS_MODEL (sysprof_marks_model_get_type())
|
||||
#define SYSPROF_TYPE_MARKS_MODEL_KIND (sysprof_marks_model_kind_get_type())
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SYSPROF_MARKS_MODEL_COLUMN_GROUP,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_NAME,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_END_TIME,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_DURATION,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_TEXT,
|
||||
} SysprofMarksModelColumn;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SYSPROF_MARKS_MODEL_MARKS = 1,
|
||||
SYSPROF_MARKS_MODEL_COUNTERS,
|
||||
SYSPROF_MARKS_MODEL_BOTH = SYSPROF_MARKS_MODEL_MARKS | SYSPROF_MARKS_MODEL_COUNTERS,
|
||||
} SysprofMarksModelKind;
|
||||
|
||||
#define SYSPROF_MARKS_MODEL_COLUMN_LAST (SYSPROF_MARKS_MODEL_COLUMN_TEXT+1)
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofMarksModel, sysprof_marks_model, SYSPROF, MARKS_MODEL, GObject)
|
||||
|
||||
GType sysprof_marks_model_kind_get_type (void) G_GNUC_CONST;
|
||||
void sysprof_marks_model_new_async (SysprofCaptureReader *reader,
|
||||
SysprofMarksModelKind kind,
|
||||
SysprofSelection *selection,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
SysprofMarksModel *sysprof_marks_model_new_finish (GAsyncResult *result,
|
||||
GError **error);
|
||||
void sysprof_marks_model_get_range (SysprofMarksModel *self,
|
||||
gint64 *begin_time,
|
||||
gint64 *end_time);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,610 +0,0 @@
|
||||
/* sysprof-marks-page.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-marks-page"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-cell-renderer-duration.h"
|
||||
#include "sysprof-marks-model.h"
|
||||
#include "sysprof-marks-page.h"
|
||||
#include "sysprof-ui-private.h"
|
||||
#include "sysprof-zoom-manager.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofMarksModelKind kind;
|
||||
|
||||
SysprofZoomManager *zoom_manager;
|
||||
|
||||
gint64 capture_begin_time;
|
||||
gint64 capture_end_time;
|
||||
|
||||
/* Template objects */
|
||||
GtkScrolledWindow *scroller;
|
||||
GtkTreeView *tree_view;
|
||||
GtkBox *details_box;
|
||||
GtkTreeViewColumn *duration_column;
|
||||
SysprofCellRendererDuration *duration_cell;
|
||||
GtkStack *stack;
|
||||
GtkLabel *group;
|
||||
GtkLabel *mark;
|
||||
GtkLabel *time;
|
||||
GtkLabel *end;
|
||||
GtkLabel *duration;
|
||||
GtkTextView *message;
|
||||
GtkWidget *failed;
|
||||
GtkWidget *marks;
|
||||
} SysprofMarksPagePrivate;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_KIND,
|
||||
PROP_ZOOM_MANAGER,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (SysprofMarksPage, sysprof_marks_page, SYSPROF_TYPE_PAGE)
|
||||
|
||||
static gboolean
|
||||
sysprof_marks_page_tree_view_key_press_event_cb (SysprofMarksPage *self,
|
||||
guint keyval,
|
||||
guint keycode,
|
||||
GdkModifierType state,
|
||||
GtkEventControllerKey *controller)
|
||||
{
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
gint dir = 0;
|
||||
|
||||
g_assert (SYSPROF_MARKS_PAGE (self));
|
||||
g_assert (GTK_IS_EVENT_CONTROLLER_KEY (controller));
|
||||
|
||||
if ((state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK)) == 0)
|
||||
{
|
||||
switch (keyval)
|
||||
{
|
||||
case GDK_KEY_Left:
|
||||
dir = -1;
|
||||
break;
|
||||
|
||||
case GDK_KEY_Right:
|
||||
dir = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dir)
|
||||
{
|
||||
GtkAdjustment *adj = gtk_scrolled_window_get_hadjustment (priv->scroller);
|
||||
gdouble step = gtk_adjustment_get_step_increment (adj);
|
||||
gdouble val = CLAMP (gtk_adjustment_get_value (adj) + (step * dir),
|
||||
gtk_adjustment_get_lower (adj),
|
||||
gtk_adjustment_get_upper (adj));
|
||||
gtk_adjustment_set_value (adj, val);
|
||||
return GDK_EVENT_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
return GDK_EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_first_selected (GtkTreeSelection *selection,
|
||||
GtkTreeModel **model,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
GtkTreeModel *m;
|
||||
|
||||
g_assert (GTK_IS_TREE_SELECTION (selection));
|
||||
|
||||
if (gtk_tree_selection_count_selected_rows (selection) != 1)
|
||||
return FALSE;
|
||||
|
||||
m = gtk_tree_view_get_model (gtk_tree_selection_get_tree_view (selection));
|
||||
if (model)
|
||||
*model = m;
|
||||
|
||||
if (iter)
|
||||
{
|
||||
GList *paths = gtk_tree_selection_get_selected_rows (selection, model);
|
||||
gtk_tree_model_get_iter (m, iter, paths->data);
|
||||
g_list_free_full (paths, (GDestroyNotify)gtk_tree_path_free);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_selection_changed_cb (SysprofMarksPage *self,
|
||||
GtkTreeSelection *selection)
|
||||
{
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_PAGE (self));
|
||||
g_assert (GTK_IS_TREE_SELECTION (selection));
|
||||
|
||||
if (get_first_selected (selection, &model, &iter))
|
||||
{
|
||||
g_autofree gchar *group = NULL;
|
||||
g_autofree gchar *name = NULL;
|
||||
g_autofree gchar *duration_str = NULL;
|
||||
g_autofree gchar *time_str = NULL;
|
||||
g_autofree gchar *end_str = NULL;
|
||||
g_autofree gchar *text = NULL;
|
||||
GtkAdjustment *adj;
|
||||
gdouble x;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
gint64 duration;
|
||||
gint64 etime;
|
||||
gint64 otime;
|
||||
gdouble lower;
|
||||
gdouble upper;
|
||||
gdouble value;
|
||||
gdouble page_size;
|
||||
gint width;
|
||||
|
||||
gtk_tree_model_get (model, &iter,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_GROUP, &group,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_NAME, &name,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME, &begin_time,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_END_TIME, &end_time,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_TEXT, &text,
|
||||
-1);
|
||||
|
||||
duration = end_time - begin_time;
|
||||
duration_str = _sysprof_format_duration (duration);
|
||||
|
||||
otime = begin_time - priv->capture_begin_time;
|
||||
time_str = _sysprof_format_duration (otime);
|
||||
|
||||
etime = end_time - priv->capture_begin_time;
|
||||
end_str = _sysprof_format_duration (etime);
|
||||
|
||||
gtk_label_set_label (priv->group, group);
|
||||
gtk_label_set_label (priv->mark, name);
|
||||
gtk_label_set_label (priv->duration, duration_str);
|
||||
gtk_label_set_label (priv->time, time_str);
|
||||
gtk_label_set_label (priv->end, end_str);
|
||||
|
||||
gtk_text_buffer_set_text (gtk_text_view_get_buffer (priv->message), text, -1);
|
||||
|
||||
adj = gtk_scrolled_window_get_hadjustment (priv->scroller);
|
||||
width = gtk_tree_view_column_get_width (priv->duration_column);
|
||||
x = sysprof_zoom_manager_get_offset_at_time (priv->zoom_manager,
|
||||
begin_time - priv->capture_begin_time,
|
||||
width);
|
||||
|
||||
g_object_get (adj,
|
||||
"lower", &lower,
|
||||
"upper", &upper,
|
||||
"value", &value,
|
||||
"page-size", &page_size,
|
||||
NULL);
|
||||
|
||||
if (x < value)
|
||||
gtk_adjustment_set_value (adj, MAX (lower, x - (page_size / 3.0)));
|
||||
else if (x > (value + page_size))
|
||||
gtk_adjustment_set_value (adj, MIN (upper - page_size, (x - (page_size / 3.0))));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_marks_page_tree_view_query_tooltip_cb (SysprofMarksPage *self,
|
||||
gint x,
|
||||
gint y,
|
||||
gboolean keyboard_mode,
|
||||
GtkTooltip *tooltip,
|
||||
GtkTreeView *tree_view)
|
||||
{
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
GtkTreeViewColumn *column;
|
||||
GtkTreePath *path = NULL;
|
||||
gint cell_x, cell_y;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_PAGE (self));
|
||||
g_assert (GTK_IS_TOOLTIP (tooltip));
|
||||
g_assert (GTK_IS_TREE_VIEW (tree_view));
|
||||
|
||||
if (gtk_tree_view_get_path_at_pos (tree_view, x, y, &path, &column, &cell_x, &cell_y))
|
||||
{
|
||||
GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (gtk_tree_model_get_iter (model, &iter, path))
|
||||
{
|
||||
g_autofree gchar *text = NULL;
|
||||
g_autofree gchar *timestr = NULL;
|
||||
g_autofree gchar *tooltip_text = NULL;
|
||||
g_autofree gchar *durationstr = NULL;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
gint64 duration;
|
||||
|
||||
gtk_tree_model_get (model, &iter,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME, &begin_time,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_END_TIME, &end_time,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_TEXT, &text,
|
||||
-1);
|
||||
|
||||
duration = end_time - begin_time;
|
||||
begin_time -= priv->capture_begin_time;
|
||||
durationstr = _sysprof_format_duration (duration);
|
||||
|
||||
if (duration != 0)
|
||||
timestr = g_strdup_printf ("%0.4lf (%s)", begin_time / (gdouble)SYSPROF_NSEC_PER_SEC, durationstr);
|
||||
else
|
||||
timestr = g_strdup_printf ("%0.4lf", begin_time / (gdouble)SYSPROF_NSEC_PER_SEC);
|
||||
|
||||
tooltip_text = g_strdup_printf ("%s: %s", timestr, text);
|
||||
|
||||
gtk_tooltip_set_text (tooltip, tooltip_text);
|
||||
|
||||
ret = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_load_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(SysprofMarksModel) model = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GTask) task = user_data;
|
||||
SysprofMarksPagePrivate *priv;
|
||||
SysprofCaptureReader *reader;
|
||||
SysprofMarksPage *self;
|
||||
|
||||
g_assert (G_IS_ASYNC_RESULT (result));
|
||||
g_assert (G_IS_TASK (task));
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
priv = sysprof_marks_page_get_instance_private (self);
|
||||
|
||||
if (!(model = sysprof_marks_model_new_finish (result, &error)))
|
||||
{
|
||||
g_task_return_error (task, g_steal_pointer (&error));
|
||||
return;
|
||||
}
|
||||
|
||||
reader = g_task_get_task_data (task);
|
||||
g_assert (reader != NULL);
|
||||
|
||||
priv->capture_begin_time = sysprof_capture_reader_get_start_time (reader);
|
||||
priv->capture_end_time = sysprof_capture_reader_get_end_time (reader);
|
||||
|
||||
g_object_set (priv->duration_cell,
|
||||
"capture-begin-time", priv->capture_begin_time,
|
||||
"capture-end-time", priv->capture_end_time,
|
||||
"zoom-manager", priv->zoom_manager,
|
||||
NULL);
|
||||
|
||||
gtk_tree_view_set_model (priv->tree_view, GTK_TREE_MODEL (model));
|
||||
|
||||
if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL) == 0)
|
||||
gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (priv->failed));
|
||||
else
|
||||
gtk_stack_set_visible_child (priv->stack, GTK_WIDGET (priv->marks));
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_load_async (SysprofPage *page,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofSelection *selection,
|
||||
SysprofCaptureCondition *filter,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofMarksPage *self = (SysprofMarksPage *)page;
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
g_autoptr(GTask) task = NULL;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_MARKS_PAGE (self));
|
||||
g_return_if_fail (reader != NULL);
|
||||
g_return_if_fail (!selection || SYSPROF_IS_SELECTION (selection));
|
||||
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_marks_page_load_async);
|
||||
g_task_set_task_data (task,
|
||||
sysprof_capture_reader_ref (reader),
|
||||
(GDestroyNotify) sysprof_capture_reader_unref);
|
||||
|
||||
sysprof_marks_model_new_async (reader,
|
||||
priv->kind,
|
||||
selection,
|
||||
cancellable,
|
||||
sysprof_marks_page_load_cb,
|
||||
g_steal_pointer (&task));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_marks_page_load_finish (SysprofPage *page,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_MARKS_PAGE (page), FALSE);
|
||||
g_return_val_if_fail (G_IS_TASK (result), FALSE);
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_set_hadjustment (SysprofPage *page,
|
||||
GtkAdjustment *hadjustment)
|
||||
{
|
||||
SysprofMarksPage *self = (SysprofMarksPage *)page;
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_PAGE (self));
|
||||
g_assert (!hadjustment || GTK_IS_ADJUSTMENT (hadjustment));
|
||||
|
||||
gtk_scrolled_window_set_hadjustment (priv->scroller, hadjustment);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_set_size_group (SysprofPage *page,
|
||||
GtkSizeGroup *size_group)
|
||||
{
|
||||
SysprofMarksPage *self = (SysprofMarksPage *)page;
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_PAGE (self));
|
||||
g_assert (GTK_IS_SIZE_GROUP (size_group));
|
||||
|
||||
gtk_size_group_add_widget (size_group, GTK_WIDGET (priv->details_box));
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_tree_view_row_activated_cb (SysprofMarksPage *self,
|
||||
GtkTreePath *path,
|
||||
GtkTreeViewColumn *column,
|
||||
GtkTreeView *tree_view)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
|
||||
g_assert (SYSPROF_IS_MARKS_PAGE (self));
|
||||
g_assert (path != NULL);
|
||||
g_assert (GTK_IS_TREE_VIEW_COLUMN (column));
|
||||
g_assert (GTK_IS_TREE_VIEW (tree_view));
|
||||
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
|
||||
if (gtk_tree_model_get_iter (model, &iter, path))
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
gint64 begin_time;
|
||||
gint64 end_time;
|
||||
|
||||
gtk_tree_model_get (model, &iter,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_BEGIN_TIME, &begin_time,
|
||||
SYSPROF_MARKS_MODEL_COLUMN_END_TIME, &end_time,
|
||||
-1);
|
||||
|
||||
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (self), SYSPROF_TYPE_DISPLAY));
|
||||
sysprof_display_add_to_selection (display, begin_time, end_time);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_finalize (GObject *object)
|
||||
{
|
||||
SysprofMarksPage *self = (SysprofMarksPage *)object;
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
|
||||
g_clear_object (&priv->zoom_manager);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_marks_page_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofMarksPage *self = SYSPROF_MARKS_PAGE (object);
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_KIND:
|
||||
g_value_set_enum (value, priv->kind);
|
||||
break;
|
||||
|
||||
case PROP_ZOOM_MANAGER:
|
||||
g_value_set_object (value, priv->zoom_manager);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofMarksPage *self = SYSPROF_MARKS_PAGE (object);
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_KIND:
|
||||
priv->kind = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_ZOOM_MANAGER:
|
||||
if (g_set_object (&priv->zoom_manager, g_value_get_object (value)))
|
||||
{
|
||||
g_object_set (priv->duration_cell,
|
||||
"zoom-manager", priv->zoom_manager,
|
||||
NULL);
|
||||
if (priv->zoom_manager)
|
||||
g_signal_connect_object (priv->zoom_manager,
|
||||
"notify::zoom",
|
||||
G_CALLBACK (gtk_tree_view_column_queue_resize),
|
||||
priv->duration_column,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_class_init (SysprofMarksPageClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofPageClass *page_class = SYSPROF_PAGE_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_marks_page_finalize;
|
||||
object_class->get_property = sysprof_marks_page_get_property;
|
||||
object_class->set_property = sysprof_marks_page_set_property;
|
||||
|
||||
page_class->load_async = sysprof_marks_page_load_async;
|
||||
page_class->load_finish = sysprof_marks_page_load_finish;
|
||||
page_class->set_hadjustment = sysprof_marks_page_set_hadjustment;
|
||||
page_class->set_size_group = sysprof_marks_page_set_size_group;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/sysprof/ui/sysprof-marks-page.ui");
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, end);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, details_box);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, duration_cell);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, duration_column);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, scroller);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, stack);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, tree_view);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, group);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, mark);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, duration);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, time);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, message);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, marks);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, SysprofMarksPage, failed);
|
||||
|
||||
properties [PROP_KIND] =
|
||||
g_param_spec_enum ("kind", NULL, NULL,
|
||||
SYSPROF_TYPE_MARKS_MODEL_KIND,
|
||||
SYSPROF_MARKS_MODEL_MARKS,
|
||||
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
properties [PROP_ZOOM_MANAGER] =
|
||||
g_param_spec_object ("zoom-manager", NULL, NULL,
|
||||
SYSPROF_TYPE_ZOOM_MANAGER,
|
||||
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
g_type_ensure (SYSPROF_TYPE_CELL_RENDERER_DURATION);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_marks_page_init (SysprofMarksPage *self)
|
||||
{
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
GtkEventController *controller;
|
||||
|
||||
priv->kind = SYSPROF_MARKS_MODEL_MARKS;
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (priv->tree_view),
|
||||
GTK_SELECTION_MULTIPLE);
|
||||
|
||||
controller = gtk_event_controller_key_new ();
|
||||
gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
|
||||
g_signal_connect_object (controller,
|
||||
"key-pressed",
|
||||
G_CALLBACK (sysprof_marks_page_tree_view_key_press_event_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
g_signal_connect_object (priv->tree_view,
|
||||
"row-activated",
|
||||
G_CALLBACK (sysprof_marks_page_tree_view_row_activated_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
|
||||
g_signal_connect_object (priv->tree_view,
|
||||
"query-tooltip",
|
||||
G_CALLBACK (sysprof_marks_page_tree_view_query_tooltip_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
|
||||
g_signal_connect_object (gtk_tree_view_get_selection (priv->tree_view),
|
||||
"changed",
|
||||
G_CALLBACK (sysprof_marks_page_selection_changed_cb),
|
||||
self,
|
||||
G_CONNECT_SWAPPED);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
sysprof_marks_page_new (SysprofZoomManager *zoom_manager,
|
||||
SysprofMarksModelKind kind)
|
||||
{
|
||||
SysprofMarksPage *self;
|
||||
SysprofMarksPagePrivate *priv;
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_ZOOM_MANAGER (zoom_manager), NULL);
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_MARKS_PAGE,
|
||||
"zoom-manager", zoom_manager,
|
||||
NULL);
|
||||
priv = sysprof_marks_page_get_instance_private (self);
|
||||
priv->kind = kind;
|
||||
|
||||
return GTK_WIDGET (self);
|
||||
}
|
||||
|
||||
void
|
||||
_sysprof_marks_page_set_hadjustment (SysprofMarksPage *self,
|
||||
GtkAdjustment *hadjustment)
|
||||
{
|
||||
SysprofMarksPagePrivate *priv = sysprof_marks_page_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_MARKS_PAGE (self));
|
||||
g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
|
||||
|
||||
gtk_scrolled_window_set_hadjustment (priv->scroller, hadjustment);
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
/* sysprof-marks-page.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-marks-model.h"
|
||||
#include "sysprof-page.h"
|
||||
#include "sysprof-zoom-manager.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_MARKS_PAGE (sysprof_marks_page_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofMarksPage, sysprof_marks_page, SYSPROF, MARKS_PAGE, SysprofPage)
|
||||
|
||||
struct _SysprofMarksPageClass
|
||||
{
|
||||
SysprofPageClass parent_class;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
GtkWidget *sysprof_marks_page_new (SysprofZoomManager *zoom_manager,
|
||||
SysprofMarksModelKind kind);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,259 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="SysprofMarksPage" parent="SysprofPage">
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="hhomogeneous">false</property>
|
||||
<property name="vhomogeneous">false</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="marks">
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="details_box">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Details</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-start">6</property>
|
||||
<property name="margin-end">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="hexpand">false</property>
|
||||
<property name="vexpand">true</property>
|
||||
<property name="margin-start">6</property>
|
||||
<property name="margin-end">6</property>
|
||||
<property name="column-spacing">6</property>
|
||||
<property name="row-spacing">3</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Group</property>
|
||||
<property name="xalign">1</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="row">0</property>
|
||||
<property name="column">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Mark</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="yalign">0</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="row">1</property>
|
||||
<property name="column">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Time</property>
|
||||
<property name="xalign">1</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="row">2</property>
|
||||
<property name="column">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">End</property>
|
||||
<property name="xalign">1</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="row">3</property>
|
||||
<property name="column">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Duration</property>
|
||||
<property name="xalign">1</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="row">4</property>
|
||||
<property name="column">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Message</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="yalign">0</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="row">5</property>
|
||||
<property name="column">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="group">
|
||||
<property name="xalign">0</property>
|
||||
<property name="wrap">true</property>
|
||||
<layout>
|
||||
<property name="row">0</property>
|
||||
<property name="column">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="mark">
|
||||
<property name="xalign">0</property>
|
||||
<property name="max-width-chars">5</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<layout>
|
||||
<property name="row">1</property>
|
||||
<property name="column">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="time">
|
||||
<property name="xalign">0</property>
|
||||
<layout>
|
||||
<property name="row">2</property>
|
||||
<property name="column">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="end">
|
||||
<property name="xalign">0</property>
|
||||
<layout>
|
||||
<property name="row">3</property>
|
||||
<property name="column">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="duration">
|
||||
<property name="xalign">0</property>
|
||||
<layout>
|
||||
<property name="row">4</property>
|
||||
<property name="column">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="message">
|
||||
<property name="editable">false</property>
|
||||
</object>
|
||||
</child>
|
||||
<layout>
|
||||
<property name="row">5</property>
|
||||
<property name="column">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
<property name="orientation">vertical</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scroller">
|
||||
<property name="hscrollbar-policy">external</property>
|
||||
<property name="hexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="tree_view">
|
||||
<property name="enable-grid-lines">horizontal</property>
|
||||
<property name="has-tooltip">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="duration_column">
|
||||
<property name="title" translatable="yes">Duration</property>
|
||||
<property name="expand">true</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererDuration" id="duration_cell">
|
||||
<property name="xalign">0</property>
|
||||
<property name="ypad">1</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">5</attribute>
|
||||
<attribute name="begin-time">2</attribute>
|
||||
<attribute name="end-time">3</attribute>
|
||||
</attributes>
|
||||
<cell-packing>
|
||||
<property name="expand">true</property>
|
||||
</cell-packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="failed">
|
||||
<property name="halign">center</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">12</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="icon-name">computer-fail-symbolic</property>
|
||||
<property name="pixel-size">128</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="title">
|
||||
<property name="label" translatable="yes">No Timings Available</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<attributes>
|
||||
<attribute name="scale" value="2.0"/>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="subtitle">
|
||||
<property name="label" translatable="yes">No timing data was found for the current selection</property>
|
||||
<property name="use-markup">true</property>
|
||||
<property name="wrap">true</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,70 +0,0 @@
|
||||
/* sysprof-memory-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-memory-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-memory-aid.h"
|
||||
|
||||
struct _SysprofMemoryAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofMemoryAid, sysprof_memory_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
SysprofAid *
|
||||
sysprof_memory_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_MEMORY_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memory_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
#ifdef __linux__
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_MEMORY_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
source = sysprof_memory_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memory_aid_class_init (SysprofMemoryAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_memory_aid_prepare;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memory_aid_init (SysprofMemoryAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Memory Usage"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-memory-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_MEMORY_AID (sysprof_memory_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofMemoryAid, sysprof_memory_aid, SYSPROF, MEMORY_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_memory_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,226 +0,0 @@
|
||||
/* sysprof-memprof-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-memprof-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-memprof-aid.h"
|
||||
#include "sysprof-memprof-page.h"
|
||||
#include "sysprof-memprof-source.h"
|
||||
#include "sysprof-memprof-visualizer.h"
|
||||
|
||||
struct _SysprofMemprofAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofMemprofAid, sysprof_memprof_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
guint has_allocs : 1;
|
||||
} Present;
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
static void
|
||||
on_group_activated_cb (SysprofVisualizerGroup *group,
|
||||
SysprofPage *page)
|
||||
{
|
||||
SysprofDisplay *display;
|
||||
|
||||
g_assert (SYSPROF_IS_VISUALIZER_GROUP (group));
|
||||
g_assert (SYSPROF_IS_PAGE (page));
|
||||
|
||||
display = SYSPROF_DISPLAY (gtk_widget_get_ancestor (GTK_WIDGET (page), SYSPROF_TYPE_DISPLAY));
|
||||
sysprof_display_set_visible_page (display, page);
|
||||
}
|
||||
|
||||
SysprofAid *
|
||||
sysprof_memprof_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_MEMPROF_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
#ifdef __linux__
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_MEMPROF_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
source = sysprof_memprof_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
discover_samples_cb (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
Present *p = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (p != NULL);
|
||||
|
||||
if (frame->type == SYSPROF_CAPTURE_FRAME_ALLOCATION)
|
||||
{
|
||||
p->has_allocs = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *p = task_data;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_MEMPROF_AID (source_object));
|
||||
g_assert (p != NULL);
|
||||
g_assert (p->cursor != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
sysprof_capture_cursor_foreach (p->cursor, discover_samples_cb, p);
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_ALLOCATION };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_MEMPROF_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_memprof_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_memprof_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_memprof_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
Present *p;
|
||||
|
||||
g_assert (SYSPROF_IS_MEMPROF_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
p = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if (p->has_allocs)
|
||||
{
|
||||
SysprofVisualizerGroup *group;
|
||||
SysprofVisualizer *row;
|
||||
SysprofPage *page;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"has-page", TRUE,
|
||||
"priority", -300,
|
||||
"title", _("Memory"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
row = sysprof_memprof_visualizer_new (FALSE);
|
||||
sysprof_visualizer_group_insert (group, row, 0, FALSE);
|
||||
|
||||
row = sysprof_memprof_visualizer_new (TRUE);
|
||||
sysprof_visualizer_group_insert (group, row, 1, FALSE);
|
||||
|
||||
page = g_object_new (SYSPROF_TYPE_MEMPROF_PAGE,
|
||||
"title", _("Memory Allocations"),
|
||||
"vexpand", TRUE,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
sysprof_display_add_page (p->display, page);
|
||||
|
||||
g_signal_connect_object (group,
|
||||
"group-activated",
|
||||
G_CALLBACK (on_group_activated_cb),
|
||||
page,
|
||||
0);
|
||||
|
||||
sysprof_display_add_group (p->display, group);
|
||||
}
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_aid_class_init (SysprofMemprofAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_memprof_aid_prepare;
|
||||
aid_class->present_async = sysprof_memprof_aid_present_async;
|
||||
aid_class->present_finish = sysprof_memprof_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_aid_init (SysprofMemprofAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Track Allocations"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "org.gnome.Sysprof-symbolic");
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-memprof-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_MEMPROF_AID (sysprof_memprof_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofMemprofAid, sysprof_memprof_aid, SYSPROF, MEMPROF_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_memprof_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
/* sysprof-memprof-page.h
|
||||
*
|
||||
* Copyright 2016-2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <sysprof.h>
|
||||
|
||||
#include "sysprof-page.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_MEMPROF_PAGE (sysprof_memprof_page_get_type())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofMemprofPage, sysprof_memprof_page, SYSPROF, MEMPROF_PAGE, SysprofPage)
|
||||
|
||||
struct _SysprofMemprofPageClass
|
||||
{
|
||||
SysprofPageClass parent_class;
|
||||
|
||||
void (*go_previous) (SysprofMemprofPage *self);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _reserved[16];
|
||||
};
|
||||
|
||||
GtkWidget *sysprof_memprof_page_new (void);
|
||||
SysprofMemprofProfile *sysprof_memprof_page_get_profile (SysprofMemprofPage *self);
|
||||
void sysprof_memprof_page_set_profile (SysprofMemprofPage *self,
|
||||
SysprofMemprofProfile *profile);
|
||||
gchar *sysprof_memprof_page_screenshot (SysprofMemprofPage *self);
|
||||
guint sysprof_memprof_page_get_n_functions (SysprofMemprofPage *self);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,330 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="SysprofMemprofPage" parent="SysprofPage">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<child>
|
||||
<object class="AdwPreferencesPage" id="summary_page">
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Number of Allocations</property>
|
||||
<property name="subtitle" translatable="yes">Total number of allocation and free records</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="num_allocs">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Leaked Allocations</property>
|
||||
<property name="subtitle" translatable="yes">Number of allocations without a free record</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="leaked_allocs">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="activatable">false</property>
|
||||
<property name="title" translatable="yes">Temporary Allocations</property>
|
||||
<property name="subtitle" translatable="yes">Number of allocations freed from similar stack trace</property>
|
||||
<child type="suffix">
|
||||
<object class="GtkLabel" id="temp_allocs_count">
|
||||
<property name="hexpand">true</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="selectable">true</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="title" translatable="yes">Allocations by Size</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="by_size">
|
||||
<style>
|
||||
<class name="boxed-list"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="EggPaned" id="callgraph">
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="EggPaned">
|
||||
<property name="width-request">400</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="functions_view">
|
||||
<property name="fixed-height-mode">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_name_column">
|
||||
<property name="expand">true</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<property name="title" translatable="yes">Functions</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="ellipsize">middle</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_self_column">
|
||||
<property name="visible">false</property>
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<property name="title" translatable="yes">Self</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_total_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<property name="title" translatable="yes">Total</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="callers_view">
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="callers_name_column">
|
||||
<property name="expand">true</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<property name="title" translatable="yes">Callers</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="ellipsize">middle</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="callers_self_column">
|
||||
<property name="visible">false</property>
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<property name="title" translatable="yes">Self</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="callers_total_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<property name="title" translatable="yes">Total</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<child>
|
||||
<object class="GtkTreeView" id="descendants_view">
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="descendants_name_column">
|
||||
<property name="expand">true</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<property name="title" translatable="yes">Descendants</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="descendants_self_column">
|
||||
<property name="visible">false</property>
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<property name="title" translatable="yes">Self</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="descendants_total_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<property name="title" translatable="yes">Total</property>
|
||||
<child>
|
||||
<object class="SysprofCellRendererPercent">
|
||||
<property name="width">65</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="percent">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="function_size_column">
|
||||
<property name="expand">false</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="title" translatable="yes">Size</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="function_size_cell">
|
||||
<property name="xalign">1.0</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwStatusPage" id="loading_state">
|
||||
<property name="icon-name">content-loading-symbolic</property>
|
||||
<property name="title" translatable="yes">Analyzing Memory Allocations</property>
|
||||
<property name="description" translatable="yes">Sysprof is busy analyzing memory allocations.</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwStatusPage" id="empty_state">
|
||||
<property name="icon-name">computer-fail-symbolic</property>
|
||||
<property name="title" translatable="yes">Not Enough Samples</property>
|
||||
<property name="description" translatable="yes">More samples are necessary to display a callgraph.</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
<property name="orientation">horizontal</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCenterBox">
|
||||
<property name="orientation">horizontal</property>
|
||||
<child type="center">
|
||||
<object class="GtkBox">
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<property name="margin-start">6</property>
|
||||
<property name="margin-end">6</property>
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="homogeneous">true</property>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="summary">
|
||||
<property name="label" translatable="yes">Summary</property>
|
||||
<property name="active">false</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="all_allocs">
|
||||
<property name="label" translatable="yes">All Allocations</property>
|
||||
<property name="group">summary</property>
|
||||
<property name="active">true</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="temp_allocs">
|
||||
<property name="label" translatable="yes">Temporary Allocations</property>
|
||||
<property name="active">false</property>
|
||||
<property name="group">summary</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="leaked_allocs_button">
|
||||
<property name="label" translatable="yes">Leaked Allocations</property>
|
||||
<property name="active">false</property>
|
||||
<property name="group">summary</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
@ -1,613 +0,0 @@
|
||||
/* sysprof-memprof-visualizer.c
|
||||
*
|
||||
* Copyright 2020 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"
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-memprof-visualizer"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "rax.h"
|
||||
|
||||
#include "sysprof-memprof-visualizer.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
SysprofCaptureReader *reader;
|
||||
rax *rax;
|
||||
GtkAllocation alloc;
|
||||
gint64 begin_time;
|
||||
gint64 duration;
|
||||
gint64 total_alloc;
|
||||
gint64 max_alloc;
|
||||
GdkRGBA fg;
|
||||
GdkRGBA fg2;
|
||||
guint scale;
|
||||
} DrawContext;
|
||||
|
||||
struct _SysprofMemprofVisualizer
|
||||
{
|
||||
SysprofVisualizer parent_instance;
|
||||
|
||||
SysprofCaptureReader *reader;
|
||||
GCancellable *cancellable;
|
||||
|
||||
cairo_surface_t *surface;
|
||||
gint surface_w;
|
||||
gint surface_h;
|
||||
|
||||
guint queued_draw;
|
||||
|
||||
gint64 begin_time;
|
||||
gint64 duration;
|
||||
|
||||
gint64 cached_total_alloc;
|
||||
gint64 cached_max_alloc;
|
||||
|
||||
guint mode : 1;
|
||||
};
|
||||
|
||||
enum {
|
||||
MODE_ALLOCS,
|
||||
MODE_TOTAL,
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SysprofMemprofVisualizer, sysprof_memprof_visualizer, SYSPROF_TYPE_VISUALIZER)
|
||||
|
||||
static void
|
||||
draw_context_free (DrawContext *draw)
|
||||
{
|
||||
g_clear_pointer (&draw->reader, sysprof_capture_reader_unref);
|
||||
g_clear_pointer (&draw->surface, cairo_surface_destroy);
|
||||
g_clear_pointer (&draw->rax, raxFree);
|
||||
g_slice_free (DrawContext, draw);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_visualizer_set_reader (SysprofVisualizer *visualizer,
|
||||
SysprofCaptureReader *reader)
|
||||
{
|
||||
SysprofMemprofVisualizer *self = (SysprofMemprofVisualizer *)visualizer;
|
||||
|
||||
g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
|
||||
|
||||
if (reader == self->reader)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&self->reader, sysprof_capture_reader_unref);
|
||||
|
||||
self->reader = sysprof_capture_reader_ref (reader);
|
||||
self->begin_time = sysprof_capture_reader_get_start_time (reader);
|
||||
self->duration = sysprof_capture_reader_get_end_time (reader)
|
||||
- sysprof_capture_reader_get_start_time (reader);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
SysprofVisualizer *
|
||||
sysprof_memprof_visualizer_new (gboolean total_allocs)
|
||||
{
|
||||
SysprofMemprofVisualizer *self;
|
||||
|
||||
self = g_object_new (SYSPROF_TYPE_MEMPROF_VISUALIZER,
|
||||
"title", total_allocs ? _("Memory Used") : _("Memory Allocations"),
|
||||
"height-request", 35,
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
if (total_allocs)
|
||||
self->mode = MODE_TOTAL;
|
||||
else
|
||||
self->mode = MODE_ALLOCS;
|
||||
|
||||
return SYSPROF_VISUALIZER (self);
|
||||
}
|
||||
|
||||
static guint64
|
||||
get_max_alloc (SysprofCaptureReader *reader)
|
||||
{
|
||||
SysprofCaptureFrameType type;
|
||||
gint64 ret = 0;
|
||||
|
||||
while (sysprof_capture_reader_peek_type (reader, &type))
|
||||
{
|
||||
const SysprofCaptureAllocation *ev;
|
||||
|
||||
if (type == SYSPROF_CAPTURE_FRAME_ALLOCATION)
|
||||
{
|
||||
if (!(ev = sysprof_capture_reader_read_allocation (reader)))
|
||||
break;
|
||||
|
||||
if (ev->alloc_size > ret)
|
||||
ret = ev->alloc_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sysprof_capture_reader_skip (reader))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sysprof_capture_reader_reset (reader);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static guint64
|
||||
get_total_alloc (SysprofCaptureReader *reader)
|
||||
{
|
||||
SysprofCaptureFrameType type;
|
||||
guint64 total = 0;
|
||||
guint64 max = 0;
|
||||
rax *r;
|
||||
|
||||
r = raxNew ();
|
||||
|
||||
while (sysprof_capture_reader_peek_type (reader, &type))
|
||||
{
|
||||
const SysprofCaptureAllocation *ev;
|
||||
|
||||
if (type == SYSPROF_CAPTURE_FRAME_ALLOCATION)
|
||||
{
|
||||
if (!(ev = sysprof_capture_reader_read_allocation (reader)))
|
||||
break;
|
||||
|
||||
if (ev->alloc_size > 0)
|
||||
{
|
||||
raxInsert (r,
|
||||
(guint8 *)&ev->alloc_addr,
|
||||
sizeof ev->alloc_addr,
|
||||
GSIZE_TO_POINTER (ev->alloc_size),
|
||||
NULL);
|
||||
|
||||
total += ev->alloc_size;
|
||||
|
||||
if (total > max)
|
||||
max = total;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpointer res = raxFind (r, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr);
|
||||
|
||||
if (res != raxNotFound)
|
||||
{
|
||||
total -= GPOINTER_TO_SIZE (res);
|
||||
raxRemove (r,
|
||||
(guint8 *)&ev->alloc_addr,
|
||||
sizeof ev->alloc_addr,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sysprof_capture_reader_skip (reader))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sysprof_capture_reader_reset (reader);
|
||||
raxFree (r);
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_total_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
SysprofCaptureFrameType type;
|
||||
DrawContext *draw = task_data;
|
||||
gint64 total = 0;
|
||||
cairo_t *cr;
|
||||
rax *r;
|
||||
gint x = 0;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (draw != NULL);
|
||||
g_assert (draw->surface != NULL);
|
||||
g_assert (draw->reader != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
if (draw->total_alloc == 0)
|
||||
draw->total_alloc = get_total_alloc (draw->reader);
|
||||
|
||||
r = raxNew ();
|
||||
|
||||
/* To avoid sorting, this code assums that all allocation information
|
||||
* is sorted and in order. Generally this is the case, but a crafted
|
||||
* syscap file could break it on purpose if they tried.
|
||||
*/
|
||||
|
||||
cr = cairo_create (draw->surface);
|
||||
cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
|
||||
while (sysprof_capture_reader_peek_type (draw->reader, &type))
|
||||
{
|
||||
const SysprofCaptureAllocation *ev;
|
||||
gint y;
|
||||
|
||||
if (type == SYSPROF_CAPTURE_FRAME_ALLOCATION)
|
||||
{
|
||||
if (!(ev = sysprof_capture_reader_read_allocation (draw->reader)))
|
||||
break;
|
||||
|
||||
if (ev->alloc_size > 0)
|
||||
{
|
||||
raxInsert (r,
|
||||
(guint8 *)&ev->alloc_addr,
|
||||
sizeof ev->alloc_addr,
|
||||
GSIZE_TO_POINTER (ev->alloc_size),
|
||||
NULL);
|
||||
|
||||
total += ev->alloc_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpointer res = raxFind (r, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr);
|
||||
|
||||
if (res != raxNotFound)
|
||||
{
|
||||
total -= GPOINTER_TO_SIZE (res);
|
||||
raxRemove (r,
|
||||
(guint8 *)&ev->alloc_addr,
|
||||
sizeof ev->alloc_addr,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sysprof_capture_reader_skip (draw->reader))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
x = (ev->frame.time - draw->begin_time) / (gdouble)draw->duration * draw->alloc.width;
|
||||
y = draw->alloc.height - ((gdouble)total / (gdouble)draw->total_alloc * (gdouble)draw->alloc.height);
|
||||
|
||||
cairo_rectangle (cr, x, y, 1, 1);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
|
||||
raxFree (r);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_alloc_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
static const gdouble dashes[] = { 1.0, 2.0 };
|
||||
DrawContext *draw = task_data;
|
||||
SysprofCaptureFrameType type;
|
||||
GdkRGBA *last;
|
||||
GdkRGBA mid;
|
||||
cairo_t *cr;
|
||||
guint counter = 0;
|
||||
gint midpt;
|
||||
gdouble log_max;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (draw != NULL);
|
||||
g_assert (draw->surface != NULL);
|
||||
g_assert (draw->reader != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
if (draw->max_alloc == 0)
|
||||
draw->max_alloc = get_max_alloc (draw->reader);
|
||||
|
||||
log_max = log10 (draw->max_alloc);
|
||||
midpt = draw->alloc.height / 2;
|
||||
|
||||
cr = cairo_create (draw->surface);
|
||||
|
||||
/* Draw mid-point line */
|
||||
mid = draw->fg;
|
||||
mid.alpha *= 0.4;
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
gdk_cairo_set_source_rgba (cr, &mid);
|
||||
cairo_move_to (cr, 0, midpt);
|
||||
cairo_line_to (cr, draw->alloc.width, midpt);
|
||||
cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes), 0);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
|
||||
gdk_cairo_set_source_rgba (cr, &draw->fg);
|
||||
last = &draw->fg;
|
||||
|
||||
/* Now draw data points */
|
||||
while (sysprof_capture_reader_peek_type (draw->reader, &type))
|
||||
{
|
||||
const SysprofCaptureAllocation *ev;
|
||||
gint64 size;
|
||||
gdouble l;
|
||||
gint x;
|
||||
gint y;
|
||||
|
||||
/* Cancellation check every 1000 frames */
|
||||
if G_UNLIKELY (++counter == 1000)
|
||||
{
|
||||
if (g_task_return_error_if_cancelled (task))
|
||||
{
|
||||
cairo_destroy (cr);
|
||||
return;
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
/* We only care about memory frames here */
|
||||
if (type != SYSPROF_CAPTURE_FRAME_ALLOCATION)
|
||||
{
|
||||
if (!sysprof_capture_reader_skip (draw->reader))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ev = sysprof_capture_reader_read_allocation (draw->reader)))
|
||||
break;
|
||||
|
||||
if (ev->alloc_size > 0)
|
||||
{
|
||||
size = ev->alloc_size;
|
||||
raxInsert (draw->rax, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr, GSIZE_TO_POINTER (size), NULL);
|
||||
|
||||
if (last != &draw->fg)
|
||||
{
|
||||
gdk_cairo_set_source_rgba (cr, &draw->fg);
|
||||
last = &draw->fg;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size = GPOINTER_TO_SIZE (raxFind (draw->rax, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr));
|
||||
if (size)
|
||||
raxRemove (draw->rax, (guint8 *)&ev->alloc_addr, sizeof ev->alloc_addr, NULL);
|
||||
|
||||
if (last != &draw->fg2)
|
||||
{
|
||||
gdk_cairo_set_source_rgba (cr, &draw->fg2);
|
||||
last = &draw->fg2;
|
||||
}
|
||||
}
|
||||
|
||||
l = log10 (size);
|
||||
|
||||
x = (ev->frame.time - draw->begin_time) / (gdouble)draw->duration * draw->alloc.width;
|
||||
|
||||
if (ev->alloc_size > 0)
|
||||
y = midpt - ((l / log_max) * midpt);
|
||||
else
|
||||
y = midpt + ((l / log_max) * midpt);
|
||||
|
||||
/* Fill immediately instead of batching draws so that
|
||||
* we don't take a lot of memory to hold on to the
|
||||
* path while drawing.
|
||||
*/
|
||||
cairo_rectangle (cr, x, y, 1, 1);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_finished (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr(SysprofMemprofVisualizer) self = user_data;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
g_assert (object == NULL);
|
||||
g_assert (G_IS_TASK (result));
|
||||
g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
|
||||
|
||||
if (g_task_propagate_boolean (G_TASK (result), &error))
|
||||
{
|
||||
DrawContext *draw = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
g_clear_pointer (&self->surface, cairo_surface_destroy);
|
||||
|
||||
self->surface = g_steal_pointer (&draw->surface);
|
||||
self->surface_w = draw->alloc.width;
|
||||
self->surface_h = draw->alloc.height;
|
||||
self->cached_max_alloc = draw->max_alloc;
|
||||
self->cached_total_alloc = draw->total_alloc;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_memprof_visualizer_begin_draw (SysprofMemprofVisualizer *self)
|
||||
{
|
||||
g_autoptr(GTask) task = NULL;
|
||||
GtkAllocation alloc;
|
||||
DrawContext *draw;
|
||||
|
||||
g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
|
||||
|
||||
self->queued_draw = 0;
|
||||
|
||||
/* Make sure we even need to draw */
|
||||
gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
|
||||
if (self->reader == NULL ||
|
||||
!gtk_widget_get_visible (GTK_WIDGET (self)) ||
|
||||
!gtk_widget_get_mapped (GTK_WIDGET (self)) ||
|
||||
alloc.width == 0 || alloc.height == 0)
|
||||
return G_SOURCE_REMOVE;
|
||||
|
||||
/* Some GPUs (Intel) cannot deal with graphics textures larger than
|
||||
* 8000x8000. So here we are going to cheat a bit and just use that as our
|
||||
* max, and scale when drawing. The biggest issue here is that long term we
|
||||
* need a tiling solution that lets us render lots of tiles and then draw
|
||||
* them as necessary.
|
||||
*/
|
||||
if (alloc.width > 8000)
|
||||
alloc.width = 8000;
|
||||
|
||||
draw = g_slice_new0 (DrawContext);
|
||||
draw->rax = raxNew ();
|
||||
draw->alloc.width = alloc.width;
|
||||
draw->alloc.height = alloc.height;
|
||||
draw->reader = sysprof_capture_reader_copy (self->reader);
|
||||
draw->begin_time = self->begin_time;
|
||||
draw->duration = self->duration;
|
||||
draw->scale = gtk_widget_get_scale_factor (GTK_WIDGET (self));
|
||||
draw->max_alloc = self->cached_max_alloc;
|
||||
draw->total_alloc = self->cached_total_alloc;
|
||||
|
||||
gdk_rgba_parse (&draw->fg, "rgba(246,97,81,1)");
|
||||
gdk_rgba_parse (&draw->fg2, "rgba(245,194,17,1)");
|
||||
|
||||
draw->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
alloc.width * draw->scale,
|
||||
alloc.height * draw->scale);
|
||||
cairo_surface_set_device_scale (draw->surface, draw->scale, draw->scale);
|
||||
|
||||
g_cancellable_cancel (self->cancellable);
|
||||
g_clear_object (&self->cancellable);
|
||||
self->cancellable = g_cancellable_new ();
|
||||
|
||||
task = g_task_new (NULL, self->cancellable, draw_finished, g_object_ref (self));
|
||||
g_task_set_source_tag (task, sysprof_memprof_visualizer_begin_draw);
|
||||
g_task_set_task_data (task, g_steal_pointer (&draw), (GDestroyNotify)draw_context_free);
|
||||
|
||||
if (self->mode == MODE_ALLOCS)
|
||||
g_task_run_in_thread (task, draw_alloc_worker);
|
||||
else
|
||||
g_task_run_in_thread (task, draw_total_worker);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_visualizer_queue_redraw (SysprofMemprofVisualizer *self)
|
||||
{
|
||||
g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
|
||||
|
||||
if (self->queued_draw == 0)
|
||||
self->queued_draw = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
|
||||
(GSourceFunc) sysprof_memprof_visualizer_begin_draw,
|
||||
g_object_ref (self),
|
||||
g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_visualizer_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
sysprof_memprof_visualizer_queue_redraw (SYSPROF_MEMPROF_VISUALIZER (widget));
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_visualizer_dispose (GObject *object)
|
||||
{
|
||||
SysprofMemprofVisualizer *self = (SysprofMemprofVisualizer *)object;
|
||||
|
||||
g_clear_pointer (&self->reader, sysprof_capture_reader_unref);
|
||||
g_clear_pointer (&self->surface, cairo_surface_destroy);
|
||||
g_clear_handle_id (&self->queued_draw, g_source_remove);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_memprof_visualizer_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_visualizer_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
SysprofMemprofVisualizer *self = (SysprofMemprofVisualizer *)widget;
|
||||
|
||||
g_assert (SYSPROF_IS_MEMPROF_VISUALIZER (self));
|
||||
g_assert (GTK_IS_SNAPSHOT (snapshot));
|
||||
|
||||
GTK_WIDGET_CLASS (sysprof_memprof_visualizer_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
if (self->surface != NULL)
|
||||
{
|
||||
cairo_t *cr;
|
||||
GtkAllocation alloc;
|
||||
|
||||
gtk_widget_get_allocation (widget, &alloc);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, alloc.width, alloc.height));
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_rectangle (cr, 0, 0, alloc.width, alloc.height);
|
||||
|
||||
/* We might be drawing an updated image in the background, and this
|
||||
* will take our current surface (which is the wrong size) and draw
|
||||
* it stretched to fit the allocation. That gives us *something* that
|
||||
* represents the end result even if it is a bit blurry in the mean
|
||||
* time. Allocators take a while to render anyway.
|
||||
*/
|
||||
if (self->surface_w != alloc.width || self->surface_h != alloc.height)
|
||||
{
|
||||
cairo_scale (cr,
|
||||
(gdouble)alloc.width / (gdouble)self->surface_w,
|
||||
(gdouble)alloc.height / (gdouble)self->surface_h);
|
||||
}
|
||||
|
||||
cairo_set_source_surface (cr, self->surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_visualizer_class_init (SysprofMemprofVisualizerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
SysprofVisualizerClass *visualizer_class = SYSPROF_VISUALIZER_CLASS (klass);
|
||||
|
||||
object_class->dispose = sysprof_memprof_visualizer_dispose;
|
||||
|
||||
widget_class->snapshot = sysprof_memprof_visualizer_snapshot;
|
||||
widget_class->size_allocate = sysprof_memprof_visualizer_size_allocate;
|
||||
|
||||
visualizer_class->set_reader = sysprof_memprof_visualizer_set_reader;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_memprof_visualizer_init (SysprofMemprofVisualizer *self)
|
||||
{
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-memprof-visualizer.h
|
||||
*
|
||||
* Copyright 2020 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-visualizer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_MEMPROF_VISUALIZER (sysprof_memprof_visualizer_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofMemprofVisualizer, sysprof_memprof_visualizer, SYSPROF, MEMPROF_VISUALIZER, SysprofVisualizer)
|
||||
|
||||
SysprofVisualizer *sysprof_memprof_visualizer_new (gboolean total_allocs);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,497 +0,0 @@
|
||||
/* sysprof-model-filter.c
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* 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 "sysprof-model-filter.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSequenceIter *child_iter;
|
||||
GSequenceIter *filter_iter;
|
||||
} SysprofModelFilterItem;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* The list we are filtering */
|
||||
GListModel *child_model;
|
||||
|
||||
/*
|
||||
* Both sequences point to the same SysprofModelFilterItem which
|
||||
* contains cross-referencing stable GSequenceIter pointers.
|
||||
* The child_seq is considered the "owner" and used to release
|
||||
* allocated resources.
|
||||
*/
|
||||
GSequence *child_seq;
|
||||
GSequence *filter_seq;
|
||||
|
||||
/*
|
||||
* Typical set of callback/closure/free function pointers and data.
|
||||
* Called for child items to determine visibility state.
|
||||
*/
|
||||
SysprofModelFilterFunc filter_func;
|
||||
gpointer filter_func_data;
|
||||
GDestroyNotify filter_func_data_destroy;
|
||||
|
||||
/*
|
||||
* If set, we will not emit items-changed. This is useful during
|
||||
* invalidation so that we can do a single emission for all items
|
||||
* that have changed.
|
||||
*/
|
||||
guint supress_items_changed : 1;
|
||||
} SysprofModelFilterPrivate;
|
||||
|
||||
static void list_model_iface_init (GListModelInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (SysprofModelFilter, sysprof_model_filter, G_TYPE_OBJECT, 0,
|
||||
G_ADD_PRIVATE (SysprofModelFilter)
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
|
||||
list_model_iface_init))
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_CHILD_MODEL,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
static guint signal_id;
|
||||
|
||||
static void
|
||||
sysprof_model_filter_item_free (gpointer data)
|
||||
{
|
||||
SysprofModelFilterItem *item = data;
|
||||
|
||||
g_clear_pointer (&item->filter_iter, g_sequence_remove);
|
||||
item->child_iter = NULL;
|
||||
g_slice_free (SysprofModelFilterItem, item);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_model_filter_default_filter_func (GObject *item,
|
||||
gpointer user_data)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locates the next item in the filter sequence starting from
|
||||
* the cross-reference found at @iter. If none are found, the
|
||||
* end_iter for the filter sequence is returned.
|
||||
*
|
||||
* This returns an iter in the filter_sequence, not the child_seq.
|
||||
*
|
||||
* Returns: a #GSequenceIter from the filter sequence.
|
||||
*/
|
||||
static GSequenceIter *
|
||||
find_next_visible_filter_iter (SysprofModelFilter *self,
|
||||
GSequenceIter *iter)
|
||||
{
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_MODEL_FILTER (self));
|
||||
g_assert (iter != NULL);
|
||||
|
||||
for (; !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter))
|
||||
{
|
||||
SysprofModelFilterItem *item = g_sequence_get (iter);
|
||||
|
||||
g_assert (item->child_iter == iter);
|
||||
g_assert (item->filter_iter == NULL ||
|
||||
g_sequence_iter_get_sequence (item->filter_iter) == priv->filter_seq);
|
||||
|
||||
if (item->filter_iter != NULL)
|
||||
return item->filter_iter;
|
||||
}
|
||||
|
||||
return g_sequence_get_end_iter (priv->filter_seq);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_model_filter_child_model_items_changed (SysprofModelFilter *self,
|
||||
guint position,
|
||||
guint n_removed,
|
||||
guint n_added,
|
||||
GListModel *child_model)
|
||||
{
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
gboolean unblocked;
|
||||
|
||||
g_assert (SYSPROF_IS_MODEL_FILTER (self));
|
||||
g_assert (G_IS_LIST_MODEL (child_model));
|
||||
g_assert (priv->child_model == child_model);
|
||||
g_assert (position <= (guint)g_sequence_get_length (priv->child_seq));
|
||||
g_assert ((g_sequence_get_length (priv->child_seq) - n_removed + n_added) ==
|
||||
g_list_model_get_n_items (child_model));
|
||||
|
||||
unblocked = !priv->supress_items_changed;
|
||||
|
||||
if (n_removed > 0)
|
||||
{
|
||||
GSequenceIter *iter = g_sequence_get_iter_at_pos (priv->child_seq, position);
|
||||
gint first_position = -1;
|
||||
guint count = 0;
|
||||
|
||||
g_assert (!g_sequence_iter_is_end (iter));
|
||||
|
||||
/* Small shortcut when all items are removed */
|
||||
if (n_removed == (guint)g_sequence_get_length (priv->child_seq))
|
||||
{
|
||||
g_sequence_remove_range (g_sequence_get_begin_iter (priv->child_seq),
|
||||
g_sequence_get_end_iter (priv->child_seq));
|
||||
g_assert (g_sequence_is_empty (priv->child_seq));
|
||||
g_assert (g_sequence_is_empty (priv->filter_seq));
|
||||
goto add_new_items;
|
||||
}
|
||||
|
||||
for (guint i = 0; i < n_removed; i++)
|
||||
{
|
||||
GSequenceIter *to_remove = iter;
|
||||
SysprofModelFilterItem *item = g_sequence_get (iter);
|
||||
|
||||
g_assert (item != NULL);
|
||||
g_assert (item->child_iter == iter);
|
||||
g_assert (item->filter_iter == NULL ||
|
||||
g_sequence_iter_get_sequence (item->filter_iter) == priv->filter_seq);
|
||||
|
||||
/* If this is visible, we need to notify about removal */
|
||||
if (unblocked && item->filter_iter != NULL)
|
||||
{
|
||||
if (first_position < 0)
|
||||
first_position = g_sequence_iter_get_position (item->filter_iter);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Fetch the next while the iter is still valid */
|
||||
iter = g_sequence_iter_next (iter);
|
||||
|
||||
/* Cascades into also removing from filter_seq. */
|
||||
g_sequence_remove (to_remove);
|
||||
}
|
||||
|
||||
if (unblocked && first_position >= 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), first_position, count, 0);
|
||||
}
|
||||
|
||||
add_new_items:
|
||||
|
||||
if (n_added > 0)
|
||||
{
|
||||
GSequenceIter *iter = g_sequence_get_iter_at_pos (priv->child_seq, position);
|
||||
GSequenceIter *filter_iter = find_next_visible_filter_iter (self, iter);
|
||||
guint filter_position = g_sequence_iter_get_position (filter_iter);
|
||||
guint count = 0;
|
||||
|
||||
/* Walk backwards to insert items into the filter list so that
|
||||
* we can use the same filter_position for each items-changed
|
||||
* signal emission.
|
||||
*/
|
||||
for (guint i = position + n_added; i > position; i--)
|
||||
{
|
||||
g_autoptr(GObject) instance = NULL;
|
||||
SysprofModelFilterItem *item;
|
||||
|
||||
item = g_slice_new0 (SysprofModelFilterItem);
|
||||
item->filter_iter = NULL;
|
||||
item->child_iter = g_sequence_insert_before (iter, item);
|
||||
|
||||
instance = g_list_model_get_item (child_model, i - 1);
|
||||
g_assert (G_IS_OBJECT (instance));
|
||||
|
||||
/* Check if this item is visible */
|
||||
if (priv->filter_func (instance, priv->filter_func_data))
|
||||
{
|
||||
item->filter_iter = g_sequence_insert_before (filter_iter, item);
|
||||
|
||||
/* Use this in the future for relative positioning */
|
||||
filter_iter = item->filter_iter;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Insert next item before this */
|
||||
iter = item->child_iter;
|
||||
}
|
||||
|
||||
if (unblocked && count)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), filter_position, 0, count);
|
||||
}
|
||||
|
||||
g_assert ((guint)g_sequence_get_length (priv->child_seq) ==
|
||||
g_list_model_get_n_items (child_model));
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_model_filter_finalize (GObject *object)
|
||||
{
|
||||
SysprofModelFilter *self = (SysprofModelFilter *)object;
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->child_seq, g_sequence_free);
|
||||
g_clear_pointer (&priv->filter_seq, g_sequence_free);
|
||||
|
||||
if (priv->filter_func_data_destroy)
|
||||
{
|
||||
g_clear_pointer (&priv->filter_func_data, priv->filter_func_data_destroy);
|
||||
priv->filter_func_data_destroy = NULL;
|
||||
}
|
||||
|
||||
g_clear_object (&priv->child_model);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_model_filter_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_model_filter_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofModelFilter *self = SYSPROF_MODEL_FILTER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CHILD_MODEL:
|
||||
g_value_set_object (value, sysprof_model_filter_get_child_model (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_model_filter_class_init (SysprofModelFilterClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_model_filter_finalize;
|
||||
object_class->get_property = sysprof_model_filter_get_property;
|
||||
|
||||
properties [PROP_CHILD_MODEL] =
|
||||
g_param_spec_object ("child-model",
|
||||
"Child Model",
|
||||
"The child model being filtered.",
|
||||
G_TYPE_LIST_MODEL,
|
||||
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
signal_id = g_signal_lookup ("items-changed", SYSPROF_TYPE_MODEL_FILTER);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_model_filter_init (SysprofModelFilter *self)
|
||||
{
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
|
||||
priv->filter_func = sysprof_model_filter_default_filter_func;
|
||||
priv->child_seq = g_sequence_new (sysprof_model_filter_item_free);
|
||||
priv->filter_seq = g_sequence_new (NULL);
|
||||
}
|
||||
|
||||
static GType
|
||||
sysprof_model_filter_get_item_type (GListModel *model)
|
||||
{
|
||||
SysprofModelFilter *self = (SysprofModelFilter *)model;
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_MODEL_FILTER (self));
|
||||
|
||||
return g_list_model_get_item_type (priv->child_model);
|
||||
}
|
||||
|
||||
static guint
|
||||
sysprof_model_filter_get_n_items (GListModel *model)
|
||||
{
|
||||
SysprofModelFilter *self = (SysprofModelFilter *)model;
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
|
||||
g_assert (SYSPROF_IS_MODEL_FILTER (self));
|
||||
g_assert (priv->filter_seq != NULL);
|
||||
|
||||
return g_sequence_get_length (priv->filter_seq);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
sysprof_model_filter_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
SysprofModelFilter *self = (SysprofModelFilter *)model;
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
SysprofModelFilterItem *item;
|
||||
GSequenceIter *iter;
|
||||
guint child_position;
|
||||
|
||||
g_assert (SYSPROF_IS_MODEL_FILTER (self));
|
||||
g_assert (position < (guint)g_sequence_get_length (priv->filter_seq));
|
||||
|
||||
iter = g_sequence_get_iter_at_pos (priv->filter_seq, position);
|
||||
g_assert (!g_sequence_iter_is_end (iter));
|
||||
|
||||
item = g_sequence_get (iter);
|
||||
g_assert (item != NULL);
|
||||
g_assert (item->filter_iter == iter);
|
||||
g_assert (item->child_iter != NULL);
|
||||
g_assert (g_sequence_iter_get_sequence (item->child_iter) == priv->child_seq);
|
||||
|
||||
child_position = g_sequence_iter_get_position (item->child_iter);
|
||||
|
||||
return g_list_model_get_item (priv->child_model, child_position);
|
||||
}
|
||||
|
||||
static void
|
||||
list_model_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = sysprof_model_filter_get_item_type;
|
||||
iface->get_n_items = sysprof_model_filter_get_n_items;
|
||||
iface->get_item = sysprof_model_filter_get_item;
|
||||
}
|
||||
|
||||
SysprofModelFilter *
|
||||
sysprof_model_filter_new (GListModel *child_model)
|
||||
{
|
||||
SysprofModelFilter *ret;
|
||||
SysprofModelFilterPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (child_model), NULL);
|
||||
|
||||
ret = g_object_new (SYSPROF_TYPE_MODEL_FILTER, NULL);
|
||||
priv = sysprof_model_filter_get_instance_private (ret);
|
||||
priv->child_model = g_object_ref (child_model);
|
||||
|
||||
g_signal_connect_object (child_model,
|
||||
"items-changed",
|
||||
G_CALLBACK (sysprof_model_filter_child_model_items_changed),
|
||||
ret,
|
||||
G_CONNECT_SWAPPED);
|
||||
|
||||
sysprof_model_filter_invalidate (ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_model_filter_get_child_model:
|
||||
* @self: A #SysprofModelFilter
|
||||
*
|
||||
* Gets the child model that is being filtered.
|
||||
*
|
||||
* Returns: (transfer none): A #GListModel.
|
||||
*/
|
||||
GListModel *
|
||||
sysprof_model_filter_get_child_model (SysprofModelFilter *self)
|
||||
{
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (SYSPROF_IS_MODEL_FILTER (self), NULL);
|
||||
|
||||
return priv->child_model;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_model_filter_invalidate (SysprofModelFilter *self)
|
||||
{
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
guint n_items;
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_MODEL_FILTER (self));
|
||||
|
||||
/* We block emission while in invalidate so that we can use
|
||||
* a single larger items-changed rather lots of small emissions.
|
||||
*/
|
||||
priv->supress_items_changed = TRUE;
|
||||
|
||||
/* First determine how many items we need to synthesize as a removal */
|
||||
n_items = g_sequence_get_length (priv->filter_seq);
|
||||
|
||||
/*
|
||||
* If we have a child store, we want to rebuild our list of items
|
||||
* from scratch, so just remove everything.
|
||||
*/
|
||||
if (!g_sequence_is_empty (priv->child_seq))
|
||||
g_sequence_remove_range (g_sequence_get_begin_iter (priv->child_seq),
|
||||
g_sequence_get_end_iter (priv->child_seq));
|
||||
|
||||
g_assert (g_sequence_is_empty (priv->child_seq));
|
||||
g_assert (g_sequence_is_empty (priv->filter_seq));
|
||||
g_assert (!priv->child_model || G_IS_LIST_MODEL (priv->child_model));
|
||||
|
||||
/*
|
||||
* Now add the new items by synthesizing the addition of all the
|
||||
* itmes in the list.
|
||||
*/
|
||||
if (priv->child_model != NULL)
|
||||
{
|
||||
guint child_n_items;
|
||||
|
||||
/*
|
||||
* Now add all the items as one shot to our list so that
|
||||
* we get populate our sequence and filter sequence.
|
||||
*/
|
||||
child_n_items = g_list_model_get_n_items (priv->child_model);
|
||||
sysprof_model_filter_child_model_items_changed (self, 0, 0, child_n_items, priv->child_model);
|
||||
|
||||
g_assert ((guint)g_sequence_get_length (priv->child_seq) == child_n_items);
|
||||
g_assert ((guint)g_sequence_get_length (priv->filter_seq) <= child_n_items);
|
||||
}
|
||||
|
||||
priv->supress_items_changed = FALSE;
|
||||
|
||||
/* Now that we've updated our sequences, notify of all the changes
|
||||
* as a single series of updates to the consumers.
|
||||
*/
|
||||
if (n_items > 0 || !g_sequence_is_empty (priv->filter_seq))
|
||||
g_list_model_items_changed (G_LIST_MODEL (self),
|
||||
0,
|
||||
n_items,
|
||||
g_sequence_get_length (priv->filter_seq));
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_model_filter_set_filter_func (SysprofModelFilter *self,
|
||||
SysprofModelFilterFunc filter_func,
|
||||
gpointer filter_func_data,
|
||||
GDestroyNotify filter_func_data_destroy)
|
||||
{
|
||||
SysprofModelFilterPrivate *priv = sysprof_model_filter_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (SYSPROF_IS_MODEL_FILTER (self));
|
||||
g_return_if_fail (filter_func || (!filter_func_data && !filter_func_data_destroy));
|
||||
|
||||
if (priv->filter_func_data_destroy != NULL)
|
||||
g_clear_pointer (&priv->filter_func_data, priv->filter_func_data_destroy);
|
||||
|
||||
if (filter_func != NULL)
|
||||
{
|
||||
priv->filter_func = filter_func;
|
||||
priv->filter_func_data = filter_func_data;
|
||||
priv->filter_func_data_destroy = filter_func_data_destroy;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->filter_func = sysprof_model_filter_default_filter_func;
|
||||
priv->filter_func_data = NULL;
|
||||
priv->filter_func_data_destroy = NULL;
|
||||
}
|
||||
|
||||
sysprof_model_filter_invalidate (self);
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
/* sysprof-model-filter.h
|
||||
*
|
||||
* Copyright 2016-2019 Christian Hergert <christian@hergert.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (SYSPROF_UI_INSIDE) && !defined (SYSPROF_UI_COMPILATION)
|
||||
# error "Only <sysprof-ui.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "sysprof-version-macros.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_MODEL_FILTER (sysprof_model_filter_get_type())
|
||||
|
||||
typedef gboolean (*SysprofModelFilterFunc) (GObject *object,
|
||||
gpointer user_data);
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
G_DECLARE_DERIVABLE_TYPE (SysprofModelFilter, sysprof_model_filter, SYSPROF, MODEL_FILTER, GObject)
|
||||
|
||||
struct _SysprofModelFilterClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
gpointer padding[8];
|
||||
};
|
||||
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
SysprofModelFilter *sysprof_model_filter_new (GListModel *child_model);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
GListModel *sysprof_model_filter_get_child_model (SysprofModelFilter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_model_filter_invalidate (SysprofModelFilter *self);
|
||||
SYSPROF_AVAILABLE_IN_ALL
|
||||
void sysprof_model_filter_set_filter_func (SysprofModelFilter *self,
|
||||
SysprofModelFilterFunc filter_func,
|
||||
gpointer filter_func_data,
|
||||
GDestroyNotify filter_func_data_destroy);
|
||||
|
||||
G_END_DECLS
|
||||
@ -1,266 +0,0 @@
|
||||
/* sysprof-netdev-aid.c
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "sysprof-netdev-aid"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "sysprof-color-cycle.h"
|
||||
#include "sysprof-duplex-visualizer.h"
|
||||
#include "sysprof-netdev-aid.h"
|
||||
|
||||
struct _SysprofNetdevAid
|
||||
{
|
||||
SysprofAid parent_instance;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SysprofCaptureCursor *cursor;
|
||||
SysprofDisplay *display;
|
||||
} Present;
|
||||
|
||||
G_DEFINE_TYPE (SysprofNetdevAid, sysprof_netdev_aid, SYSPROF_TYPE_AID)
|
||||
|
||||
static void
|
||||
present_free (gpointer data)
|
||||
{
|
||||
Present *p = data;
|
||||
|
||||
g_clear_pointer (&p->cursor, sysprof_capture_cursor_unref);
|
||||
g_clear_object (&p->display);
|
||||
g_slice_free (Present, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* sysprof_netdev_aid_new:
|
||||
*
|
||||
* Create a new #SysprofNetdevAid.
|
||||
*
|
||||
* Returns: (transfer full): a newly created #SysprofNetdevAid
|
||||
*
|
||||
* Since: 3.34
|
||||
*/
|
||||
SysprofAid *
|
||||
sysprof_netdev_aid_new (void)
|
||||
{
|
||||
return g_object_new (SYSPROF_TYPE_NETDEV_AID, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_netdev_aid_prepare (SysprofAid *self,
|
||||
SysprofProfiler *profiler)
|
||||
{
|
||||
g_autoptr(SysprofSource) source = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_NETDEV_AID (self));
|
||||
g_assert (SYSPROF_IS_PROFILER (profiler));
|
||||
|
||||
source = sysprof_netdev_source_new ();
|
||||
sysprof_profiler_add_source (profiler, source);
|
||||
}
|
||||
|
||||
static bool
|
||||
collect_netdev_counters (const SysprofCaptureFrame *frame,
|
||||
gpointer user_data)
|
||||
{
|
||||
SysprofCaptureCounterDefine *def = (SysprofCaptureCounterDefine *)frame;
|
||||
GArray *counters = user_data;
|
||||
|
||||
g_assert (frame != NULL);
|
||||
g_assert (frame->type == SYSPROF_CAPTURE_FRAME_CTRDEF);
|
||||
g_assert (counters != NULL);
|
||||
|
||||
for (guint i = 0; i < def->n_counters; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *counter = &def->counters[i];
|
||||
|
||||
if (strcmp (counter->category, "Network") == 0 &&
|
||||
(g_str_has_prefix (counter->name, "RX Bytes") ||
|
||||
g_str_has_prefix (counter->name, "TX Bytes")))
|
||||
g_array_append_vals (counters, counter, 1);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_netdev_aid_present_worker (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
Present *present = task_data;
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
|
||||
g_assert (G_IS_TASK (task));
|
||||
g_assert (SYSPROF_IS_NETDEV_AID (source_object));
|
||||
g_assert (present != NULL);
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
counters = g_array_new (FALSE, FALSE, sizeof (SysprofCaptureCounter));
|
||||
sysprof_capture_cursor_foreach (present->cursor, collect_netdev_counters, counters);
|
||||
g_task_return_pointer (task,
|
||||
g_steal_pointer (&counters),
|
||||
(GDestroyNotify) g_array_unref);
|
||||
}
|
||||
|
||||
static guint
|
||||
find_other_id (GArray *counters,
|
||||
const gchar *rx)
|
||||
{
|
||||
g_autofree gchar *other = NULL;
|
||||
|
||||
g_assert (counters);
|
||||
g_assert (rx != NULL);
|
||||
|
||||
other = g_strdup (rx);
|
||||
other[0] = 'T';
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *c = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_str_equal (c->name, other))
|
||||
return c->id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_netdev_aid_present_async (SysprofAid *aid,
|
||||
SysprofCaptureReader *reader,
|
||||
SysprofDisplay *display,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
static const SysprofCaptureFrameType types[] = { SYSPROF_CAPTURE_FRAME_CTRDEF };
|
||||
g_autoptr(SysprofCaptureCondition) condition = NULL;
|
||||
g_autoptr(SysprofCaptureCursor) cursor = NULL;
|
||||
g_autoptr(GTask) task = NULL;
|
||||
Present present;
|
||||
|
||||
g_assert (SYSPROF_IS_NETDEV_AID (aid));
|
||||
g_assert (reader != NULL);
|
||||
g_assert (SYSPROF_IS_DISPLAY (display));
|
||||
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
condition = sysprof_capture_condition_new_where_type_in (1, types);
|
||||
cursor = sysprof_capture_cursor_new (reader);
|
||||
sysprof_capture_cursor_add_condition (cursor, g_steal_pointer (&condition));
|
||||
|
||||
present.cursor = g_steal_pointer (&cursor);
|
||||
present.display = g_object_ref (display);
|
||||
|
||||
task = g_task_new (aid, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, sysprof_netdev_aid_present_async);
|
||||
g_task_set_task_data (task,
|
||||
g_slice_dup (Present, &present),
|
||||
present_free);
|
||||
g_task_run_in_thread (task, sysprof_netdev_aid_present_worker);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
sysprof_netdev_aid_present_finish (SysprofAid *aid,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GArray) counters = NULL;
|
||||
Present *present;
|
||||
|
||||
g_assert (SYSPROF_IS_AID (aid));
|
||||
g_assert (G_IS_TASK (result));
|
||||
|
||||
present = g_task_get_task_data (G_TASK (result));
|
||||
|
||||
if ((counters = g_task_propagate_pointer (G_TASK (result), error)))
|
||||
{
|
||||
g_autoptr(SysprofColorCycle) cycle = sysprof_color_cycle_new ();
|
||||
SysprofVisualizerGroup *group;
|
||||
|
||||
group = g_object_new (SYSPROF_TYPE_VISUALIZER_GROUP,
|
||||
"can-focus", TRUE,
|
||||
"title", _("Network"),
|
||||
"visible", TRUE,
|
||||
NULL);
|
||||
|
||||
for (guint i = 0; i < counters->len; i++)
|
||||
{
|
||||
const SysprofCaptureCounter *ctr = &g_array_index (counters, SysprofCaptureCounter, i);
|
||||
|
||||
if (g_str_has_prefix (ctr->name, "RX Bytes"))
|
||||
{
|
||||
g_autofree gchar *title = NULL;
|
||||
gboolean is_combined;
|
||||
GtkWidget *row;
|
||||
GdkRGBA rgba;
|
||||
guint other_id;
|
||||
|
||||
if (!(other_id = find_other_id (counters, ctr->name)))
|
||||
continue;
|
||||
|
||||
is_combined = g_str_equal (ctr->description, "Combined");
|
||||
|
||||
if (is_combined)
|
||||
title = g_strdup ("Network Bytes (All)");
|
||||
else
|
||||
title = g_strdup_printf ("Network Bytes%s", ctr->name + strlen ("RX Bytes"));
|
||||
|
||||
row = g_object_new (SYSPROF_TYPE_DUPLEX_VISUALIZER,
|
||||
"title", title,
|
||||
"height-request", 35,
|
||||
"visible", is_combined,
|
||||
NULL);
|
||||
sysprof_color_cycle_next (cycle, &rgba);
|
||||
sysprof_duplex_visualizer_set_counters (SYSPROF_DUPLEX_VISUALIZER (row), ctr->id, other_id);
|
||||
sysprof_duplex_visualizer_set_colors (SYSPROF_DUPLEX_VISUALIZER (row), &rgba, &rgba);
|
||||
sysprof_visualizer_group_insert (group, SYSPROF_VISUALIZER (row), is_combined ? 0 : -1, !is_combined);
|
||||
}
|
||||
}
|
||||
|
||||
if (counters->len > 0)
|
||||
sysprof_display_add_group (present->display, group);
|
||||
else
|
||||
g_object_unref (g_object_ref_sink (group));
|
||||
}
|
||||
|
||||
return counters != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_netdev_aid_class_init (SysprofNetdevAidClass *klass)
|
||||
{
|
||||
SysprofAidClass *aid_class = SYSPROF_AID_CLASS (klass);
|
||||
|
||||
aid_class->prepare = sysprof_netdev_aid_prepare;
|
||||
aid_class->present_async = sysprof_netdev_aid_present_async;
|
||||
aid_class->present_finish = sysprof_netdev_aid_present_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_netdev_aid_init (SysprofNetdevAid *self)
|
||||
{
|
||||
sysprof_aid_set_display_name (SYSPROF_AID (self), _("Network"));
|
||||
sysprof_aid_set_icon_name (SYSPROF_AID (self), "preferences-system-network-symbolic");
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
/* sysprof-netdev-aid.h
|
||||
*
|
||||
* Copyright 2019 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sysprof-aid.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_NETDEV_AID (sysprof_netdev_aid_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofNetdevAid, sysprof_netdev_aid, SYSPROF, NETDEV_AID, SysprofAid)
|
||||
|
||||
SysprofAid *sysprof_netdev_aid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user