openbox/keyboard.h \
openbox/keytree.c \
openbox/keytree.h \
+ openbox/mainloop.c \
+ openbox/mainloop.h \
openbox/menuframe.c \
openbox/menuframe.h \
openbox/menu.c \
openbox/stacking.h \
openbox/startup.c \
openbox/startup.h \
- openbox/timer.c \
- openbox/timer.h \
openbox/translate.c \
openbox/translate.h \
openbox/window.c \
#include "debug.h"
#include "dock.h"
+#include "mainloop.h"
#include "screen.h"
#include "prop.h"
#include "config.h"
dock_configure();
}
-static void hide_timeout(void *n)
+static gboolean hide_timeout(gpointer data)
{
- /* dont repeat */
- timer_stop(dock->hide_timer);
- dock->hide_timer = NULL;
-
/* hide */
dock->hidden = TRUE;
dock_configure();
+
+ return FALSE; /* don't repeat */
}
void dock_hide(gboolean hide)
dock_configure();
/* if was hiding, stop it */
- if (dock->hide_timer) {
- timer_stop(dock->hide_timer);
- dock->hide_timer = NULL;
- }
+ ob_main_loop_timeout_remove(ob_main_loop, hide_timeout);
} else {
- g_assert(!dock->hide_timer);
- dock->hide_timer = timer_start(config_dock_hide_timeout * 1000,
- (ObTimeoutHandler)hide_timeout,
- NULL);
+ ob_main_loop_timeout_add(ob_main_loop, config_dock_hide_timeout * 1000,
+ hide_timeout, NULL, NULL);
}
}
#ifndef __dock_h
#define __dock_h
-#include "timer.h"
#include "window.h"
#include "stacking.h"
#include "geom.h"
gint h;
gboolean hidden;
- ObTimer *hide_timer;
GList *dock_apps;
};
#include "menuframe.h"
#include "keyboard.h"
#include "mouse.h"
+#include "mainloop.h"
#include "framerender.h"
#include "focus.h"
#include "moveresize.h"
#include "stacking.h"
#include "extensions.h"
-#include "timer.h"
#include "event.h"
#include <X11/Xlib.h>
#include <X11/ICE/ICElib.h>
#endif
-static void event_process(XEvent *e);
+static void event_process(const XEvent *e, gpointer data);
static void event_handle_root(XEvent *e);
static void event_handle_menu(XEvent *e);
static void event_handle_dock(ObDock *s, XEvent *e);
static void event_handle_dockapp(ObDockApp *app, XEvent *e);
static void event_handle_client(ObClient *c, XEvent *e);
-static void fd_event_handle();
-#ifdef USE_SM
-static void ice_watch(IceConn conn, IcePointer data, Bool opening,
- IcePointer *watch_data);
-#endif
-static void find_max_fd();
#define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
(e)->xfocus.detail == NotifyAncestor || \
};
static int mask_table_size;
-static fd_set selset, allset;
#ifdef USE_SM
-static IceConn ice_conn;
-static int ice_fd;
-#endif
-static int max_fd, x_fd;
-static GData *fd_handler_list;
-
+static void ice_handler(int fd, gpointer conn)
+{
+ Bool b;
+ IceProcessMessages(conn, NULL, &b);
+}
-#ifdef USE_SM
static void ice_watch(IceConn conn, IcePointer data, Bool opening,
IcePointer *watch_data)
{
+ static gint fd = -1;
+
if (opening) {
- g_assert (ice_fd < 0);
- ice_conn = conn;
- ice_fd = IceConnectionNumber(conn);
- FD_SET(ice_fd, &allset);
+ fd = IceConnectionNumber(conn);
+ ob_main_loop_fd_add(ob_main_loop, fd, ice_handler, conn, NULL);
} else {
- FD_CLR(ice_fd, &allset);
- ice_fd = -1;
+ ob_main_loop_fd_remove(ob_main_loop, fd);
+ fd = -1;
}
- find_max_fd();
}
#endif
+#ifdef USE_LIBSN
+static void sn_handler(const XEvent *e, gpointer display)
+{
+ XEvent ec;
+ ec = *e;
+ sn_display_process_event(display, &ec);
+}
+#endif
+
+
void event_startup()
{
mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
}
}
- FD_ZERO(&allset);
- max_fd = x_fd = ConnectionNumber(ob_display);
- FD_SET(x_fd, &allset);
+ ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
#ifdef USE_SM
- ice_fd = -1;
IceAddConnectionWatch(ice_watch, NULL);
#endif
- g_datalist_init(&fd_handler_list);
+#ifdef USE_LIBSN
+ ob_main_loop_x_add(ob_main_loop, sn_handler, ob_sn_display, NULL);
+#endif
}
void event_shutdown()
{
XFreeModifiermap(modmap);
- g_datalist_clear(&fd_handler_list);
-}
-
-void event_loop()
-{
- XEvent e;
- struct timeval *wait;
- gboolean had_event = FALSE;
-
- while (XPending(ob_display)) {
- XNextEvent(ob_display, &e);
-
-#ifdef USE_LIBSN
- sn_display_process_event(ob_sn_display, &e);
-#endif
-
- event_process(&e);
- had_event = TRUE;
- }
-
- if (!had_event) {
- timer_dispatch((GTimeVal**)&wait);
- selset = allset;
- select(max_fd + 1, &selset, NULL, NULL, wait);
-
- /* handle the X events as soon as possible? */
- if (FD_ISSET(x_fd, &selset))
- return;
-
-#ifdef USE_SM
- if (ice_fd >= 0 && FD_ISSET(ice_fd, &selset)) {
- Bool b;
- IceProcessMessages(ice_conn, NULL, &b);
- }
-#endif
-
- fd_event_handle();
- }
}
static Window event_get_window(XEvent *e)
#endif
return TRUE;
} else {
- event_process(&fe);
+ event_process(&fe, NULL);
#ifdef DEBUG_FOCUS
ob_debug("focused window got an Out/In back to "
"itself but focus_client was null "
/* once all the FocusOut's have been dealt with, if there
is a FocusIn still left and it is valid, then use it */
- event_process(&fe);
+ event_process(&fe, NULL);
/* secret magic way of event_process telling us that no
client was found for the FocusIn event. ^_^ */
if (fe.xfocus.window != None) {
return FALSE;
}
-static void event_process(XEvent *e)
+static void event_process(const XEvent *ec, gpointer data)
{
Window window;
ObClient *client = NULL;
ObDock *dock = NULL;
ObDockApp *dockapp = NULL;
ObWindow *obwin = NULL;
+ XEvent ee, *e;
+
+ /* make a copy we can mangle */
+ ee = *ec;
+ e = ⅇ
window = event_get_window(e);
if ((obwin = g_hash_table_lookup(window_map, &window))) {
}
}
-void event_add_fd_handler(event_fd_handler *h) {
- g_datalist_id_set_data(&fd_handler_list, h->fd, h);
- FD_SET(h->fd, &allset);
- max_fd = MAX(max_fd, h->fd);
-}
-
-static void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
-{
- *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
-}
-
-static void find_max_fd()
-{
- int tmpmax = -1;
- g_datalist_foreach(&fd_handler_list, find_max_fd_foreach,
- (gpointer)&tmpmax);
- max_fd = MAX(x_fd, tmpmax);
-#ifdef USE_SM
- max_fd = MAX(ice_fd, max_fd);
-#endif
-}
-
-void event_remove_fd(gint n)
-{
- FD_CLR(n, &allset);
- g_datalist_id_remove_data(&fd_handler_list, (GQuark)n);
- find_max_fd();
-}
-
-static void fd_event_handle_foreach(GQuark n,
- gpointer data, gpointer user_data)
-{
- if (FD_ISSET( (int)n, &selset)) {
- event_fd_handler *h = (event_fd_handler *)data;
- g_assert(h->fd == (int)n);
- h->handler(h->fd, h->data);
- }
-}
-
-static void fd_event_handle()
-{
- g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
-}
-
static void event_handle_dock(ObDock *s, XEvent *e)
{
switch (e->type) {
void event_startup();
void event_shutdown();
-typedef struct event_fd_handler {
- gint fd;
- gpointer data;
- void (*handler)(gint fd, gpointer data);
-} event_fd_handler;
-
-void event_add_fd_handler(event_fd_handler *handler);
-void event_remove_fd(gint n);
-
-void event_loop();
-
#endif
XUngrabKeyboard(ob_display, event_lasttime);
ret = TRUE;
}
+
+ g_message("grabs: %d", kgrabs);
+
return ret;
}
+#include "mainloop.h"
#include "focus.h"
#include "screen.h"
#include "frame.h"
#include "client.h"
#include "action.h"
#include "prop.h"
-#include "timer.h"
#include "config.h"
#include "keytree.h"
#include "keyboard.h"
static GSList *interactive_states;
static KeyBindingTree *curpos;
-static ObTimer *chain_timer;
static void grab_for_window(Window win, gboolean grab)
{
grab_for_window(((ObClient*)it->data)->frame->window, grab);
}
+static gboolean chain_timeout(gpointer data)
+{
+ keyboard_reset_chains();
+
+ return FALSE; /* don't repeat */
+}
+
void keyboard_reset_chains()
{
- if (chain_timer) {
- timer_stop(chain_timer);
- chain_timer = NULL;
- }
+ ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
+
if (curpos) {
curpos = NULL;
grab_keys(TRUE);
}
}
-static void chain_timeout(ObTimer *t, void *data)
-{
- keyboard_reset_chains();
-}
-
gboolean keyboard_bind(GList *keylist, ObAction *action)
{
KeyBindingTree *tree, *t;
if (p->key == e->xkey.keycode &&
p->state == e->xkey.state) {
if (p->first_child != NULL) { /* part of a chain */
- if (chain_timer) timer_stop(chain_timer);
+ ob_main_loop_timeout_remove(ob_main_loop, chain_timeout);
/* 5 second timeout for chains */
- chain_timer = timer_start(5000*1000, chain_timeout,
- NULL);
+ ob_main_loop_timeout_add(ob_main_loop, 5 * G_USEC_PER_SEC,
+ chain_timeout, NULL, NULL);
curpos = p;
grab_keys(TRUE);
} else {
--- /dev/null
+#include "mainloop.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/select.h>
+#include <signal.h>
+
+typedef struct _ObMainLoopTimer ObMainLoopTimer;
+typedef struct _ObMainLoopSignal ObMainLoopSignal;
+typedef struct _ObMainLoopSignalHandlerType ObMainLoopSignalHandlerType;
+typedef struct _ObMainLoopXHandlerType ObMainLoopXHandlerType;
+typedef struct _ObMainLoopFdHandlerType ObMainLoopFdHandlerType;
+
+/* this should be more than the number of possible signals on any
+ architecture... */
+#define NUM_SIGNALS 99
+
+/* all created ObMainLoops. Used by the signal handler to pass along signals */
+static GSList *all_loops;
+
+/* signals are global to all loops */
+struct {
+ guint installed; /* a ref count */
+ struct sigaction oldact;
+} all_signals[NUM_SIGNALS];
+
+/* a set of all possible signals */
+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(ObMainLoop *loop, GTimeVal **wait);
+static void fd_handler_destroy(gpointer data);
+
+struct _ObMainLoop
+{
+ 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 _ObMainLoopTimer
+{
+ gulong delay;
+ GSourceFunc func;
+ gpointer data;
+ 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;
+};
+
+struct _ObMainLoopSignalHandlerType
+{
+ ObMainLoop *loop;
+ gint signal;
+ gpointer data;
+ ObMainLoopSignalHandler func;
+ GDestroyNotify destroy;
+};
+
+struct _ObMainLoopXHandlerType
+{
+ ObMainLoop *loop;
+ gpointer data;
+ ObMainLoopXHandler func;
+ GDestroyNotify destroy;
+};
+
+struct _ObMainLoopFdHandlerType
+{
+ ObMainLoop *loop;
+ gint fd;
+ gpointer data;
+ ObMainLoopFdHandler func;
+ GDestroyNotify destroy;
+};
+
+ObMainLoop *ob_main_loop_new(Display *display)
+{
+ ObMainLoop *loop;
+
+ loop = g_new0(ObMainLoop, 1);
+ loop->display = display;
+ loop->fd_x = ConnectionNumber(display);
+ FD_ZERO(&loop->fd_set);
+ FD_SET(loop->fd_x, &loop->fd_set);
+ loop->fd_max = loop->fd_x;
+
+ 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 ob_main_loop_destroy(ObMainLoop *loop)
+{
+ guint i;
+ GSList *it, *next;
+
+ if (loop) {
+ g_assert(loop->running == FALSE);
+
+ for (it = loop->x_handlers; it; it = next) {
+ ObMainLoopXHandlerType *h = it->data;
+ next = g_slist_next(it);
+ ob_main_loop_x_remove(loop, h->func);
+ }
+
+ g_hash_table_destroy(loop->fd_handlers);
+
+ for (it = loop->timers; it; it = g_slist_next(it)) {
+ ObMainLoopTimer *t = it->data;
+ if (t->destroy) t->destroy(t->data);
+ g_free(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) {
+ ObMainLoopSignalHandlerType *h = it->data;
+ next = g_slist_next(it);
+ ob_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) {
+ guint i;
+
+ /* 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_free(loop);
+ }
+}
+
+static void fd_handle_foreach(gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ ObMainLoopFdHandlerType *h = value;
+ fd_set *set = data;
+
+ if (FD_ISSET(h->fd, set))
+ h->func(h->fd, h->data);
+}
+
+void ob_main_loop_run(ObMainLoop *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)) {
+ ObMainLoopSignalHandlerType *h = it->data;
+ h->func(i, h->data);
+ }
+ loop->signals_fired[i]--;
+ }
+ }
+ loop->signal_fired = FALSE;
+
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ } else if (XPending(loop->display)) {
+ do {
+ XNextEvent(loop->display, &e);
+
+ for (it = loop->x_handlers; it; it = g_slist_next(it)) {
+ ObMainLoopXHandlerType *h = it->data;
+ h->func(&e, h->data);
+ }
+ } while (XPending(loop->display));
+ } 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 ob_main_loop_exit(ObMainLoop *loop)
+{
+ loop->run = FALSE;
+}
+
+/*** XEVENT WATCHERS ***/
+
+void ob_main_loop_x_add(ObMainLoop *loop,
+ ObMainLoopXHandler handler,
+ gpointer data,
+ GDestroyNotify notify)
+{
+ ObMainLoopXHandlerType *h;
+
+ h = g_new(ObMainLoopXHandlerType, 1);
+ h->loop = loop;
+ h->func = handler;
+ h->data = data;
+ h->destroy = notify;
+ loop->x_handlers = g_slist_prepend(loop->x_handlers, h);
+}
+
+void ob_main_loop_x_remove(ObMainLoop *loop,
+ ObMainLoopXHandler handler)
+{
+ GSList *it, *next;
+
+ for (it = loop->x_handlers; it; it = next) {
+ ObMainLoopXHandlerType *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_free(h);
+ }
+ }
+}
+
+/*** 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, "Fuck ya. Core dump. (Signal=%d)\n", sig);
+
+ /* die with a core dump */
+ abort();
+ }
+
+ for (it = all_loops; it; it = g_slist_next(it)) {
+ ObMainLoop *loop = it->data;
+ loop->signal_fired = TRUE;
+ loop->signals_fired[sig]++;
+ }
+}
+
+void ob_main_loop_signal_add(ObMainLoop *loop,
+ gint signal,
+ ObMainLoopSignalHandler handler,
+ gpointer data,
+ GDestroyNotify notify)
+{
+ ObMainLoopSignalHandlerType *h;
+
+ g_return_if_fail(signal < NUM_SIGNALS);
+
+ h = g_new(ObMainLoopSignalHandlerType, 1);
+ 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 ob_main_loop_signal_remove(ObMainLoop *loop,
+ ObMainLoopSignalHandler handler)
+{
+ guint i;
+ GSList *it, *next;
+
+ for (i = 0; i < NUM_SIGNALS; ++i) {
+ for (it = loop->signal_handlers[i]; it; it = next) {
+ ObMainLoopSignalHandlerType *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_free(h);
+ }
+ }
+ }
+
+}
+
+/*** FILE DESCRIPTOR WATCHERS ***/
+
+static void max_fd_func(gpointer key, gpointer value, gpointer data)
+{
+ ObMainLoop *loop = data;
+
+ /* key is the fd */
+ loop->fd_max = MAX(loop->fd_max, *(gint*)key);
+}
+
+static void calc_max_fd(ObMainLoop *loop)
+{
+ loop->fd_max = loop->fd_x;
+
+ g_hash_table_foreach(loop->fd_handlers, max_fd_func, loop);
+}
+
+void ob_main_loop_fd_add(ObMainLoop *loop,
+ gint fd,
+ ObMainLoopFdHandler handler,
+ gpointer data,
+ GDestroyNotify notify)
+{
+ ObMainLoopFdHandlerType *h;
+
+ h = g_new(ObMainLoopFdHandlerType, 1);
+ 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)
+{
+ ObMainLoopFdHandlerType *h = data;
+
+ FD_CLR(h->fd, &h->loop->fd_set);
+
+ if (h->destroy)
+ h->destroy(h->data);
+}
+
+void ob_main_loop_fd_remove(ObMainLoop *loop,
+ gint fd)
+{
+ g_hash_table_remove(loop->fd_handlers, &fd);
+}
+
+/*** TIMEOUTS ***/
+
+#define NEAREST_TIMEOUT(loop) \
+ (((ObMainLoopTimer*)(loop)->timers->data)->timeout)
+
+static long timecompare(GTimeVal *a, GTimeVal *b)
+{
+ long r;
+
+ if ((r = b->tv_sec - a->tv_sec)) return r;
+ return b->tv_usec - a->tv_usec;
+
+}
+
+static void insert_timer(ObMainLoop *loop, ObMainLoopTimer *ins)
+{
+ GSList *it;
+ for (it = loop->timers; it; it = g_slist_next(it)) {
+ ObMainLoopTimer *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 ob_main_loop_timeout_add(ObMainLoop *loop,
+ gulong microseconds,
+ GSourceFunc handler,
+ gpointer data,
+ GDestroyNotify notify)
+{
+ ObMainLoopTimer *t = g_new(ObMainLoopTimer, 1);
+ t->delay = microseconds;
+ t->func = handler;
+ t->data = data;
+ t->destroy = notify;
+ t->del_me = FALSE;
+ t->last = t->timeout = loop->now;
+ g_time_val_add(&t->timeout, t->delay);
+
+ insert_timer(loop, t);
+}
+
+void ob_main_loop_timeout_remove(ObMainLoop *loop,
+ GSourceFunc handler)
+{
+ GSList *it;
+
+ for (it = loop->timers; it; it = g_slist_next(it)) {
+ ObMainLoopTimer *t = it->data;
+ if (t->func == handler) {
+ t->del_me = TRUE;
+ break;
+ }
+ }
+}
+
+/* find the time to wait for the nearest timeout */
+static gboolean nearest_timeout_wait(ObMainLoop *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(ObMainLoop *loop, GTimeVal **wait)
+{
+ g_get_current_time(&loop->now);
+
+ while (loop->timers != NULL) {
+ ObMainLoopTimer *curr = loop->timers->data; /* get the top element */
+ /* 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, loop->timers);
+ g_free(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, loop->timers);
+ 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);
+ }
+
+ /* 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;
+ return;
+ }
+
+ if (nearest_timeout_wait(loop, &loop->ret_wait))
+ *wait = &loop->ret_wait;
+ else
+ *wait = NULL;
+}
--- /dev/null
+#ifndef __ob__mainloop_h
+#define __ob__mainloop_h
+
+#include <X11/Xlib.h>
+#include <glib.h>
+
+typedef struct _ObMainLoop ObMainLoop;
+
+ObMainLoop *ob_main_loop_new(Display *display);
+void ob_main_loop_destroy(ObMainLoop *loop);
+
+typedef void (*ObMainLoopXHandler) (const XEvent *e, gpointer data);
+
+void ob_main_loop_x_add(ObMainLoop *loop,
+ ObMainLoopXHandler handler,
+ gpointer data,
+ GDestroyNotify notify);
+void ob_main_loop_x_remove(ObMainLoop *loop,
+ ObMainLoopXHandler handler);
+
+typedef void (*ObMainLoopFdHandler) (gint fd, gpointer data);
+
+void ob_main_loop_fd_add(ObMainLoop *loop,
+ gint fd,
+ ObMainLoopFdHandler handler,
+ gpointer data,
+ GDestroyNotify notify);
+void ob_main_loop_fd_remove(ObMainLoop *loop,
+ gint fd);
+
+typedef void (*ObMainLoopSignalHandler) (gint signal, gpointer data);
+
+void ob_main_loop_signal_add(ObMainLoop *loop,
+ gint signal,
+ ObMainLoopSignalHandler handler,
+ gpointer data,
+ GDestroyNotify notify);
+void ob_main_loop_signal_remove(ObMainLoop *loop,
+ ObMainLoopSignalHandler handler);
+
+void ob_main_loop_timeout_add(ObMainLoop *loop,
+ gulong microseconds,
+ GSourceFunc handler,
+ gpointer data,
+ GDestroyNotify notify);
+void ob_main_loop_timeout_remove(ObMainLoop *loop,
+ GSourceFunc handler);
+
+void ob_main_loop_run(ObMainLoop *loop);
+void ob_main_loop_exit(ObMainLoop *loop);
+
+#endif
#include "mouse.h"
#include "extensions.h"
#include "grab.h"
-#include "timer.h"
#include "group.h"
#include "config.h"
+#include "mainloop.h"
#include "gettext.h"
#include "parser/parse.h"
#include "render/render.h"
RrInstance *ob_rr_inst;
RrTheme *ob_rr_theme;
+ObMainLoop *ob_main_loop;
Display *ob_display;
gint ob_screen;
gboolean ob_sm_use = TRUE;
static ObState state;
static gboolean xsync;
-static gboolean shutdown;
static gboolean restart;
static char *restart_path;
static Cursor cursors[OB_NUM_CURSORS];
static KeyCode keys[OB_NUM_KEYS];
static gchar *sm_save_file;
-static void signal_handler(int signal);
+static void signal_handler(int signal, gpointer data);
static void parse_args(int argc, char **argv);
int main(int argc, char **argv)
{
- struct sigaction action;
- sigset_t sigset;
char *path;
xmlDocPtr doc;
xmlNodePtr node;
bind_textdomain_codeset(PACKAGE_NAME, "UTF-8");
textdomain(PACKAGE_NAME);
- /* set up signal handler */
- sigemptyset(&sigset);
- action.sa_handler = signal_handler;
- action.sa_mask = sigset;
- action.sa_flags = SA_NOCLDSTOP | SA_NODEFER;
- sigaction(SIGUSR1, &action, (struct sigaction *) NULL);
- sigaction(SIGPIPE, &action, (struct sigaction *) NULL);
-/* sigaction(SIGSEGV, &action, (struct sigaction *) NULL);*/
- sigaction(SIGFPE, &action, (struct sigaction *) NULL);
- sigaction(SIGTERM, &action, (struct sigaction *) NULL);
- sigaction(SIGINT, &action, (struct sigaction *) NULL);
- sigaction(SIGHUP, &action, (struct sigaction *) NULL);
-
/* create the ~/.openbox dir */
path = g_build_filename(g_get_home_dir(), ".openbox", NULL);
mkdir(path, (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP |
if (fcntl(ConnectionNumber(ob_display), F_SETFD, 1) == -1)
ob_exit_with_error("Failed to set display as close-on-exec.");
+ ob_main_loop = ob_main_loop_new(ob_display);
+
+ /* set up signal handler */
+ ob_main_loop_signal_add(ob_main_loop, SIGUSR1, signal_handler, NULL, NULL);
+ ob_main_loop_signal_add(ob_main_loop, SIGTERM, signal_handler, NULL, NULL);
+ ob_main_loop_signal_add(ob_main_loop, SIGINT, signal_handler, NULL, NULL);
+ ob_main_loop_signal_add(ob_main_loop, SIGHUP, signal_handler, NULL, NULL);
+ ob_main_loop_signal_add(ob_main_loop, SIGPIPE, signal_handler, NULL, NULL);
+
if (sm_save_file)
session_load(sm_save_file);
session_startup(argc, argv);
/* startup the parsing so everything can register sections of the rc */
i = parse_startup();
- /* anything that is going to read data from the rc file needs to be
- in this group */
- timer_startup();
event_startup();
grab_startup();
/* focus_backup is used for stacking, so this needs to come before
client_manage_all();
state = OB_STATE_RUNNING;
- while (!shutdown)
- event_loop();
+ ob_main_loop_run(ob_main_loop);
state = OB_STATE_EXITING;
dock_remove_all();
window_shutdown();
grab_shutdown();
event_shutdown();
- timer_shutdown();
config_shutdown();
}
return 0;
}
-static void signal_handler(int sig)
+static void signal_handler(int signal, gpointer data)
{
- switch (sig) {
- case SIGUSR1:
- fprintf(stderr, "Caught SIGUSR1 signal. Restarting.");
+ if (signal == SIGUSR1) {
+ fprintf(stderr, "Caught signal %d. Restarting.\n", signal);
ob_restart();
- break;
-
- case SIGHUP:
- case SIGINT:
- case SIGTERM:
- case SIGPIPE:
- fprintf(stderr, "Caught signal %d. Exiting.", sig);
+ } else {
+ fprintf(stderr, "Caught signal %d. Exiting.\n", signal);
ob_exit();
- break;
-
- case SIGFPE:
- case SIGSEGV:
- fprintf(stderr, "Caught signal %d. Aborting and dumping core.", sig);
- abort();
}
}
void ob_exit()
{
- shutdown = TRUE;
+ ob_main_loop_exit(ob_main_loop);
}
Cursor ob_cursor(ObCursor cursor)
#include <glib.h>
#include <X11/Xlib.h>
+struct _ObMainLoop;
+
extern RrInstance *ob_rr_inst;
extern RrTheme *ob_rr_theme;
+extern struct _ObMainLoop *ob_main_loop;
+
/*! The X display */
extern Display *ob_display;
#include "debug.h"
#include "openbox.h"
+#include "mainloop.h"
#include "dock.h"
#include "xerror.h"
#include "prop.h"
#include "startup.h"
#include "grab.h"
-#include "timer.h"
#include "config.h"
#include "screen.h"
#include "client.h"
#ifdef USE_LIBSN
static SnMonitorContext *sn_context;
static int sn_busy_cnt;
-static ObTimer *sn_timer;
static void sn_event_func(SnMonitorEvent *event, void *data);
#endif
}
#ifdef USE_LIBSN
-static void sn_timeout(ObTimer *t, void *data)
+static gboolean sn_timeout(gpointer data)
{
- timer_stop(sn_timer);
- sn_timer = NULL;
sn_busy_cnt = 0;
set_root_cursor();
+
+ return FALSE; /* don't repeat */
}
static void sn_event_func(SnMonitorEvent *ev, void *data)
switch (sn_monitor_event_get_type(ev)) {
case SN_MONITOR_EVENT_INITIATED:
++sn_busy_cnt;
- if (sn_timer)
- timer_stop(sn_timer);
+ ob_main_loop_timeout_remove(ob_main_loop, sn_timeout);
/* 30 second timeout for apps to start */
- sn_timer = timer_start(30 * 1000000, sn_timeout, NULL);
+ ob_main_loop_timeout_add(ob_main_loop, 30 * G_USEC_PER_SEC,
+ sn_timeout, NULL, NULL);
break;
case SN_MONITOR_EVENT_CHANGED:
break;
case SN_MONITOR_EVENT_COMPLETED:
if (sn_busy_cnt) --sn_busy_cnt;
- if (sn_timer) {
- timer_stop(sn_timer);
- sn_timer = NULL;
- }
+ ob_main_loop_timeout_remove(ob_main_loop, sn_timeout);
break;
case SN_MONITOR_EVENT_CANCELED:
if (sn_busy_cnt) --sn_busy_cnt;
- if (sn_timer) {
- timer_stop(sn_timer);
- sn_timer = NULL;
- }
+ ob_main_loop_timeout_remove(ob_main_loop, sn_timeout);
};
if (sn_busy_cnt != cnt)
+++ /dev/null
-#include "timer.h"
-
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-
-static GTimeVal now;
-static GTimeVal ret_wait;
-static GSList *timers; /* nearest timer is at the top */
-
-#define NEAREST_TIMEOUT (((ObTimer*)timers->data)->timeout)
-
-static long timecompare(GTimeVal *a, GTimeVal *b)
-{
- long r;
-
- if ((r = b->tv_sec - a->tv_sec)) return r;
- return b->tv_usec - a->tv_usec;
-
-}
-
-static void insert_timer(ObTimer *self)
-{
- GSList *it;
- for (it = timers; it != NULL; it = it->next) {
- ObTimer *t = it->data;
- if (timecompare(&self->timeout, &t->timeout) <= 0) {
- timers = g_slist_insert_before(timers, it, self);
- break;
- }
- }
- if (it == NULL) /* didnt fit anywhere in the list */
- timers = g_slist_append(timers, self);
-}
-
-void timer_startup()
-{
- g_get_current_time(&now);
- timers = NULL;
-}
-
-void timer_shutdown()
-{
- GSList *it;
- for (it = timers; it != NULL; it = it->next) {
- g_free(it->data);
- }
- g_slist_free(timers);
- timers = NULL;
-}
-
-ObTimer *timer_start(long delay, ObTimeoutHandler cb, void *data)
-{
- ObTimer *self = g_new(ObTimer, 1);
- self->delay = delay;
- self->action = cb;
- self->data = data;
- self->del_me = FALSE;
- g_get_current_time(&now);
- self->last = self->timeout = now;
- g_time_val_add(&self->timeout, delay);
-
- insert_timer(self);
-
- return self;
-}
-
-void timer_stop(ObTimer *self)
-{
- self->del_me = TRUE;
-}
-
-/* find the time to wait for the nearest timeout */
-static gboolean nearest_timeout_wait(GTimeVal *tm)
-{
- if (timers == NULL)
- return FALSE;
-
- tm->tv_sec = NEAREST_TIMEOUT.tv_sec - now.tv_sec;
- tm->tv_usec = NEAREST_TIMEOUT.tv_usec - 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;
-}
-
-
-void timer_dispatch(GTimeVal **wait)
-{
- g_get_current_time(&now);
-
- while (timers != NULL) {
- ObTimer *curr = timers->data; /* get the top element */
- /* since timer_stop doesn't actually free the timer, we have to do our
- real freeing in here.
- */
- if (curr->del_me) {
- timers = g_slist_delete_link(timers, timers); /* delete the top */
- g_free(curr);
- continue;
- }
-
- /* the queue is sorted, so if this timer shouldn't fire, none are
- ready */
- if (timecompare(&NEAREST_TIMEOUT, &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.
- */
- timers = g_slist_delete_link(timers, timers);
- g_time_val_add(&curr->last, curr->delay);
- curr->action(curr, curr->data);
- g_time_val_add(&curr->timeout, curr->delay);
- insert_timer(curr);
-
- /* 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.
- */
- ret_wait.tv_sec = ret_wait.tv_usec = 0;
- *wait = &ret_wait;
- return;
- }
-
- if (nearest_timeout_wait(&ret_wait))
- *wait = &ret_wait;
- else
- *wait = NULL;
-}
+++ /dev/null
-#ifndef __timer_h
-#define __timer_h
-
-#include <glib.h>
-
-typedef struct _ObTimer ObTimer;
-
-/*! Data type of Timer callback */
-typedef void (*ObTimeoutHandler)(ObTimer *t, void *data);
-
-struct _ObTimer
-{
- /*! Microseconds between timer firings */
- long delay;
- /*! Callback for timer expiry */
- ObTimeoutHandler action;
- /*! Data sent to callback */
- void *data;
- /*! We overload the delete operator to just set this to true */
- gboolean del_me;
- /*! The time the last fire should've been at */
- GTimeVal last;
- /*! When this timer will next trigger */
- GTimeVal timeout;
-};
-
-/*! Initializes the timer subsection */
-void timer_startup();
-/*! Destroys the timer subsection */
-void timer_shutdown();
-
-/* Creates a new timer with a given delay */
-ObTimer *timer_start(long delay, ObTimeoutHandler cb, void *data);
-/* Stops and frees a timer */
-void timer_stop(ObTimer *self);
-
-/*! Dispatch all pending timers. Sets wait to the amount of time to wait for
- the next timer, or NULL if there are no timers to wait for */
-void timer_dispatch(GTimeVal **wait);
-
-#endif