[console] watcher: split watcher out from application
- From: Zander Brown <zbrown src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [console] watcher: split watcher out from application
- Date: Sun, 7 Aug 2022 16:05:51 +0000 (UTC)
commit 004e034f80407ca919e72c8708c9c5ab71ff37c2
Author: Zander Brown <zbrown gnome org>
Date: Sat Aug 6 02:54:37 2022 +0100
watcher: split watcher out from application
At least initally it takes the form of a global singleton, but will
probably be attached to application again in due course
The watcher machinery didn't really interact with much of application,
and didn't really conceptually belong there. By splitting out we
hopefully simplify later experiments with alternative watchers.
src/kgx-application.c | 234 +----------------------------------
src/kgx-application.h | 28 -----
src/kgx-watcher.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/kgx-watcher.h | 41 ++++++
src/kgx-window.c | 9 +-
src/meson.build | 2 +
6 files changed, 384 insertions(+), 266 deletions(-)
---
diff --git a/src/kgx-application.c b/src/kgx-application.c
index f2a0f7f..0b61316 100644
--- a/src/kgx-application.c
+++ b/src/kgx-application.c
@@ -40,6 +40,7 @@
#include "kgx-pages.h"
#include "kgx-simple-tab.h"
#include "kgx-resources.h"
+#include "kgx-watcher.h"
#define LOGO_COL_SIZE 28
#define LOGO_ROW_SIZE 14
@@ -172,8 +173,6 @@ kgx_application_finalize (GObject *object)
g_clear_object (&self->settings);
g_clear_object (&self->desktop_interface);
- g_clear_pointer (&self->watching, g_tree_unref);
- g_clear_pointer (&self->children, g_tree_unref);
g_clear_pointer (&self->pages, g_tree_unref);
G_OBJECT_CLASS (kgx_application_parent_class)->finalize (object);
@@ -205,115 +204,6 @@ kgx_application_activate (GApplication *app)
}
-static gboolean
-handle_watch_iter (gpointer pid,
- gpointer val,
- gpointer user_data)
-{
- KgxProcess *process = val;
- KgxApplication *self = user_data;
- GPid parent = kgx_process_get_parent (process);
- struct ProcessWatch *watch = NULL;
-
- watch = g_tree_lookup (self->watching, GINT_TO_POINTER (parent));
-
- // There are far more processes on the system than there are children
- // of watches, thus lookup are unlikly
- if (G_UNLIKELY (watch != NULL)) {
-
- /* If the page died we stop caring about its processes */
- if (G_UNLIKELY (watch->page == NULL)) {
- g_tree_remove (self->watching, GINT_TO_POINTER (parent));
- g_tree_remove (self->children, pid);
-
- return FALSE;
- }
-
- if (!g_tree_lookup (self->children, pid)) {
- struct ProcessWatch *child_watch = g_new0 (struct ProcessWatch, 1);
-
- child_watch->process = g_rc_box_acquire (process);
- g_set_weak_pointer (&child_watch->page, watch->page);
-
- g_debug ("Hello %i!", GPOINTER_TO_INT (pid));
-
- g_tree_insert (self->children, pid, child_watch);
- }
-
- kgx_tab_push_child (watch->page, process);
- }
-
- return FALSE;
-}
-
-
-struct RemoveDead {
- GTree *plist;
- GPtrArray *dead;
-};
-
-
-static gboolean
-remove_dead (gpointer pid,
- gpointer val,
- gpointer user_data)
-{
- struct RemoveDead *data = user_data;
- struct ProcessWatch *watch = val;
-
- if (!g_tree_lookup (data->plist, pid)) {
- g_debug ("%i marked as dead", GPOINTER_TO_INT (pid));
-
- kgx_tab_pop_child (watch->page, watch->process);
-
- g_ptr_array_add (data->dead, pid);
- }
-
- return FALSE;
-}
-
-
-static gboolean
-watch (gpointer data)
-{
- KgxApplication *self = KGX_APPLICATION (data);
- g_autoptr (GTree) plist = NULL;
- struct RemoveDead dead;
-
- plist = kgx_process_get_list ();
-
- g_tree_foreach (plist, handle_watch_iter, self);
-
- dead.plist = plist;
- dead.dead = g_ptr_array_new_full (1, NULL);
-
- g_tree_foreach (self->children, remove_dead, &dead);
-
- // We can't modify self->chilren whilst walking it
- for (int i = 0; i < dead.dead->len; i++) {
- g_tree_remove (self->children, g_ptr_array_index (dead.dead, i));
- }
-
- g_ptr_array_unref (dead.dead);
-
- return G_SOURCE_CONTINUE;
-}
-
-static inline void
-set_watcher (KgxApplication *self, gboolean focused)
-{
- g_debug ("updated watcher focused? %s", focused ? "yes" : "no");
-
- if (self->timeout != 0) {
- g_source_remove (self->timeout);
- }
-
- // Slow down polling when nothing is focused
- self->timeout = g_timeout_add (focused ? 500 : 2000, watch, self);
- g_source_set_name_by_id (self->timeout, "[kgx] child watcher");
-}
-
-
static void
kgx_application_startup (GApplication *app)
{
@@ -365,8 +255,6 @@ kgx_application_startup (GApplication *app)
settings_action = g_settings_create_action (self->settings, "theme");
g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (settings_action));
-
- set_watcher (KGX_APPLICATION (app), TRUE);
}
@@ -681,18 +569,6 @@ kgx_application_class_init (KgxApplicationClass *klass)
}
-static void
-clear_watch (struct ProcessWatch *watch)
-{
- g_return_if_fail (watch != NULL);
-
- g_clear_pointer (&watch->process, kgx_process_unref);
- g_clear_weak_pointer (&watch->page);
-
- g_clear_pointer (&watch, g_free);
-}
-
-
static void
font_changed (GSettings *settings,
const char *key,
@@ -914,67 +790,7 @@ kgx_application_init (KgxApplication *self)
G_CALLBACK (font_changed),
self);
- self->watching = g_tree_new_full (kgx_pid_cmp,
- NULL,
- NULL,
- (GDestroyNotify) clear_watch);
- self->children = g_tree_new_full (kgx_pid_cmp,
- NULL,
- NULL,
- (GDestroyNotify) clear_watch);
self->pages = g_tree_new_full (kgx_pid_cmp, NULL, NULL, NULL);
-
- self->active = 0;
- self->timeout = 0;
-}
-
-
-/**
- * kgx_application_add_watch:
- * @self: the #KgxApplication
- * @pid: the shell process to watch
- * @page: the #KgxTab the shell is running in
- *
- * Registers a new shell process with the pid watcher
- */
-void
-kgx_application_add_watch (KgxApplication *self,
- GPid pid,
- KgxTab *page)
-{
- struct ProcessWatch *watch;
-
- g_return_if_fail (KGX_IS_APPLICATION (self));
- g_return_if_fail (KGX_IS_TAB (page));
-
- watch = g_new0 (struct ProcessWatch, 1);
- watch->process = kgx_process_new (pid);
- g_set_weak_pointer (&watch->page, page);
-
- g_debug ("Started watching %i", pid);
-
- g_tree_insert (self->watching, GINT_TO_POINTER (pid), watch);
-}
-
-/**
- * kgx_application_remove_watch:
- * @self: the #KgxApplication
- * @pid: the shell process to stop watch watching
- *
- * unregisters the shell with #GPid pid
- */
-void
-kgx_application_remove_watch (KgxApplication *self,
- GPid pid)
-{
- g_return_if_fail (KGX_IS_APPLICATION (self));
-
- if (G_LIKELY (g_tree_lookup (self->watching, GINT_TO_POINTER (pid)))) {
- g_tree_remove (self->watching, GINT_TO_POINTER (pid));
- g_debug ("Stopped watching %i", pid);
- } else {
- g_warning ("Unknown process %i", pid);
- }
}
@@ -1001,52 +817,6 @@ kgx_application_get_font (KgxApplication *self)
}
-/**
- * kgx_application_push_active:
- * @self: the #KgxApplication
- *
- * Increase the active window count
- */
-void
-kgx_application_push_active (KgxApplication *self)
-{
- g_return_if_fail (KGX_IS_APPLICATION (self));
-
- self->active++;
-
- g_debug ("push_active");
-
- if (G_LIKELY (self->active > 0)) {
- set_watcher (self, TRUE);
- } else {
- set_watcher (self, FALSE);
- }
-}
-
-
-/**
- * kgx_application_pop_active:
- * @self: the #KgxApplication
- *
- * Decrease the active window count
- */
-void
-kgx_application_pop_active (KgxApplication *self)
-{
- g_return_if_fail (KGX_IS_APPLICATION (self));
-
- self->active--;
-
- g_debug ("pop_active");
-
- if (G_LIKELY (self->active < 1)) {
- set_watcher (self, FALSE);
- } else {
- set_watcher (self, TRUE);
- }
-}
-
-
static void
page_died (gpointer data, GObject *dead_object)
{
@@ -1117,7 +887,7 @@ started (GObject *src,
return;
}
- kgx_application_add_watch (KGX_APPLICATION (app), pid, page);
+ kgx_watcher_add (kgx_watcher_get_default (), pid, page);
}
diff --git a/src/kgx-application.h b/src/kgx-application.h
index fa401cd..4aa879b 100644
--- a/src/kgx-application.h
+++ b/src/kgx-application.h
@@ -44,29 +44,13 @@ G_BEGIN_DECLS
#define KGX_TYPE_APPLICATION (kgx_application_get_type())
-/**
- * ProcessWatch:
- * @page: the #KgxTab the #KgxProcess is in
- * @process: what we are watching
- *
- * Stability: Private
- */
-struct ProcessWatch {
- KgxTab /*weak*/ *page;
- KgxProcess *process;
-};
/**
* KgxApplication:
* @theme: the colour palette in use
* @scale: the font scaling used
* @desktop_interface: the #GSettings storing the system monospace font
- * @watching: ~ (element-type GLib.Pid ProcessWatch) the shells running in windows
- * @children: ~ (element-type GLib.Pid ProcessWatch) the processes running in shells
* @pages: ~ (element-type uint Kgx.Page) the global page id / page map
- * @active: counter of #KgxWindow's with #GtkWindow:is-active = %TRUE,
- * obviously this should only ever be 1 or but we can't be certain
- * @timeout: the current #GSource id of the watcher
*
* Stability: Private
*/
@@ -83,25 +67,13 @@ struct _KgxApplication
GSettings *settings;
GSettings *desktop_interface;
- GTree *watching;
- GTree *children;
GTree *pages;
-
- guint timeout;
- int active;
};
G_DECLARE_FINAL_TYPE (KgxApplication, kgx_application, KGX, APPLICATION, AdwApplication)
-void kgx_application_add_watch (KgxApplication *self,
- GPid pid,
- KgxTab *page);
-void kgx_application_remove_watch (KgxApplication *self,
- GPid pid);
PangoFontDescription *kgx_application_get_font (KgxApplication *self);
-void kgx_application_push_active (KgxApplication *self);
-void kgx_application_pop_active (KgxApplication *self);
void kgx_application_add_page (KgxApplication *self,
KgxTab *page);
KgxTab *kgx_application_lookup_page (KgxApplication *self,
diff --git a/src/kgx-watcher.c b/src/kgx-watcher.c
new file mode 100644
index 0000000..2fdb966
--- /dev/null
+++ b/src/kgx-watcher.c
@@ -0,0 +1,336 @@
+/* kgx-watcher.c
+ *
+ * Copyright 2022 Zander Brown
+ *
+ * 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/>.
+ */
+
+#include "kgx-config.h"
+
+#include "kgx-watcher.h"
+
+
+/**
+ * ProcessWatch:
+ * @page: the #KgxTab the #KgxProcess is in
+ * @process: what we are watching
+ *
+ * Stability: Private
+ */
+struct ProcessWatch {
+ KgxTab /*weak*/ *page;
+ KgxProcess *process;
+};
+
+
+/**
+ * KgxWatcher:
+ * @watching: (element-type GLib.Pid ProcessWatch) the shells running in windows
+ * @children: (element-type GLib.Pid ProcessWatch) the processes running in shells
+ * @active: counter of #KgxWindow's with #GtkWindow:is-active = %TRUE,
+ * obviously this should only ever be 1 or but we can't be certain
+ * @timeout: the current #GSource id of the watcher
+ *
+ * Used to monitor processes running in pages
+ */
+struct _KgxWatcher {
+ GObject parent_instance;
+
+ GTree *watching;
+ GTree *children;
+
+ guint timeout;
+ int active;
+};
+
+
+G_DEFINE_TYPE (KgxWatcher, kgx_watcher, G_TYPE_OBJECT)
+
+
+static void
+kgx_watcher_dispose (GObject *object)
+{
+ KgxWatcher *self = KGX_WATCHER (object);
+
+ g_clear_pointer (&self->watching, g_tree_unref);
+ g_clear_pointer (&self->children, g_tree_unref);
+
+ G_OBJECT_CLASS (kgx_watcher_parent_class)->dispose (object);
+}
+
+
+static void
+kgx_watcher_class_init (KgxWatcherClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = kgx_watcher_dispose;
+}
+
+
+static void
+clear_watch (struct ProcessWatch *watch)
+{
+ g_return_if_fail (watch != NULL);
+
+ g_clear_pointer (&watch->process, kgx_process_unref);
+ g_clear_weak_pointer (&watch->page);
+
+ g_clear_pointer (&watch, g_free);
+}
+
+
+static gboolean
+handle_watch_iter (gpointer pid,
+ gpointer val,
+ gpointer user_data)
+{
+ KgxProcess *process = val;
+ KgxWatcher *self = user_data;
+ GPid parent = kgx_process_get_parent (process);
+ struct ProcessWatch *watch = NULL;
+
+ watch = g_tree_lookup (self->watching, GINT_TO_POINTER (parent));
+
+ // There are far more processes on the system than there are children
+ // of watches, thus lookup are unlikly
+ if (G_UNLIKELY (watch != NULL)) {
+
+ /* If the page died we stop caring about its processes */
+ if (G_UNLIKELY (watch->page == NULL)) {
+ g_tree_remove (self->watching, GINT_TO_POINTER (parent));
+ g_tree_remove (self->children, pid);
+
+ return FALSE;
+ }
+
+ if (!g_tree_lookup (self->children, pid)) {
+ struct ProcessWatch *child_watch = g_new0 (struct ProcessWatch, 1);
+
+ child_watch->process = g_rc_box_acquire (process);
+ g_set_weak_pointer (&child_watch->page, watch->page);
+
+ g_debug ("Hello %i!", GPOINTER_TO_INT (pid));
+
+ g_tree_insert (self->children, pid, child_watch);
+ }
+
+ kgx_tab_push_child (watch->page, process);
+ }
+
+ return FALSE;
+}
+
+
+struct RemoveDead {
+ GTree *plist;
+ GPtrArray *dead;
+};
+
+
+static gboolean
+remove_dead (gpointer pid,
+ gpointer val,
+ gpointer user_data)
+{
+ struct RemoveDead *data = user_data;
+ struct ProcessWatch *watch = val;
+
+ if (!g_tree_lookup (data->plist, pid)) {
+ g_debug ("%i marked as dead", GPOINTER_TO_INT (pid));
+
+ kgx_tab_pop_child (watch->page, watch->process);
+
+ g_ptr_array_add (data->dead, pid);
+ }
+
+ return FALSE;
+}
+
+
+static gboolean
+watch (gpointer data)
+{
+ KgxWatcher *self = KGX_WATCHER (data);
+ g_autoptr (GTree) plist = NULL;
+ struct RemoveDead dead;
+
+ plist = kgx_process_get_list ();
+
+ g_tree_foreach (plist, handle_watch_iter, self);
+
+ dead.plist = plist;
+ dead.dead = g_ptr_array_new_full (1, NULL);
+
+ g_tree_foreach (self->children, remove_dead, &dead);
+
+ // We can't modify self->chilren whilst walking it
+ for (int i = 0; i < dead.dead->len; i++) {
+ g_tree_remove (self->children, g_ptr_array_index (dead.dead, i));
+ }
+
+ g_ptr_array_unref (dead.dead);
+
+ return G_SOURCE_CONTINUE;
+}
+
+
+static inline void
+set_watcher (KgxWatcher *self, gboolean focused)
+{
+ g_debug ("updated watcher focused? %s", focused ? "yes" : "no");
+
+ if (self->timeout != 0) {
+ g_source_remove (self->timeout);
+ }
+
+ // Slow down polling when nothing is focused
+ self->timeout = g_timeout_add (focused ? 500 : 2000, watch, self);
+ g_source_set_name_by_id (self->timeout, "[kgx] child watcher");
+}
+
+
+static void
+kgx_watcher_init (KgxWatcher *self)
+{
+ self->watching = g_tree_new_full (kgx_pid_cmp,
+ NULL,
+ NULL,
+ (GDestroyNotify) clear_watch);
+ self->children = g_tree_new_full (kgx_pid_cmp,
+ NULL,
+ NULL,
+ (GDestroyNotify) clear_watch);
+
+ self->active = 0;
+ self->timeout = 0;
+
+ set_watcher (self, TRUE);
+}
+
+
+/**
+ * kgx_watcher_get_default:
+ *
+ * Returns: (transfer none): the #KgxWatcher singleton
+ */
+KgxWatcher *
+kgx_watcher_get_default (void)
+{
+ static KgxWatcher *instance;
+
+ if (instance == NULL) {
+ instance = g_object_new (KGX_TYPE_WATCHER, NULL);
+ g_object_add_weak_pointer (G_OBJECT (instance), (gpointer *) &instance);
+ }
+
+ return instance;
+}
+
+
+/**
+ * kgx_watcher_add:
+ * @self: the #KgxWatcher
+ * @pid: the shell process to watch
+ * @page: the #KgxTab the shell is running in
+ *
+ * Registers a new shell process with the pid watcher
+ */
+void
+kgx_watcher_add (KgxWatcher *self,
+ GPid pid,
+ KgxTab *page)
+{
+ struct ProcessWatch *watch;
+
+ g_return_if_fail (KGX_IS_WATCHER (self));
+ g_return_if_fail (KGX_IS_TAB (page));
+
+ watch = g_new0 (struct ProcessWatch, 1);
+ watch->process = kgx_process_new (pid);
+ g_set_weak_pointer (&watch->page, page);
+
+ g_debug ("Started watching %i", pid);
+
+ g_tree_insert (self->watching, GINT_TO_POINTER (pid), watch);
+}
+
+
+/**
+ * kgx_watcher_remove:
+ * @self: the #KgxWatcher
+ * @pid: the shell process to stop watch watching
+ *
+ * unregisters the shell with #GPid pid
+ */
+void
+kgx_watcher_remove (KgxWatcher *self,
+ GPid pid)
+{
+ g_return_if_fail (KGX_IS_WATCHER (self));
+
+ if (G_LIKELY (g_tree_lookup (self->watching, GINT_TO_POINTER (pid)))) {
+ g_tree_remove (self->watching, GINT_TO_POINTER (pid));
+ g_debug ("Stopped watching %i", pid);
+ } else {
+ g_warning ("Unknown process %i", pid);
+ }
+}
+
+
+/**
+ * kgx_watcher_push_active:
+ * @self: the #KgxWatcher
+ *
+ * Increase the active window count
+ */
+void
+kgx_watcher_push_active (KgxWatcher *self)
+{
+ g_return_if_fail (KGX_IS_WATCHER (self));
+
+ self->active++;
+
+ g_debug ("push_active");
+
+ if (G_LIKELY (self->active > 0)) {
+ set_watcher (self, TRUE);
+ } else {
+ set_watcher (self, FALSE);
+ }
+}
+
+
+/**
+ * kgx_watcher_pop_active:
+ * @self: the #KgxWatcher
+ *
+ * Decrease the active window count
+ */
+void
+kgx_watcher_pop_active (KgxWatcher *self)
+{
+ g_return_if_fail (KGX_IS_WATCHER (self));
+
+ self->active--;
+
+ g_debug ("pop_active");
+
+ if (G_LIKELY (self->active < 1)) {
+ set_watcher (self, FALSE);
+ } else {
+ set_watcher (self, TRUE);
+ }
+}
+
diff --git a/src/kgx-watcher.h b/src/kgx-watcher.h
new file mode 100644
index 0000000..e344dae
--- /dev/null
+++ b/src/kgx-watcher.h
@@ -0,0 +1,41 @@
+/* kgx-watcher.h
+ *
+ * Copyright 2022 Zander Brown
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+#include "kgx-process.h"
+#include "kgx-tab.h"
+
+G_BEGIN_DECLS
+
+#define KGX_TYPE_WATCHER kgx_watcher_get_type ()
+G_DECLARE_FINAL_TYPE (KgxWatcher, kgx_watcher, KGX, WATCHER, GObject)
+
+
+KgxWatcher *kgx_watcher_get_default (void);
+void kgx_watcher_add (KgxWatcher *self,
+ GPid pid,
+ KgxTab *page);
+void kgx_watcher_remove (KgxWatcher *self,
+ GPid pid);
+void kgx_watcher_push_active (KgxWatcher *self);
+void kgx_watcher_pop_active (KgxWatcher *self);
+
+G_END_DECLS
diff --git a/src/kgx-window.c b/src/kgx-window.c
index 5086afe..9c63bb2 100644
--- a/src/kgx-window.c
+++ b/src/kgx-window.c
@@ -41,6 +41,7 @@
#include "kgx-tab-button.h"
#include "kgx-tab-switcher.h"
#include "kgx-theme-switcher.h"
+#include "kgx-watcher.h"
G_DEFINE_TYPE (KgxWindow, kgx_window, ADW_TYPE_APPLICATION_WINDOW)
@@ -211,14 +212,10 @@ kgx_window_close_request (GtkWindow *window)
static void
active_changed (GObject *object, GParamSpec *pspec, gpointer data)
{
- GtkApplication *app;
-
- app = gtk_window_get_application (GTK_WINDOW (object));
-
if (gtk_window_is_active (GTK_WINDOW (object))) {
- kgx_application_push_active (KGX_APPLICATION (app));
+ kgx_watcher_push_active (kgx_watcher_get_default ());
} else {
- kgx_application_pop_active (KGX_APPLICATION (app));
+ kgx_watcher_pop_active (kgx_watcher_get_default ());
}
}
diff --git a/src/meson.build b/src/meson.build
index f8d5358..48a1dc2 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -23,6 +23,8 @@ kgx_sources = [
'kgx-proxy-info.h',
'kgx-close-dialog.c',
'kgx-close-dialog.h',
+ 'kgx-watcher.c',
+ 'kgx-watcher.h',
'kgx-window.c',
'kgx-window.h',
'kgx-process.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]