From 27a63e34145ea023e8b0a0fb08117c38ba137af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?= Date: Fri, 25 Sep 2020 06:45:27 +0200 Subject: [PATCH] Collect events in the main thread --- wdmtg.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/wdmtg.c b/wdmtg.c index 1b8e7ec..c5a1f71 100644 --- a/wdmtg.c +++ b/wdmtg.c @@ -243,6 +243,41 @@ x_text_property(xcb_window_t window, xcb_atom_t property) return NULL; } +// --- Async Queue Source ------------------------------------------------------ + +static gboolean +async_queue_source_prepare(G_GNUC_UNUSED GSource *source, + G_GNUC_UNUSED gint *timeout_) +{ + return g_async_queue_length(g.queue) > 0; +} + +static gboolean +async_queue_source_dispatch(G_GNUC_UNUSED GSource *source, + GSourceFunc callback, gpointer user_data) +{ + // I don't want to call it once per message, prefer batch processing + if (callback) + return callback(user_data); + + return G_SOURCE_CONTINUE; +} + +static GSource * +async_queue_source_new(void) +{ + static GSourceFuncs funcs = { + .prepare = async_queue_source_prepare, + .check = NULL, + .dispatch = async_queue_source_dispatch, + .finalize = NULL, + }; + + GSource *source = g_source_new(&funcs, sizeof *source); + g_source_set_name(source, "AsyncQueueSource"); + return source; +} + // --- Generator --------------------------------------------------------------- static void @@ -252,6 +287,9 @@ push_event(void) { event->title = g_strdup(gen.current_title); event->idle = gen.current_idle; g_async_queue_push(g.queue, event); + + // This is the best thing GLib exposes (GWakeUp is internal) + g_main_context_wakeup(g_main_context_default()); } static char * @@ -309,11 +347,8 @@ update_current_window(void) } free(gpr); - if (update_window_title(new_title)) { - printf("Window changed: %s\n", - gen.current_title ? gen.current_title : "(none)"); + if (update_window_title(new_title)) push_event(); - } } static void @@ -324,10 +359,8 @@ on_x_property_notify(const xcb_property_notify_event_t *ev) update_current_window(); } else if (ev->window == gen.current_window && ev->atom == gen.atom_net_wm_name) { - if (update_window_title(x_window_title(ev->window))) { - printf("Title changed: %s\n", gen.current_title); + if (update_window_title(x_window_title(ev->window))) push_event(); - } } } @@ -357,7 +390,6 @@ static void on_x_alarm_notify(const xcb_sync_alarm_notify_event_t *ev) { if (ev->alarm == gen.idle_alarm_inactive) { - printf("User is inactive\n"); gen.current_idle = true; push_event(); @@ -369,7 +401,6 @@ on_x_alarm_notify(const xcb_sync_alarm_notify_event_t *ev) set_idle_alarm(&gen.idle_alarm_active, XCB_SYNC_TESTTYPE_NEGATIVE_COMPARISON, minus_one); } else if (ev->alarm == gen.idle_alarm_active) { - printf("User is active\n"); gen.current_idle = false; push_event(); @@ -508,6 +539,18 @@ generator_cleanup(void) // --- Main -------------------------------------------------------------------- +static gboolean +on_queue_incoming(G_GNUC_UNUSED gpointer user_data) +{ + struct event *event = NULL; + while ((event = g_async_queue_try_pop(g.queue))) { + printf("Event: ts: %ld, title: %s, idle: %d\n", + event->timestamp, event->title ?: "(none)", event->idle); + event_free(event); + } + return G_SOURCE_CONTINUE; +} + static sqlite3 * database_init(const gchar *db_path) { @@ -642,10 +685,9 @@ main(int argc, char *argv[]) g.db = database_init(db_path); g_free(db_path); - // TODO: somehow read events from the async queue - // TODO: how in the name of fuck would our custom source wake up a sleeping - // main loop? There is g_main_context_wakeup() but... - // - GWakeUp is internal, apparently + GSource *queue_source = async_queue_source_new(); + g_source_set_callback(queue_source, on_queue_incoming, NULL, NULL); + g_source_attach(queue_source, g_main_context_default()); // TODO: listen for connections on the control socket