diff options
Diffstat (limited to 'obt')
| -rw-r--r-- | obt/mainloop.c | 698 | ||||
| -rw-r--r-- | obt/mainloop.h | 81 | ||||
| -rw-r--r-- | obt/xevent.c | 140 | ||||
| -rw-r--r-- | obt/xevent.h | 48 | ||||
| -rw-r--r-- | obt/xqueue.c | 66 | ||||
| -rw-r--r-- | obt/xqueue.h | 9 |
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 |
