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