using the ObMainLoop, which rulz the planet
authorDana Jansens <danakj@orodu.net>
Sat, 30 Aug 2003 07:20:16 +0000 (07:20 +0000)
committerDana Jansens <danakj@orodu.net>
Sat, 30 Aug 2003 07:20:16 +0000 (07:20 +0000)
14 files changed:
Makefile.am
openbox/dock.c
openbox/dock.h
openbox/event.c
openbox/event.h
openbox/grab.c
openbox/keyboard.c
openbox/mainloop.c [new file with mode: 0644]
openbox/mainloop.h [new file with mode: 0644]
openbox/openbox.c
openbox/openbox.h
openbox/screen.c
openbox/timer.c [deleted file]
openbox/timer.h [deleted file]

index edfb202..6d447a6 100644 (file)
@@ -146,6 +146,8 @@ openbox_openbox_SOURCES = \
        openbox/keyboard.h \
        openbox/keytree.c \
        openbox/keytree.h \
+       openbox/mainloop.c \
+       openbox/mainloop.h \
        openbox/menuframe.c \
        openbox/menuframe.h \
        openbox/menu.c \
@@ -174,8 +176,6 @@ openbox_openbox_SOURCES = \
        openbox/stacking.h \
        openbox/startup.c \
        openbox/startup.h \
-       openbox/timer.c \
-       openbox/timer.h \
        openbox/translate.c \
        openbox/translate.h \
        openbox/window.c \
index 07f2dbe..df176d6 100644 (file)
@@ -1,5 +1,6 @@
 #include "debug.h"
 #include "dock.h"
+#include "mainloop.h"
 #include "screen.h"
 #include "prop.h"
 #include "config.h"
@@ -522,15 +523,13 @@ void dock_app_drag(ObDockApp *app, XMotionEvent *e)
     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)
@@ -543,14 +542,9 @@ 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);
     }
 }
index f42a202..fbd5e16 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __dock_h
 #define __dock_h
 
-#include "timer.h"
 #include "window.h"
 #include "stacking.h"
 #include "geom.h"
@@ -28,7 +27,6 @@ struct _ObDock
     gint h;
 
     gboolean hidden;
-    ObTimer *hide_timer;
 
     GList *dock_apps;
 };
index 04e6514..92ebdfb 100644 (file)
 #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 || \
@@ -75,32 +69,38 @@ static const int mask_table[] = {
 };
 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]);
@@ -128,59 +128,20 @@ void event_startup()
        }
     }
 
-    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)
@@ -399,7 +360,7 @@ static gboolean event_ignore(XEvent *e, ObClient *client)
 #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 "
@@ -411,7 +372,7 @@ static gboolean event_ignore(XEvent *e, ObClient *client)
 
                     /* 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) {
@@ -457,13 +418,18 @@ static gboolean event_ignore(XEvent *e, ObClient *client)
     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 = &ee;
 
     window = event_get_window(e);
     if ((obwin = g_hash_table_lookup(window_map, &window))) {
@@ -1063,50 +1029,6 @@ static void event_handle_client(ObClient *client, XEvent *e)
     }
 }
 
-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) {
index 6aade18..0c6c7b9 100644 (file)
@@ -14,15 +14,4 @@ extern guint ScrollLockMask;
 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
index 549b0f1..2ef51fe 100644 (file)
@@ -30,6 +30,9 @@ gboolean grab_keyboard(gboolean grab)
             XUngrabKeyboard(ob_display, event_lasttime);
         ret = TRUE;
     }
+
+    g_message("grabs: %d", kgrabs);
+
     return ret;
 }
 
index 42eea89..86ead52 100644 (file)
@@ -1,3 +1,4 @@
+#include "mainloop.h"
 #include "focus.h"
 #include "screen.h"
 #include "frame.h"
@@ -7,7 +8,6 @@
 #include "client.h"
 #include "action.h"
 #include "prop.h"
-#include "timer.h"
 #include "config.h"
 #include "keytree.h"
 #include "keyboard.h"
@@ -27,7 +27,6 @@ typedef struct {
 static GSList *interactive_states;
 
 static KeyBindingTree *curpos;
-static ObTimer *chain_timer;
 
 static void grab_for_window(Window win, gboolean grab)
 {
@@ -62,23 +61,23 @@ static void grab_keys(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;
@@ -213,10 +212,10 @@ void keyboard_event(ObClient *client, const XEvent *e)
         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 {
diff --git a/openbox/mainloop.c b/openbox/mainloop.c
new file mode 100644 (file)
index 0000000..4b07cc4
--- /dev/null
@@ -0,0 +1,601 @@
+#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;
+}
diff --git a/openbox/mainloop.h b/openbox/mainloop.h
new file mode 100644 (file)
index 0000000..ecbcc38
--- /dev/null
@@ -0,0 +1,52 @@
+#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
index ca02d8b..5214696 100644 (file)
@@ -16,9 +16,9 @@
 #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"
@@ -49,6 +49,7 @@
 
 RrInstance *ob_rr_inst;
 RrTheme    *ob_rr_theme;
+ObMainLoop *ob_main_loop;
 Display    *ob_display;
 gint        ob_screen;
 gboolean    ob_sm_use = TRUE;
@@ -57,20 +58,17 @@ gboolean    ob_replace_wm;
 
 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;
@@ -88,19 +86,6 @@ int main(int argc, char **argv)
     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 |
@@ -128,6 +113,15 @@ int main(int argc, char **argv)
     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);
@@ -209,9 +203,6 @@ int main(int argc, char **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
@@ -246,8 +237,7 @@ int main(int argc, char **argv)
        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();
@@ -265,7 +255,6 @@ int main(int argc, char **argv)
         window_shutdown();
         grab_shutdown();
        event_shutdown();
-       timer_shutdown();
         config_shutdown();
     }
 
@@ -304,26 +293,14 @@ int main(int argc, char **argv)
     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();
     }
 }
 
@@ -418,7 +395,7 @@ void ob_restart()
 
 void ob_exit()
 {
-    shutdown = TRUE;
+    ob_main_loop_exit(ob_main_loop);
 }
 
 Cursor ob_cursor(ObCursor cursor)
index b5b473b..2f325df 100644 (file)
 #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; 
 
index 1eb0051..7913770 100644 (file)
@@ -1,11 +1,11 @@
 #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"
@@ -50,7 +50,6 @@ static Popup *desktop_cycle_popup;
 #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
@@ -1077,13 +1076,13 @@ static void set_root_cursor()
 }
 
 #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)
@@ -1104,26 +1103,20 @@ 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)
diff --git a/openbox/timer.c b/openbox/timer.c
deleted file mode 100644 (file)
index 33f4bab..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-#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;
-}
diff --git a/openbox/timer.h b/openbox/timer.h
deleted file mode 100644 (file)
index aa26c98..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#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