[libdazzle] counters: add helper counter window for debugging
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libdazzle] counters: add helper counter window for debugging
- Date: Wed, 14 Jun 2017 08:10:56 +0000 (UTC)
commit 393ac8e610b7b15d951c58ff5a32914d1ffa1fa8
Author: Christian Hergert <chergert redhat com>
Date: Wed Jun 14 01:10:40 2017 -0700
counters: add helper counter window for debugging
This can be a useful tool for applications that want to display counters
for the current process.
src/dazzle.gresources.xml | 1 +
src/dazzle.h | 1 +
src/meson.build | 2 +
src/widgets/dzl-counters-window.c | 231 ++++++++++++++++++++++++++++++++++++
src/widgets/dzl-counters-window.h | 49 ++++++++
src/widgets/dzl-counters-window.ui | 60 +++++++++
tests/meson.build | 6 +
tests/test-counters-window.c | 67 +++++++++++
8 files changed, 417 insertions(+), 0 deletions(-)
---
diff --git a/src/dazzle.gresources.xml b/src/dazzle.gresources.xml
index b4a5dbb..5c152cb 100644
--- a/src/dazzle.gresources.xml
+++ b/src/dazzle.gresources.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/dazzle/ui">
+ <file compressed="true" preprocess="xml-stripblanks"
alias="dzl-counters-window.ui">widgets/dzl-counters-window.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="dzl-simple-popover.ui">widgets/dzl-simple-popover.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="dzl-empty-state.ui">widgets/dzl-empty-state.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="dzl-pill-box.ui">widgets/dzl-pill-box.ui</file>
diff --git a/src/dazzle.h b/src/dazzle.h
index 473cdd8..6fe97c5 100644
--- a/src/dazzle.h
+++ b/src/dazzle.h
@@ -135,6 +135,7 @@ G_BEGIN_DECLS
#include "widgets/dzl-box.h"
#include "widgets/dzl-centering-bin.h"
#include "widgets/dzl-column-layout.h"
+#include "widgets/dzl-counters-window.h"
#include "widgets/dzl-elastic-bin.h"
#include "widgets/dzl-empty-state.h"
#include "widgets/dzl-entry-box.h"
diff --git a/src/meson.build b/src/meson.build
index 6f8cf91..7dbcc0d 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -153,6 +153,7 @@ libdazzle_public_headers = [
'widgets/dzl-box.h',
'widgets/dzl-centering-bin.h',
'widgets/dzl-column-layout.h',
+ 'widgets/dzl-counters-window.h',
'widgets/dzl-elastic-bin.h',
'widgets/dzl-empty-state.h',
'widgets/dzl-entry-box.h',
@@ -297,6 +298,7 @@ libdazzle_public_sources = [
'widgets/dzl-box.c',
'widgets/dzl-centering-bin.c',
'widgets/dzl-column-layout.c',
+ 'widgets/dzl-counters-window.c',
'widgets/dzl-elastic-bin.c',
'widgets/dzl-empty-state.c',
'widgets/dzl-entry-box.c',
diff --git a/src/widgets/dzl-counters-window.c b/src/widgets/dzl-counters-window.c
new file mode 100644
index 0000000..3b4db50
--- /dev/null
+++ b/src/widgets/dzl-counters-window.c
@@ -0,0 +1,231 @@
+/* dzl-counters-window.c
+ *
+ * Copyright (C) 2017 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/>.
+ */
+
+#define G_LOG_DOMAIN "dzl-counters-window"
+
+#include "dzl-counters-window.h"
+
+typedef struct
+{
+ GtkTreeView *tree_view;
+ GtkTreeStore *tree_store;
+ GtkTreeViewColumn *value_column;
+ GtkCellRendererText *value_cell;
+
+ DzlCounterArena *arena;
+
+ guint update_source;
+} DzlCountersWindowPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (DzlCountersWindow, dzl_counters_window, GTK_TYPE_WINDOW)
+
+static void
+get_value_cell_data_func (GtkCellLayout *cell_layout,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ static PangoAttrList *attrs;
+ DzlCounter *counter = NULL;
+ g_autofree gchar *str = NULL;
+ gint64 value = 0;
+
+ if G_UNLIKELY (attrs == NULL)
+ {
+ attrs = pango_attr_list_new ();
+ pango_attr_list_insert (attrs, pango_attr_foreground_alpha_new (0.35 * G_MAXUSHORT));
+ }
+
+ gtk_tree_model_get (model, iter, 0, &counter, -1);
+
+ if (counter != NULL)
+ value = dzl_counter_get (counter);
+
+ str = g_strdup_printf ("%"G_GINT64_FORMAT, value);
+
+ g_object_set (cell,
+ "attributes", value == 0 ? attrs : NULL,
+ "text", str,
+ NULL);
+}
+
+static gboolean
+update_display (gpointer data)
+{
+ DzlCountersWindow *self = data;
+ DzlCountersWindowPrivate *priv = dzl_counters_window_get_instance_private (self);
+ GdkWindow *window;
+
+ g_assert (DZL_IS_COUNTERS_WINDOW (self));
+
+ window = gtk_tree_view_get_bin_window (priv->tree_view);
+ gdk_window_invalidate_rect (window, NULL, FALSE);
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+dzl_counters_window_realize (GtkWidget *widget)
+{
+ DzlCountersWindow *self = (DzlCountersWindow *)widget;
+ DzlCountersWindowPrivate *priv = dzl_counters_window_get_instance_private (self);
+
+ g_assert (DZL_IS_COUNTERS_WINDOW (self));
+
+ priv->update_source =
+ g_timeout_add_seconds_full (G_PRIORITY_LOW, 1, update_display, self, NULL);
+
+ GTK_WIDGET_CLASS (dzl_counters_window_parent_class)->realize (widget);
+}
+
+static void
+dzl_counters_window_unrealize (GtkWidget *widget)
+{
+ DzlCountersWindow *self = (DzlCountersWindow *)widget;
+ DzlCountersWindowPrivate *priv = dzl_counters_window_get_instance_private (self);
+
+ g_assert (DZL_IS_COUNTERS_WINDOW (self));
+
+ if (priv->update_source != 0)
+ {
+ g_source_remove (priv->update_source);
+ priv->update_source = 0;
+ }
+
+ GTK_WIDGET_CLASS (dzl_counters_window_parent_class)->unrealize (widget);
+}
+
+static void
+dzl_counters_window_finalize (GObject *object)
+{
+ DzlCountersWindow *self = (DzlCountersWindow *)object;
+ DzlCountersWindowPrivate *priv = dzl_counters_window_get_instance_private (self);
+
+ g_clear_pointer (&priv->arena, dzl_counter_arena_unref);
+ g_clear_object (&priv->tree_store);
+
+ G_OBJECT_CLASS (dzl_counters_window_parent_class)->finalize (object);
+}
+
+static void
+dzl_counters_window_class_init (DzlCountersWindowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = dzl_counters_window_finalize;
+
+ widget_class->realize = dzl_counters_window_realize;
+ widget_class->unrealize = dzl_counters_window_unrealize;
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/dazzle/ui/dzl-counters-window.ui");
+ gtk_widget_class_bind_template_child_private (widget_class, DzlCountersWindow, tree_view);
+ gtk_widget_class_bind_template_child_private (widget_class, DzlCountersWindow, value_cell);
+ gtk_widget_class_bind_template_child_private (widget_class, DzlCountersWindow, value_column);
+}
+
+static void
+dzl_counters_window_init (DzlCountersWindow *self)
+{
+ DzlCountersWindowPrivate *priv = dzl_counters_window_get_instance_private (self);
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ priv->tree_store = gtk_tree_store_new (4, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ gtk_tree_view_set_model (priv->tree_view, GTK_TREE_MODEL (priv->tree_store));
+
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv->value_column),
+ GTK_CELL_RENDERER (priv->value_cell),
+ get_value_cell_data_func,
+ NULL, NULL);
+}
+
+static void
+foreach_counter_cb (DzlCounter *counter,
+ gpointer user_data)
+{
+ DzlCountersWindow *self = user_data;
+ DzlCountersWindowPrivate *priv = dzl_counters_window_get_instance_private (self);
+ GtkTreeIter iter;
+
+ g_assert (DZL_IS_COUNTERS_WINDOW (self));
+
+ gtk_tree_store_append (priv->tree_store, &iter, NULL);
+ gtk_tree_store_set (priv->tree_store, &iter,
+ 0, counter,
+ 1, counter->category,
+ 2, counter->name,
+ 3, counter->description,
+ -1);
+}
+
+static void
+dzl_counters_window_reload (DzlCountersWindow *self)
+{
+ DzlCountersWindowPrivate *priv = dzl_counters_window_get_instance_private (self);
+
+ g_assert (DZL_IS_COUNTERS_WINDOW (self));
+
+ gtk_tree_store_clear (priv->tree_store);
+ if (priv->arena == NULL)
+ return;
+
+ dzl_counter_arena_foreach (priv->arena, foreach_counter_cb, self);
+}
+
+GtkWidget *
+dzl_counters_window_new (void)
+{
+ return g_object_new (DZL_TYPE_COUNTERS_WINDOW, NULL);
+}
+
+/**
+ * dzl_counters_window_get_arena:
+ * @self: a #DzlCountersWindow
+ *
+ * Gets the currently viewed arena, if any.
+ *
+ * Returns: (transfer none) (nullable): A #DzlCounterArena or %NULL.
+ */
+DzlCounterArena *
+dzl_counters_window_get_arena (DzlCountersWindow *self)
+{
+ DzlCountersWindowPrivate *priv = dzl_counters_window_get_instance_private (self);
+
+ g_return_val_if_fail (DZL_IS_COUNTERS_WINDOW (self), NULL);
+
+ return priv->arena;
+}
+
+void
+dzl_counters_window_set_arena (DzlCountersWindow *self,
+ DzlCounterArena *arena)
+{
+ DzlCountersWindowPrivate *priv = dzl_counters_window_get_instance_private (self);
+
+ g_return_if_fail (DZL_IS_COUNTERS_WINDOW (self));
+
+ if (arena != priv->arena)
+ {
+ g_clear_pointer (&priv->arena, dzl_counter_arena_unref);
+ if (arena != NULL)
+ priv->arena = dzl_counter_arena_ref (arena);
+ dzl_counters_window_reload (self);
+ }
+}
diff --git a/src/widgets/dzl-counters-window.h b/src/widgets/dzl-counters-window.h
new file mode 100644
index 0000000..67fc825
--- /dev/null
+++ b/src/widgets/dzl-counters-window.h
@@ -0,0 +1,49 @@
+/* dzl-counters-window.h
+ *
+ * Copyright (C) 2017 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/>.
+ */
+
+#ifndef DZL_COUNTERS_WINDOW_H
+#define DZL_COUNTERS_WINDOW_H
+
+#include <gtk/gtk.h>
+
+#include "util/dzl-counter.h"
+
+G_BEGIN_DECLS
+
+#define DZL_TYPE_COUNTERS_WINDOW (dzl_counters_window_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (DzlCountersWindow, dzl_counters_window, DZL, COUNTERS_WINDOW, GtkWindow)
+
+struct _DzlCountersWindowClass
+{
+ GtkWindowClass parent_class;
+
+ gpointer _reserved1;
+ gpointer _reserved2;
+ gpointer _reserved3;
+ gpointer _reserved4;
+};
+
+GtkWidget *dzl_counters_window_new (void);
+DzlCounterArena *dzl_counters_window_get_arena (DzlCountersWindow *self);
+void dzl_counters_window_set_arena (DzlCountersWindow *self,
+ DzlCounterArena *arena);
+
+G_END_DECLS
+
+#endif /* DZL_COUNTERS_WINDOW_H */
diff --git a/src/widgets/dzl-counters-window.ui b/src/widgets/dzl-counters-window.ui
new file mode 100644
index 0000000..7a6f5c4
--- /dev/null
+++ b/src/widgets/dzl-counters-window.ui
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="DzlCountersWindow" parent="GtkWindow">
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="expand">true</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkTreeView" id="tree_view">
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Category</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Name</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="value_column">
+ <property name="expand">false</property>
+ <property name="title" translatable="yes">Value</property>
+ <child>
+ <object class="GtkCellRendererText" id="value_cell">
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="expand">true</property>
+ <property name="title" translatable="yes">Description</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/tests/meson.build b/tests/meson.build
index 7f40618..d7e4871 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -265,4 +265,10 @@ test_ring = executable('test-ring', 'test-ring.c',
dependencies: libdazzle_deps + [libdazzle_dep],
)
+test_counters_window = executable('test-counters-window', 'test-counters-window.c',
+ c_args: test_cflags,
+ link_args: test_link_args,
+ dependencies: libdazzle_deps + [libdazzle_dep],
+)
+
endif
diff --git a/tests/test-counters-window.c b/tests/test-counters-window.c
new file mode 100644
index 0000000..88f4595
--- /dev/null
+++ b/tests/test-counters-window.c
@@ -0,0 +1,67 @@
+#include <dazzle.h>
+#include <stdlib.h>
+#include <errno.h>
+
+static gboolean
+int_parse_with_range (gint *value,
+ gint lower,
+ gint upper,
+ const gchar *str)
+{
+ gint64 v64;
+
+ g_assert (value);
+ g_assert (lower <= upper);
+
+ v64 = g_ascii_strtoll (str, NULL, 10);
+
+ if (((v64 == G_MININT64) || (v64 == G_MAXINT64)) && (errno == ERANGE))
+ return FALSE;
+
+ if ((v64 < lower) || (v64 > upper))
+ return FALSE;
+
+ *value = (gint)v64;
+
+ return TRUE;
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ GtkWidget *window;
+ DzlCounterArena *arena;
+ gint pid;
+
+ gtk_init (&argc, &argv);
+
+ if (argc < 2)
+ {
+ g_printerr ("usage: %s [PID]\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ if (!int_parse_with_range (&pid, 1, G_MAXUSHORT, argv[1]))
+ {
+ g_printerr ("usage: %s [PID]\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ arena = dzl_counter_arena_new_for_pid (pid);
+
+ if (arena == NULL)
+ {
+ g_printerr ("Failed to access counters for process %u.\n", pid);
+ return EXIT_FAILURE;
+ }
+
+ window = dzl_counters_window_new ();
+ dzl_counters_window_set_arena (DZL_COUNTERS_WINDOW (window), arena);
+ g_signal_connect (window, "delete-event", gtk_main_quit, NULL);
+ gtk_window_present (GTK_WINDOW (window));
+
+ gtk_main ();
+
+ return EXIT_SUCCESS;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]