using the ObMainLoop, which rulz the planet

This commit is contained in:
Dana Jansens 2003-08-30 07:20:16 +00:00
parent 952ca24571
commit de4f92ccc6
14 changed files with 745 additions and 391 deletions

View 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 \

View 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);
}
}

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

View file

@ -11,12 +11,12 @@
#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>
@ -39,18 +39,12 @@
#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) {

View 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

View file

@ -30,6 +30,9 @@ gboolean grab_keyboard(gboolean grab)
XUngrabKeyboard(ob_display, event_lasttime);
ret = TRUE;
}
g_message("grabs: %d", kgrabs);
return ret;
}

View 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 {

601
openbox/mainloop.c Normal file
View file

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

52
openbox/mainloop.h Normal file
View file

@ -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

View 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)

View file

@ -14,9 +14,13 @@
#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;

View 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)

View file

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

View file

@ -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