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:
Christian Hergert
2023-07-12 10:00:11 -07:00
parent 6075a0cd91
commit ae571f3f6e
148 changed files with 0 additions and 29695 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 (&copy);
}
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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
{
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
{
}

View File

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

View File

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

View File

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

View File

@ -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)
{
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
{
}

View File

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

View File

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

View File

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

View File

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

View File

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