summaryrefslogtreecommitdiff
path: root/obt
diff options
context:
space:
mode:
authorDana Jansens <danakj@orodu.net>2010-06-08 17:50:23 -0400
committerDana Jansens <danakj@orodu.net>2010-06-14 12:19:01 -0400
commitfd77a0a7b3f892925f203287b8b46c6ec9be94ea (patch)
treea3e61c8c17969a41279ba21592be7543a262fcd5 /obt
parent2e94af28e4c12166cb74233526bb79f50877903c (diff)
Use GMainLoop instead of ObtMainLoop
Diffstat (limited to 'obt')
-rw-r--r--obt/mainloop.c698
-rw-r--r--obt/mainloop.h81
-rw-r--r--obt/xevent.c140
-rw-r--r--obt/xevent.h48
-rw-r--r--obt/xqueue.c66
-rw-r--r--obt/xqueue.h9
6 files changed, 75 insertions, 967 deletions
diff --git a/obt/mainloop.c b/obt/mainloop.c
deleted file mode 100644
index 75366256..00000000
--- a/obt/mainloop.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
- obt/mainloop.c for the Openbox window manager
- Copyright (c) 2006 Mikael Magnusson
- Copyright (c) 2003-2007 Dana Jansens
-
- 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 2 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.
-
- See the COPYING file for a copy of the GNU General Public License.
-*/
-
-#include "obt/mainloop.h"
-#include "obt/display.h"
-#include "obt/xqueue.h"
-#include "obt/util.h"
-
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-
-typedef struct _ObtMainLoopTimer ObtMainLoopTimer;
-typedef struct _ObtMainLoopSignal ObtMainLoopSignal;
-typedef struct _ObtMainLoopSignalHandlerType ObtMainLoopSignalHandlerType;
-typedef struct _ObtMainLoopXHandlerType ObtMainLoopXHandlerType;
-typedef struct _ObtMainLoopFdHandlerType ObtMainLoopFdHandlerType;
-
-/* this should be more than the number of possible signals on any
- architecture... */
-#define NUM_SIGNALS 99
-
-/* all created ObtMainLoops. Used by the signal handler to pass along
- signals */
-static GSList *all_loops;
-
-/* signals are global to all loops */
-static struct {
- guint installed; /* a ref count */
- struct sigaction oldact;
-} all_signals[NUM_SIGNALS];
-
-/* a set of all possible signals */
-static sigset_t all_signals_set;
-
-/* signals which cause a core dump, these can't be used for callbacks */
-static gint core_signals[] =
-{
- SIGABRT,
- SIGSEGV,
- SIGFPE,
- SIGILL,
- SIGQUIT,
- SIGTRAP,
- SIGSYS,
- SIGBUS,
- SIGXCPU,
- SIGXFSZ
-};
-#define NUM_CORE_SIGNALS (sizeof(core_signals) / sizeof(core_signals[0]))
-
-static void sighandler(gint sig);
-static void timer_dispatch(ObtMainLoop *loop, GTimeVal **wait);
-static void fd_handler_destroy(gpointer data);
-static void calc_max_fd(ObtMainLoop *loop);
-
-struct _ObtMainLoop
-{
- gint ref;
- Display *display;
-
- gboolean run; /* do keep running */
- gboolean running; /* is still running */
-
- GSList *x_handlers;
-
- gint fd_x; /* The X fd is a special case! */
- gint fd_max;
- GHashTable *fd_handlers;
- fd_set fd_set;
-
- GSList *timers;
- GTimeVal now;
- GTimeVal ret_wait;
-
- gboolean signal_fired;
- guint signals_fired[NUM_SIGNALS];
- GSList *signal_handlers[NUM_SIGNALS];
-};
-
-struct _ObtMainLoopTimer
-{
- gulong delay;
- GSourceFunc func;
- gpointer data;
- GEqualFunc equal;
- GDestroyNotify destroy;
-
- /* The timer needs to be freed */
- gboolean del_me;
- /* The time the last fire should've been at */
- GTimeVal last;
- /* When this timer will next trigger */
- GTimeVal timeout;
-
- /* Only allow a timer's function to fire once per run through the list,
- so that it doesn't get locked in there forever */
- gboolean fired;
-};
-
-struct _ObtMainLoopSignalHandlerType
-{
- ObtMainLoop *loop;
- gint signal;
- gpointer data;
- ObtMainLoopSignalHandler func;
- GDestroyNotify destroy;
-};
-
-struct _ObtMainLoopXHandlerType
-{
- ObtMainLoop *loop;
- gpointer data;
- ObtMainLoopXHandler func;
- GDestroyNotify destroy;
-};
-
-struct _ObtMainLoopFdHandlerType
-{
- ObtMainLoop *loop;
- gint fd;
- gpointer data;
- ObtMainLoopFdHandler func;
- GDestroyNotify destroy;
-};
-
-ObtMainLoop *obt_main_loop_new(void)
-{
- ObtMainLoop *loop;
-
- loop = g_slice_new0(ObtMainLoop);
- loop->ref = 1;
- FD_ZERO(&loop->fd_set);
- loop->fd_x = -1;
- loop->fd_max = -1;
-
- loop->fd_handlers = g_hash_table_new_full(g_int_hash, g_int_equal,
- NULL, fd_handler_destroy);
-
- g_get_current_time(&loop->now);
-
- /* only do this if we're the first loop created */
- if (!all_loops) {
- guint i;
- struct sigaction action;
- sigset_t sigset;
-
- /* initialize the all_signals_set */
- sigfillset(&all_signals_set);
-
- sigemptyset(&sigset);
- action.sa_handler = sighandler;
- action.sa_mask = sigset;
- action.sa_flags = SA_NOCLDSTOP;
-
- /* grab all the signals that cause core dumps */
- for (i = 0; i < NUM_CORE_SIGNALS; ++i) {
- /* SIGABRT is curiously not grabbed here!! that's because when we
- get one of the core_signals, we use abort() to dump the core.
- And having the abort() only go back to our signal handler again
- is less than optimal */
- if (core_signals[i] != SIGABRT) {
- sigaction(core_signals[i], &action,
- &all_signals[core_signals[i]].oldact);
- all_signals[core_signals[i]].installed++;
- }
- }
- }
-
- all_loops = g_slist_prepend(all_loops, loop);
-
- return loop;
-}
-
-void obt_main_loop_ref(ObtMainLoop *loop)
-{
- ++loop->ref;
-}
-
-void obt_main_loop_unref(ObtMainLoop *loop)
-{
- guint i;
- GSList *it, *next;
-
- if (loop && --loop->ref == 0) {
- g_assert(loop->running == FALSE);
-
- for (it = loop->x_handlers; it; it = next) {
- ObtMainLoopXHandlerType *h = it->data;
- next = g_slist_next(it);
- obt_main_loop_x_remove(loop, h->func);
- }
-
- g_hash_table_destroy(loop->fd_handlers);
-
- for (it = loop->timers; it; it = g_slist_next(it)) {
- ObtMainLoopTimer *t = it->data;
- if (t->destroy) t->destroy(t->data);
- g_slice_free(ObtMainLoopTimer, t);
- }
- g_slist_free(loop->timers);
- loop->timers = NULL;
-
- for (i = 0; i < NUM_SIGNALS; ++i)
- for (it = loop->signal_handlers[i]; it; it = next) {
- ObtMainLoopSignalHandlerType *h = it->data;
- next = g_slist_next(it);
- obt_main_loop_signal_remove(loop, h->func);
- }
-
- all_loops = g_slist_remove(all_loops, loop);
-
- /* only do this if we're the last loop destroyed */
- if (!all_loops) {
- /* grab all the signals that cause core dumps */
- for (i = 0; i < NUM_CORE_SIGNALS; ++i) {
- if (all_signals[core_signals[i]].installed) {
- sigaction(core_signals[i],
- &all_signals[core_signals[i]].oldact, NULL);
- all_signals[core_signals[i]].installed--;
- }
- }
- }
-
- g_slice_free(ObtMainLoop, loop);
- }
-}
-
-static void fd_handle_foreach(gpointer key,
- gpointer value,
- gpointer data)
-{
- ObtMainLoopFdHandlerType *h = value;
- fd_set *set = data;
-
- if (FD_ISSET(h->fd, set))
- h->func(h->fd, h->data);
-}
-
-void obt_main_loop_run(ObtMainLoop *loop)
-{
- XEvent e;
- struct timeval *wait;
- fd_set selset;
- GSList *it;
-
- loop->run = TRUE;
- loop->running = TRUE;
-
- while (loop->run) {
- if (loop->signal_fired) {
- guint i;
- sigset_t oldset;
-
- /* block signals so that we can do this without the data changing
- on us */
- sigprocmask(SIG_SETMASK, &all_signals_set, &oldset);
-
- for (i = 0; i < NUM_SIGNALS; ++i) {
- while (loop->signals_fired[i]) {
- for (it = loop->signal_handlers[i];
- it; it = g_slist_next(it)) {
- ObtMainLoopSignalHandlerType *h = it->data;
- h->func(i, h->data);
- }
- loop->signals_fired[i]--;
- }
- }
- loop->signal_fired = FALSE;
-
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- } else if (loop->display && xqueue_pending_local()) {
- while (xqueue_next_local(&e) && loop->run) {
- if (e.type == MappingNotify)
- XRefreshKeyboardMapping(&e.xmapping);
-
- for (it = loop->x_handlers; it; it = g_slist_next(it)) {
- ObtMainLoopXHandlerType *h = it->data;
- h->func(&e, h->data);
- }
- }
- } else {
- /* this only runs if there were no x events received */
- timer_dispatch(loop, (GTimeVal**)&wait);
-
- selset = loop->fd_set;
- /* there is a small race condition here. if a signal occurs
- between this if() and the select() then we will not process
- the signal until 'wait' expires. possible solutions include
- using GStaticMutex, and having the signal handler set 'wait'
- to 0 */
- if (!loop->signal_fired)
- select(loop->fd_max + 1, &selset, NULL, NULL, wait);
-
- /* handle the X events with highest prioirity */
- if (FD_ISSET(loop->fd_x, &selset))
- continue;
-
- g_hash_table_foreach(loop->fd_handlers,
- fd_handle_foreach, &selset);
- }
- }
-
- loop->running = FALSE;
-}
-
-void obt_main_loop_exit(ObtMainLoop *loop)
-{
- loop->run = FALSE;
-}
-
-/*** XEVENT WATCHERS ***/
-
-void obt_main_loop_x_add(ObtMainLoop *loop,
- ObtMainLoopXHandler handler,
- gpointer data,
- GDestroyNotify notify)
-{
- ObtMainLoopXHandlerType *h;
-
- h = g_slice_new(ObtMainLoopXHandlerType);
- h->loop = loop;
- h->func = handler;
- h->data = data;
- h->destroy = notify;
-
- if (!loop->x_handlers) {
- g_assert(obt_display); /* is the display open? */
-
- loop->display = obt_display;
- loop->fd_x = ConnectionNumber(loop->display);
- FD_SET(loop->fd_x, &loop->fd_set);
- calc_max_fd(loop);
- }
-
- loop->x_handlers = g_slist_prepend(loop->x_handlers, h);
-}
-
-void obt_main_loop_x_remove(ObtMainLoop *loop,
- ObtMainLoopXHandler handler)
-{
- GSList *it, *next;
-
- for (it = loop->x_handlers; it; it = next) {
- ObtMainLoopXHandlerType *h = it->data;
- next = g_slist_next(it);
- if (h->func == handler) {
- loop->x_handlers = g_slist_delete_link(loop->x_handlers, it);
- if (h->destroy) h->destroy(h->data);
- g_slice_free(ObtMainLoopXHandlerType, h);
- }
- }
-
- if (!loop->x_handlers) {
- FD_CLR(loop->fd_x, &loop->fd_set);
- calc_max_fd(loop);
- }
-}
-
-/*** SIGNAL WATCHERS ***/
-
-static void sighandler(gint sig)
-{
- GSList *it;
- guint i;
-
- g_return_if_fail(sig < NUM_SIGNALS);
-
- for (i = 0; i < NUM_CORE_SIGNALS; ++i)
- if (sig == core_signals[i]) {
- /* XXX special case for signals that default to core dump.
- but throw some helpful output here... */
-
- fprintf(stderr, "How are you gentlemen? All your base are"
- " belong to us. (Openbox received signal %d)\n", sig);
-
- /* die with a core dump */
- abort();
- }
-
- for (it = all_loops; it; it = g_slist_next(it)) {
- ObtMainLoop *loop = it->data;
- loop->signal_fired = TRUE;
- loop->signals_fired[sig]++;
- }
-}
-
-void obt_main_loop_signal_add(ObtMainLoop *loop,
- gint signal,
- ObtMainLoopSignalHandler handler,
- gpointer data,
- GDestroyNotify notify)
-{
- ObtMainLoopSignalHandlerType *h;
-
- g_return_if_fail(signal < NUM_SIGNALS);
-
- h = g_slice_new(ObtMainLoopSignalHandlerType);
- h->loop = loop;
- h->signal = signal;
- h->func = handler;
- h->data = data;
- h->destroy = notify;
- loop->signal_handlers[h->signal] =
- g_slist_prepend(loop->signal_handlers[h->signal], h);
-
- if (!all_signals[signal].installed) {
- struct sigaction action;
- sigset_t sigset;
-
- sigemptyset(&sigset);
- action.sa_handler = sighandler;
- action.sa_mask = sigset;
- action.sa_flags = SA_NOCLDSTOP;
-
- sigaction(signal, &action, &all_signals[signal].oldact);
- }
-
- all_signals[signal].installed++;
-}
-
-void obt_main_loop_signal_remove(ObtMainLoop *loop,
- ObtMainLoopSignalHandler handler)
-{
- guint i;
- GSList *it, *next;
-
- for (i = 0; i < NUM_SIGNALS; ++i) {
- for (it = loop->signal_handlers[i]; it; it = next) {
- ObtMainLoopSignalHandlerType *h = it->data;
-
- next = g_slist_next(it);
-
- if (h->func == handler) {
- g_assert(all_signals[h->signal].installed > 0);
-
- all_signals[h->signal].installed--;
- if (!all_signals[h->signal].installed) {
- sigaction(h->signal, &all_signals[h->signal].oldact, NULL);
- }
-
- loop->signal_handlers[i] =
- g_slist_delete_link(loop->signal_handlers[i], it);
- if (h->destroy) h->destroy(h->data);
-
- g_slice_free(ObtMainLoopSignalHandlerType, h);
- }
- }
- }
-
-}
-
-/*** FILE DESCRIPTOR WATCHERS ***/
-
-static void max_fd_func(gpointer key, gpointer value, gpointer data)
-{
- ObtMainLoop *loop = data;
-
- /* key is the fd */
- loop->fd_max = MAX(loop->fd_max, *(gint*)key);
-}
-
-static void calc_max_fd(ObtMainLoop *loop)
-{
- loop->fd_max = loop->fd_x;
-
- g_hash_table_foreach(loop->fd_handlers, max_fd_func, loop);
-}
-
-void obt_main_loop_fd_add(ObtMainLoop *loop,
- gint fd,
- ObtMainLoopFdHandler handler,
- gpointer data,
- GDestroyNotify notify)
-{
- ObtMainLoopFdHandlerType *h;
-
- h = g_slice_new(ObtMainLoopFdHandlerType);
- h->loop = loop;
- h->fd = fd;
- h->func = handler;
- h->data = data;
- h->destroy = notify;
-
- g_hash_table_replace(loop->fd_handlers, &h->fd, h);
- FD_SET(h->fd, &loop->fd_set);
- calc_max_fd(loop);
-}
-
-static void fd_handler_destroy(gpointer data)
-{
- ObtMainLoopFdHandlerType *h = data;
-
- FD_CLR(h->fd, &h->loop->fd_set);
-
- if (h->destroy)
- h->destroy(h->data);
- g_slice_free(ObtMainLoopFdHandlerType, h);
-}
-
-void obt_main_loop_fd_remove(ObtMainLoop *loop,
- gint fd)
-{
- g_hash_table_remove(loop->fd_handlers, &fd);
- calc_max_fd(loop);
-}
-
-/*** TIMEOUTS ***/
-
-#define NEAREST_TIMEOUT(loop) \
- (((ObtMainLoopTimer*)(loop)->timers->data)->timeout)
-
-static glong timecompare(GTimeVal *a, GTimeVal *b)
-{
- glong r;
- if ((r = a->tv_sec - b->tv_sec)) return r;
- return a->tv_usec - b->tv_usec;
-}
-
-static void insert_timer(ObtMainLoop *loop, ObtMainLoopTimer *ins)
-{
- GSList *it;
- for (it = loop->timers; it; it = g_slist_next(it)) {
- ObtMainLoopTimer *t = it->data;
- if (timecompare(&ins->timeout, &t->timeout) <= 0) {
- loop->timers = g_slist_insert_before(loop->timers, it, ins);
- break;
- }
- }
- if (it == NULL) /* didnt fit anywhere in the list */
- loop->timers = g_slist_append(loop->timers, ins);
-}
-
-void obt_main_loop_timeout_add(ObtMainLoop *loop,
- gulong microseconds,
- GSourceFunc handler,
- gpointer data,
- GEqualFunc cmp,
- GDestroyNotify notify)
-{
- ObtMainLoopTimer *t = g_slice_new(ObtMainLoopTimer);
-
- g_assert(microseconds > 0); /* if it's 0 it'll cause an infinite loop */
-
- t->delay = microseconds;
- t->func = handler;
- t->data = data;
- t->equal = cmp;
- t->destroy = notify;
- t->del_me = FALSE;
- g_get_current_time(&loop->now);
- t->last = t->timeout = loop->now;
- g_time_val_add(&t->timeout, t->delay);
-
- insert_timer(loop, t);
-}
-
-void obt_main_loop_timeout_remove(ObtMainLoop *loop,
- GSourceFunc handler)
-{
- GSList *it;
-
- for (it = loop->timers; it; it = g_slist_next(it)) {
- ObtMainLoopTimer *t = it->data;
- if (t->func == handler)
- t->del_me = TRUE;
- }
-}
-
-void obt_main_loop_timeout_remove_data(ObtMainLoop *loop, GSourceFunc handler,
- gpointer data, gboolean cancel_dest)
-{
- GSList *it;
-
- for (it = loop->timers; it; it = g_slist_next(it)) {
- ObtMainLoopTimer *t = it->data;
- if (t->func == handler && t->equal(t->data, data)) {
- t->del_me = TRUE;
- if (cancel_dest)
- t->destroy = NULL;
- }
- }
-}
-
-/* find the time to wait for the nearest timeout */
-static gboolean nearest_timeout_wait(ObtMainLoop *loop, GTimeVal *tm)
-{
- if (loop->timers == NULL)
- return FALSE;
-
- tm->tv_sec = NEAREST_TIMEOUT(loop).tv_sec - loop->now.tv_sec;
- tm->tv_usec = NEAREST_TIMEOUT(loop).tv_usec - loop->now.tv_usec;
-
- while (tm->tv_usec < 0) {
- tm->tv_usec += G_USEC_PER_SEC;
- tm->tv_sec--;
- }
- tm->tv_sec += tm->tv_usec / G_USEC_PER_SEC;
- tm->tv_usec %= G_USEC_PER_SEC;
- if (tm->tv_sec < 0)
- tm->tv_sec = 0;
-
- return TRUE;
-}
-
-static void timer_dispatch(ObtMainLoop *loop, GTimeVal **wait)
-{
- GSList *it, *next;
-
- gboolean fired = FALSE;
-
- g_get_current_time(&loop->now);
-
- for (it = loop->timers; it; it = next) {
- ObtMainLoopTimer *curr;
-
- next = g_slist_next(it);
-
- curr = it->data;
-
- /* since timer_stop doesn't actually free the timer, we have to do our
- real freeing in here.
- */
- if (curr->del_me) {
- /* delete the top */
- loop->timers = g_slist_delete_link(loop->timers, it);
- if (curr->destroy)
- curr->destroy(curr->data);
- g_slice_free(ObtMainLoopTimer, curr);
- continue;
- }
-
- /* the queue is sorted, so if this timer shouldn't fire, none are
- ready */
- if (timecompare(&NEAREST_TIMEOUT(loop), &loop->now) > 0)
- break;
-
- /* we set the last fired time to delay msec after the previous firing,
- then re-insert. timers maintain their order and may trigger more
- than once if they've waited more than one delay's worth of time.
- */
- loop->timers = g_slist_delete_link(loop->timers, it);
- g_time_val_add(&curr->last, curr->delay);
- if (curr->func(curr->data)) {
- g_time_val_add(&curr->timeout, curr->delay);
- insert_timer(loop, curr);
- } else {
- if (curr->destroy)
- curr->destroy(curr->data);
- g_slice_free(ObtMainLoopTimer, curr);
- }
-
- /* the timer queue has been shuffled, start from the beginning
- (which is the next one to fire) */
- next = loop->timers;
-
- fired = TRUE;
- }
-
- if (fired) {
- /* if at least one timer fires, then don't wait on X events, as there
- may already be some in the queue from the timer callbacks.
- */
- loop->ret_wait.tv_sec = loop->ret_wait.tv_usec = 0;
- *wait = &loop->ret_wait;
- } else if (nearest_timeout_wait(loop, &loop->ret_wait))
- *wait = &loop->ret_wait;
- else
- *wait = NULL;
-}
diff --git a/obt/mainloop.h b/obt/mainloop.h
deleted file mode 100644
index f455d629..00000000
--- a/obt/mainloop.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
- obt/mainloop.h for the Openbox window manager
- Copyright (c) 2006 Mikael Magnusson
- Copyright (c) 2003-2007 Dana Jansens
-
- 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 2 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.
-
- See the COPYING file for a copy of the GNU General Public License.
-*/
-
-#ifndef __obt_mainloop_h
-#define __obt_mainloop_h
-
-#include <X11/Xlib.h>
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-typedef struct _ObtMainLoop ObtMainLoop;
-
-ObtMainLoop *obt_main_loop_new(void);
-void obt_main_loop_ref(ObtMainLoop *loop);
-void obt_main_loop_unref(ObtMainLoop *loop);
-
-typedef void (*ObtMainLoopXHandler) (const XEvent *e, gpointer data);
-
-void obt_main_loop_x_add(ObtMainLoop *loop,
- ObtMainLoopXHandler handler,
- gpointer data,
- GDestroyNotify notify);
-void obt_main_loop_x_remove(ObtMainLoop *loop,
- ObtMainLoopXHandler handler);
-
-typedef void (*ObtMainLoopFdHandler) (gint fd, gpointer data);
-
-void obt_main_loop_fd_add(ObtMainLoop *loop,
- gint fd,
- ObtMainLoopFdHandler handler,
- gpointer data,
- GDestroyNotify notify);
-void obt_main_loop_fd_remove(ObtMainLoop *loop,
- gint fd);
-
-typedef void (*ObtMainLoopSignalHandler) (gint signal, gpointer data);
-
-void obt_main_loop_signal_add(ObtMainLoop *loop,
- gint signal,
- ObtMainLoopSignalHandler handler,
- gpointer data,
- GDestroyNotify notify);
-void obt_main_loop_signal_remove(ObtMainLoop *loop,
- ObtMainLoopSignalHandler handler);
-
-void obt_main_loop_timeout_add(ObtMainLoop *loop,
- gulong microseconds,
- GSourceFunc handler,
- gpointer data,
- GEqualFunc cmp,
- GDestroyNotify notify);
-void obt_main_loop_timeout_remove(ObtMainLoop *loop,
- GSourceFunc handler);
-void obt_main_loop_timeout_remove_data(ObtMainLoop *loop,
- GSourceFunc handler,
- gpointer data,
- gboolean cancel_dest);
-
-void obt_main_loop_run(ObtMainLoop *loop);
-void obt_main_loop_exit(ObtMainLoop *loop);
-
-G_END_DECLS
-
-#endif
diff --git a/obt/xevent.c b/obt/xevent.c
deleted file mode 100644
index 10771657..00000000
--- a/obt/xevent.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
- obt/xevent.c for the Openbox window manager
- Copyright (c) 2007 Dana Jansens
-
- 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 2 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.
-
- See the COPYING file for a copy of the GNU General Public License.
-*/
-
-#include "obt/xevent.h"
-#include "obt/mainloop.h"
-#include "obt/util.h"
-
-typedef struct _ObtXEventBinding ObtXEventBinding;
-
-struct _ObtXEventHandler
-{
- gint ref;
- ObtMainLoop *loop;
-
- /* An array of hash tables where the key is the window, and the value is
- the ObtXEventBinding */
- GHashTable **bindings;
- gint num_event_types; /* the length of the bindings array */
-};
-
-struct _ObtXEventBinding
-{
- Window win;
- ObtXEventCallback func;
- gpointer data;
-};
-
-static void xevent_handler(const XEvent *e, gpointer data);
-static guint window_hash(Window *w) { return *w; }
-static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
-static void binding_free(gpointer b);
-
-ObtXEventHandler* xevent_new(void)
-{
- ObtXEventHandler *h;
-
- h = g_slice_new0(ObtXEventHandler);
- h->ref = 1;
-
- return h;
-}
-
-void xevent_ref(ObtXEventHandler *h)
-{
- ++h->ref;
-}
-
-void xevent_unref(ObtXEventHandler *h)
-{
- if (h && --h->ref == 0) {
- gint i;
-
- if (h->loop)
- obt_main_loop_x_remove(h->loop, xevent_handler);
- for (i = 0; i < h->num_event_types; ++i)
- g_hash_table_destroy(h->bindings[i]);
- g_free(h->bindings);
-
- g_slice_free(ObtXEventHandler, h);
- }
-}
-
-void xevent_register(ObtXEventHandler *h, ObtMainLoop *loop)
-{
- h->loop = loop;
- obt_main_loop_x_add(loop, xevent_handler, h, NULL);
-}
-
-void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
- ObtXEventCallback func, gpointer data)
-{
- ObtXEventBinding *b;
-
- g_assert(func);
-
- /* make sure we have a spot for the event */
- if (type + 1 < h->num_event_types) {
- gint i;
- h->bindings = g_renew(GHashTable*, h->bindings, type + 1);
- for (i = h->num_event_types; i < type + 1; ++i)
- h->bindings[i] = g_hash_table_new_full((GHashFunc)window_hash,
- (GEqualFunc)window_comp,
- NULL, binding_free);
- h->num_event_types = type + 1;
- }
-
- b = g_slice_new(ObtXEventBinding);
- b->win = win;
- b->func = func;
- b->data = data;
- g_hash_table_replace(h->bindings[type], &b->win, b);
-}
-
-static void binding_free(gpointer b)
-{
- g_slice_free(ObtXEventBinding, b);
-}
-
-void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win)
-{
- g_assert(type < h->num_event_types);
- g_assert(win);
-
- g_hash_table_remove(h->bindings[type], &win);
-}
-
-static void xevent_handler(const XEvent *e, gpointer data)
-{
- ObtXEventHandler *h;
- ObtXEventBinding *b;
-
- h = data;
-
- if (e->type < h->num_event_types) {
- const gint all = OBT_XEVENT_ALL_WINDOWS;
- /* run the all_windows handler first */
- b = g_hash_table_lookup(h->bindings[e->xany.type], &all);
- if (b) b->func(e, b->data);
- /* then run the per-window handler */
- b = g_hash_table_lookup(h->bindings[e->xany.type], &e->xany.window);
- if (b) b->func(e, b->data);
- }
- else
- g_message("Unhandled X Event type %d", e->xany.type);
-}
diff --git a/obt/xevent.h b/obt/xevent.h
deleted file mode 100644
index ec0b66e5..00000000
--- a/obt/xevent.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
- obt/xevent.h for the Openbox window manager
- Copyright (c) 2007 Dana Jansens
-
- 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 2 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.
-
- See the COPYING file for a copy of the GNU General Public License.
-*/
-
-#ifndef __obt_xevent_h
-#define __obt_xevent_h
-
-#include <X11/Xlib.h>
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-struct _ObtMainLoop;
-
-typedef struct _ObtXEventHandler ObtXEventHandler;
-
-typedef void (*ObtXEventCallback) (const XEvent *e, gpointer data);
-
-ObtXEventHandler* xevent_new(void);
-void xevent_ref(ObtXEventHandler *h);
-void xevent_unref(ObtXEventHandler *h);
-
-void xevent_register(ObtXEventHandler *h,
- struct _ObtMainLoop *loop);
-
-#define OBT_XEVENT_ALL_WINDOWS None
-
-void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
- ObtXEventCallback func, gpointer data);
-void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win);
-
-G_END_DECLS
-
-#endif /*__obt_xevent_h*/
diff --git a/obt/xqueue.c b/obt/xqueue.c
index e5d2da31..22a3de23 100644
--- a/obt/xqueue.c
+++ b/obt/xqueue.c
@@ -318,3 +318,69 @@ 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(GIOChannel *s, GIOCondition cond, 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 */
+}
+
+void xqueue_listen(void)
+{
+ GIOChannel *ch;
+
+ g_assert(obt_display != NULL);
+
+ ch = g_io_channel_unix_new(ConnectionNumber(obt_display));
+ g_io_add_watch(ch, G_IO_IN, event_read, NULL);
+ g_io_channel_unref(ch);
+}
+
+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;
+ }
+ }
+}
diff --git a/obt/xqueue.h b/obt/xqueue.h
index 8b312785..11cd2bc0 100644
--- a/obt/xqueue.h
+++ b/obt/xqueue.h
@@ -87,6 +87,15 @@ gboolean xqueue_exists_local(xqueue_match_func match, gpointer data);
gboolean xqueue_remove_local(XEvent *event_return,
xqueue_match_func match, gpointer data);
+typedef void (*ObtXQueueFunc)(const XEvent *ev, gpointer data);
+
+/*! Begin listening for X events in the default GMainContext, and feed them
+ to the registered callback functions, added with xqueue_add_callback(). */
+void xqueue_listen(void);
+
+void xqueue_add_callback(ObtXQueueFunc f, gpointer data);
+void xqueue_remove_callback(ObtXQueueFunc f, gpointer data);
+
G_END_DECLS
#endif