Use a gsource instead of gio channels for watching x events
[dana/openbox.git] / obt / xqueue.c
index 2304ea4..b370c4a 100644 (file)
@@ -78,8 +78,8 @@ static inline void grow(void) {
 
         if (qend < qstart) { /* it wraps around to 0 right now */
             for (i = 0; i <= qend; ++i)
-                q[newsz+i] = q[i];
-            qend = newsz + qend;
+                q[qsz+i] = q[i];
+            qend = qsz + qend;
         }
 
         qsz = newsz;
@@ -113,7 +113,7 @@ static gboolean read_events(gboolean block)
     return sth; /* return if we read anything */
 }
 
-static void pop(gulong p)
+static void pop(const gulong p)
 {
     /* remove the event */
     --qnum;
@@ -318,3 +318,93 @@ gboolean xqueue_pending_local(void)
     if (!qnum) read_events(FALSE);
     return qnum != 0;
 }
+
+typedef struct _ObtXQueueCB {
+    ObtXQueueFunc func;
+    gpointer data;
+} ObtXQueueCB;
+
+static ObtXQueueCB *callbacks = NULL;
+static guint n_callbacks = 0;
+
+static gboolean event_read(GSource *source, GSourceFunc callback, gpointer data)
+{
+    XEvent ev;
+
+    while (xqueue_next_local(&ev)) {
+        guint i;
+        for (i = 0; i < n_callbacks; ++i)
+            callbacks[i].func(&ev, callbacks[i].data);
+    }
+
+    return TRUE; /* repeat */
+}
+
+static gboolean x_source_prepare(GSource *source, gint *timeout)
+{
+    *timeout = -1;
+    return XPending(obt_display);
+}
+
+static gboolean x_source_check(GSource *source)
+{
+    return XPending(obt_display);
+}
+
+struct x_source {
+    GSource source;
+
+    GPollFD pfd;
+};
+
+static GSourceFuncs x_source_funcs = {
+    x_source_prepare,
+    x_source_check,
+    event_read,
+    NULL
+};
+
+void xqueue_listen(void)
+{
+    GSource *source = g_source_new(&x_source_funcs, sizeof(struct x_source));
+    struct x_source *x_source = (struct x_source *)source;
+    GPollFD *pfd = &x_source->pfd;
+
+    *pfd = (GPollFD){ ConnectionNumber(obt_display), G_IO_IN, G_IO_IN };
+    g_source_add_poll(source, pfd);
+    g_source_attach(source, NULL);
+}
+
+void xqueue_add_callback(ObtXQueueFunc f, gpointer data)
+{
+    guint i;
+
+    g_return_if_fail(f != NULL);
+
+    for (i = 0; i < n_callbacks; ++i)
+        if (callbacks[i].func == f && callbacks[i].data == data)
+            return;
+
+    callbacks = g_renew(ObtXQueueCB, callbacks, n_callbacks + 1);
+    callbacks[n_callbacks].func = f;
+    callbacks[n_callbacks].data = data;
+    ++n_callbacks;
+}
+
+void xqueue_remove_callback(ObtXQueueFunc f, gpointer data)
+{
+    guint i;
+
+    g_return_if_fail(f != NULL);
+
+    for (i = 0; i < n_callbacks; ++i) {
+        if (callbacks[i].func == f && callbacks[i].data == data) {
+            /* remove it */
+            for (; i < n_callbacks - 1; ++i)
+                callbacks[i] = callbacks[i+1];
+            callbacks = g_renew(ObtXQueueCB, callbacks, n_callbacks - 1);
+            --n_callbacks;
+            break;
+        }
+    }
+}