Use GMainLoop instead of ObtMainLoop

This commit is contained in:
Dana Jansens 2010-06-08 17:50:23 -04:00
parent 2e94af28e4
commit fd77a0a7b3
22 changed files with 281 additions and 1136 deletions

View file

@ -134,8 +134,6 @@ obt_libobt_la_SOURCES = \
obt/internal.h \
obt/keyboard.h \
obt/keyboard.c \
obt/mainloop.h \
obt/mainloop.c \
obt/xml.h \
obt/xml.c \
obt/ddparse.h \
@ -147,8 +145,6 @@ obt_libobt_la_SOURCES = \
obt/prop.h \
obt/prop.c \
obt/util.h \
obt/xevent.h \
obt/xevent.c \
obt/xqueue.h \
obt/xqueue.c
@ -437,13 +433,11 @@ obtpubinclude_HEADERS = \
obt/link.h \
obt/display.h \
obt/keyboard.h \
obt/mainloop.h \
obt/xml.h \
obt/paths.h \
obt/prop.h \
obt/util.h \
obt/version.h \
obt/xevent.h \
obt/xqueue.h
nodist_pkgconfig_DATA = \

View file

@ -1,698 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
obt/mainloop.c for the Openbox window manager
Copyright (c) 2006 Mikael Magnusson
Copyright (c) 2003-2007 Dana Jansens
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
See the COPYING file for a copy of the GNU General Public License.
*/
#include "obt/mainloop.h"
#include "obt/display.h"
#include "obt/xqueue.h"
#include "obt/util.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
typedef struct _ObtMainLoopTimer ObtMainLoopTimer;
typedef struct _ObtMainLoopSignal ObtMainLoopSignal;
typedef struct _ObtMainLoopSignalHandlerType ObtMainLoopSignalHandlerType;
typedef struct _ObtMainLoopXHandlerType ObtMainLoopXHandlerType;
typedef struct _ObtMainLoopFdHandlerType ObtMainLoopFdHandlerType;
/* this should be more than the number of possible signals on any
architecture... */
#define NUM_SIGNALS 99
/* all created ObtMainLoops. Used by the signal handler to pass along
signals */
static GSList *all_loops;
/* signals are global to all loops */
static struct {
guint installed; /* a ref count */
struct sigaction oldact;
} all_signals[NUM_SIGNALS];
/* a set of all possible signals */
static sigset_t all_signals_set;
/* signals which cause a core dump, these can't be used for callbacks */
static gint core_signals[] =
{
SIGABRT,
SIGSEGV,
SIGFPE,
SIGILL,
SIGQUIT,
SIGTRAP,
SIGSYS,
SIGBUS,
SIGXCPU,
SIGXFSZ
};
#define NUM_CORE_SIGNALS (sizeof(core_signals) / sizeof(core_signals[0]))
static void sighandler(gint sig);
static void timer_dispatch(ObtMainLoop *loop, GTimeVal **wait);
static void fd_handler_destroy(gpointer data);
static void calc_max_fd(ObtMainLoop *loop);
struct _ObtMainLoop
{
gint ref;
Display *display;
gboolean run; /* do keep running */
gboolean running; /* is still running */
GSList *x_handlers;
gint fd_x; /* The X fd is a special case! */
gint fd_max;
GHashTable *fd_handlers;
fd_set fd_set;
GSList *timers;
GTimeVal now;
GTimeVal ret_wait;
gboolean signal_fired;
guint signals_fired[NUM_SIGNALS];
GSList *signal_handlers[NUM_SIGNALS];
};
struct _ObtMainLoopTimer
{
gulong delay;
GSourceFunc func;
gpointer data;
GEqualFunc equal;
GDestroyNotify destroy;
/* The timer needs to be freed */
gboolean del_me;
/* The time the last fire should've been at */
GTimeVal last;
/* When this timer will next trigger */
GTimeVal timeout;
/* Only allow a timer's function to fire once per run through the list,
so that it doesn't get locked in there forever */
gboolean fired;
};
struct _ObtMainLoopSignalHandlerType
{
ObtMainLoop *loop;
gint signal;
gpointer data;
ObtMainLoopSignalHandler func;
GDestroyNotify destroy;
};
struct _ObtMainLoopXHandlerType
{
ObtMainLoop *loop;
gpointer data;
ObtMainLoopXHandler func;
GDestroyNotify destroy;
};
struct _ObtMainLoopFdHandlerType
{
ObtMainLoop *loop;
gint fd;
gpointer data;
ObtMainLoopFdHandler func;
GDestroyNotify destroy;
};
ObtMainLoop *obt_main_loop_new(void)
{
ObtMainLoop *loop;
loop = g_slice_new0(ObtMainLoop);
loop->ref = 1;
FD_ZERO(&loop->fd_set);
loop->fd_x = -1;
loop->fd_max = -1;
loop->fd_handlers = g_hash_table_new_full(g_int_hash, g_int_equal,
NULL, fd_handler_destroy);
g_get_current_time(&loop->now);
/* only do this if we're the first loop created */
if (!all_loops) {
guint i;
struct sigaction action;
sigset_t sigset;
/* initialize the all_signals_set */
sigfillset(&all_signals_set);
sigemptyset(&sigset);
action.sa_handler = sighandler;
action.sa_mask = sigset;
action.sa_flags = SA_NOCLDSTOP;
/* grab all the signals that cause core dumps */
for (i = 0; i < NUM_CORE_SIGNALS; ++i) {
/* SIGABRT is curiously not grabbed here!! that's because when we
get one of the core_signals, we use abort() to dump the core.
And having the abort() only go back to our signal handler again
is less than optimal */
if (core_signals[i] != SIGABRT) {
sigaction(core_signals[i], &action,
&all_signals[core_signals[i]].oldact);
all_signals[core_signals[i]].installed++;
}
}
}
all_loops = g_slist_prepend(all_loops, loop);
return loop;
}
void obt_main_loop_ref(ObtMainLoop *loop)
{
++loop->ref;
}
void obt_main_loop_unref(ObtMainLoop *loop)
{
guint i;
GSList *it, *next;
if (loop && --loop->ref == 0) {
g_assert(loop->running == FALSE);
for (it = loop->x_handlers; it; it = next) {
ObtMainLoopXHandlerType *h = it->data;
next = g_slist_next(it);
obt_main_loop_x_remove(loop, h->func);
}
g_hash_table_destroy(loop->fd_handlers);
for (it = loop->timers; it; it = g_slist_next(it)) {
ObtMainLoopTimer *t = it->data;
if (t->destroy) t->destroy(t->data);
g_slice_free(ObtMainLoopTimer, t);
}
g_slist_free(loop->timers);
loop->timers = NULL;
for (i = 0; i < NUM_SIGNALS; ++i)
for (it = loop->signal_handlers[i]; it; it = next) {
ObtMainLoopSignalHandlerType *h = it->data;
next = g_slist_next(it);
obt_main_loop_signal_remove(loop, h->func);
}
all_loops = g_slist_remove(all_loops, loop);
/* only do this if we're the last loop destroyed */
if (!all_loops) {
/* grab all the signals that cause core dumps */
for (i = 0; i < NUM_CORE_SIGNALS; ++i) {
if (all_signals[core_signals[i]].installed) {
sigaction(core_signals[i],
&all_signals[core_signals[i]].oldact, NULL);
all_signals[core_signals[i]].installed--;
}
}
}
g_slice_free(ObtMainLoop, loop);
}
}
static void fd_handle_foreach(gpointer key,
gpointer value,
gpointer data)
{
ObtMainLoopFdHandlerType *h = value;
fd_set *set = data;
if (FD_ISSET(h->fd, set))
h->func(h->fd, h->data);
}
void obt_main_loop_run(ObtMainLoop *loop)
{
XEvent e;
struct timeval *wait;
fd_set selset;
GSList *it;
loop->run = TRUE;
loop->running = TRUE;
while (loop->run) {
if (loop->signal_fired) {
guint i;
sigset_t oldset;
/* block signals so that we can do this without the data changing
on us */
sigprocmask(SIG_SETMASK, &all_signals_set, &oldset);
for (i = 0; i < NUM_SIGNALS; ++i) {
while (loop->signals_fired[i]) {
for (it = loop->signal_handlers[i];
it; it = g_slist_next(it)) {
ObtMainLoopSignalHandlerType *h = it->data;
h->func(i, h->data);
}
loop->signals_fired[i]--;
}
}
loop->signal_fired = FALSE;
sigprocmask(SIG_SETMASK, &oldset, NULL);
} else if (loop->display && xqueue_pending_local()) {
while (xqueue_next_local(&e) && loop->run) {
if (e.type == MappingNotify)
XRefreshKeyboardMapping(&e.xmapping);
for (it = loop->x_handlers; it; it = g_slist_next(it)) {
ObtMainLoopXHandlerType *h = it->data;
h->func(&e, h->data);
}
}
} else {
/* this only runs if there were no x events received */
timer_dispatch(loop, (GTimeVal**)&wait);
selset = loop->fd_set;
/* there is a small race condition here. if a signal occurs
between this if() and the select() then we will not process
the signal until 'wait' expires. possible solutions include
using GStaticMutex, and having the signal handler set 'wait'
to 0 */
if (!loop->signal_fired)
select(loop->fd_max + 1, &selset, NULL, NULL, wait);
/* handle the X events with highest prioirity */
if (FD_ISSET(loop->fd_x, &selset))
continue;
g_hash_table_foreach(loop->fd_handlers,
fd_handle_foreach, &selset);
}
}
loop->running = FALSE;
}
void obt_main_loop_exit(ObtMainLoop *loop)
{
loop->run = FALSE;
}
/*** XEVENT WATCHERS ***/
void obt_main_loop_x_add(ObtMainLoop *loop,
ObtMainLoopXHandler handler,
gpointer data,
GDestroyNotify notify)
{
ObtMainLoopXHandlerType *h;
h = g_slice_new(ObtMainLoopXHandlerType);
h->loop = loop;
h->func = handler;
h->data = data;
h->destroy = notify;
if (!loop->x_handlers) {
g_assert(obt_display); /* is the display open? */
loop->display = obt_display;
loop->fd_x = ConnectionNumber(loop->display);
FD_SET(loop->fd_x, &loop->fd_set);
calc_max_fd(loop);
}
loop->x_handlers = g_slist_prepend(loop->x_handlers, h);
}
void obt_main_loop_x_remove(ObtMainLoop *loop,
ObtMainLoopXHandler handler)
{
GSList *it, *next;
for (it = loop->x_handlers; it; it = next) {
ObtMainLoopXHandlerType *h = it->data;
next = g_slist_next(it);
if (h->func == handler) {
loop->x_handlers = g_slist_delete_link(loop->x_handlers, it);
if (h->destroy) h->destroy(h->data);
g_slice_free(ObtMainLoopXHandlerType, h);
}
}
if (!loop->x_handlers) {
FD_CLR(loop->fd_x, &loop->fd_set);
calc_max_fd(loop);
}
}
/*** SIGNAL WATCHERS ***/
static void sighandler(gint sig)
{
GSList *it;
guint i;
g_return_if_fail(sig < NUM_SIGNALS);
for (i = 0; i < NUM_CORE_SIGNALS; ++i)
if (sig == core_signals[i]) {
/* XXX special case for signals that default to core dump.
but throw some helpful output here... */
fprintf(stderr, "How are you gentlemen? All your base are"
" belong to us. (Openbox received signal %d)\n", sig);
/* die with a core dump */
abort();
}
for (it = all_loops; it; it = g_slist_next(it)) {
ObtMainLoop *loop = it->data;
loop->signal_fired = TRUE;
loop->signals_fired[sig]++;
}
}
void obt_main_loop_signal_add(ObtMainLoop *loop,
gint signal,
ObtMainLoopSignalHandler handler,
gpointer data,
GDestroyNotify notify)
{
ObtMainLoopSignalHandlerType *h;
g_return_if_fail(signal < NUM_SIGNALS);
h = g_slice_new(ObtMainLoopSignalHandlerType);
h->loop = loop;
h->signal = signal;
h->func = handler;
h->data = data;
h->destroy = notify;
loop->signal_handlers[h->signal] =
g_slist_prepend(loop->signal_handlers[h->signal], h);
if (!all_signals[signal].installed) {
struct sigaction action;
sigset_t sigset;
sigemptyset(&sigset);
action.sa_handler = sighandler;
action.sa_mask = sigset;
action.sa_flags = SA_NOCLDSTOP;
sigaction(signal, &action, &all_signals[signal].oldact);
}
all_signals[signal].installed++;
}
void obt_main_loop_signal_remove(ObtMainLoop *loop,
ObtMainLoopSignalHandler handler)
{
guint i;
GSList *it, *next;
for (i = 0; i < NUM_SIGNALS; ++i) {
for (it = loop->signal_handlers[i]; it; it = next) {
ObtMainLoopSignalHandlerType *h = it->data;
next = g_slist_next(it);
if (h->func == handler) {
g_assert(all_signals[h->signal].installed > 0);
all_signals[h->signal].installed--;
if (!all_signals[h->signal].installed) {
sigaction(h->signal, &all_signals[h->signal].oldact, NULL);
}
loop->signal_handlers[i] =
g_slist_delete_link(loop->signal_handlers[i], it);
if (h->destroy) h->destroy(h->data);
g_slice_free(ObtMainLoopSignalHandlerType, h);
}
}
}
}
/*** FILE DESCRIPTOR WATCHERS ***/
static void max_fd_func(gpointer key, gpointer value, gpointer data)
{
ObtMainLoop *loop = data;
/* key is the fd */
loop->fd_max = MAX(loop->fd_max, *(gint*)key);
}
static void calc_max_fd(ObtMainLoop *loop)
{
loop->fd_max = loop->fd_x;
g_hash_table_foreach(loop->fd_handlers, max_fd_func, loop);
}
void obt_main_loop_fd_add(ObtMainLoop *loop,
gint fd,
ObtMainLoopFdHandler handler,
gpointer data,
GDestroyNotify notify)
{
ObtMainLoopFdHandlerType *h;
h = g_slice_new(ObtMainLoopFdHandlerType);
h->loop = loop;
h->fd = fd;
h->func = handler;
h->data = data;
h->destroy = notify;
g_hash_table_replace(loop->fd_handlers, &h->fd, h);
FD_SET(h->fd, &loop->fd_set);
calc_max_fd(loop);
}
static void fd_handler_destroy(gpointer data)
{
ObtMainLoopFdHandlerType *h = data;
FD_CLR(h->fd, &h->loop->fd_set);
if (h->destroy)
h->destroy(h->data);
g_slice_free(ObtMainLoopFdHandlerType, h);
}
void obt_main_loop_fd_remove(ObtMainLoop *loop,
gint fd)
{
g_hash_table_remove(loop->fd_handlers, &fd);
calc_max_fd(loop);
}
/*** TIMEOUTS ***/
#define NEAREST_TIMEOUT(loop) \
(((ObtMainLoopTimer*)(loop)->timers->data)->timeout)
static glong timecompare(GTimeVal *a, GTimeVal *b)
{
glong r;
if ((r = a->tv_sec - b->tv_sec)) return r;
return a->tv_usec - b->tv_usec;
}
static void insert_timer(ObtMainLoop *loop, ObtMainLoopTimer *ins)
{
GSList *it;
for (it = loop->timers; it; it = g_slist_next(it)) {
ObtMainLoopTimer *t = it->data;
if (timecompare(&ins->timeout, &t->timeout) <= 0) {
loop->timers = g_slist_insert_before(loop->timers, it, ins);
break;
}
}
if (it == NULL) /* didnt fit anywhere in the list */
loop->timers = g_slist_append(loop->timers, ins);
}
void obt_main_loop_timeout_add(ObtMainLoop *loop,
gulong microseconds,
GSourceFunc handler,
gpointer data,
GEqualFunc cmp,
GDestroyNotify notify)
{
ObtMainLoopTimer *t = g_slice_new(ObtMainLoopTimer);
g_assert(microseconds > 0); /* if it's 0 it'll cause an infinite loop */
t->delay = microseconds;
t->func = handler;
t->data = data;
t->equal = cmp;
t->destroy = notify;
t->del_me = FALSE;
g_get_current_time(&loop->now);
t->last = t->timeout = loop->now;
g_time_val_add(&t->timeout, t->delay);
insert_timer(loop, t);
}
void obt_main_loop_timeout_remove(ObtMainLoop *loop,
GSourceFunc handler)
{
GSList *it;
for (it = loop->timers; it; it = g_slist_next(it)) {
ObtMainLoopTimer *t = it->data;
if (t->func == handler)
t->del_me = TRUE;
}
}
void obt_main_loop_timeout_remove_data(ObtMainLoop *loop, GSourceFunc handler,
gpointer data, gboolean cancel_dest)
{
GSList *it;
for (it = loop->timers; it; it = g_slist_next(it)) {
ObtMainLoopTimer *t = it->data;
if (t->func == handler && t->equal(t->data, data)) {
t->del_me = TRUE;
if (cancel_dest)
t->destroy = NULL;
}
}
}
/* find the time to wait for the nearest timeout */
static gboolean nearest_timeout_wait(ObtMainLoop *loop, GTimeVal *tm)
{
if (loop->timers == NULL)
return FALSE;
tm->tv_sec = NEAREST_TIMEOUT(loop).tv_sec - loop->now.tv_sec;
tm->tv_usec = NEAREST_TIMEOUT(loop).tv_usec - loop->now.tv_usec;
while (tm->tv_usec < 0) {
tm->tv_usec += G_USEC_PER_SEC;
tm->tv_sec--;
}
tm->tv_sec += tm->tv_usec / G_USEC_PER_SEC;
tm->tv_usec %= G_USEC_PER_SEC;
if (tm->tv_sec < 0)
tm->tv_sec = 0;
return TRUE;
}
static void timer_dispatch(ObtMainLoop *loop, GTimeVal **wait)
{
GSList *it, *next;
gboolean fired = FALSE;
g_get_current_time(&loop->now);
for (it = loop->timers; it; it = next) {
ObtMainLoopTimer *curr;
next = g_slist_next(it);
curr = it->data;
/* since timer_stop doesn't actually free the timer, we have to do our
real freeing in here.
*/
if (curr->del_me) {
/* delete the top */
loop->timers = g_slist_delete_link(loop->timers, it);
if (curr->destroy)
curr->destroy(curr->data);
g_slice_free(ObtMainLoopTimer, curr);
continue;
}
/* the queue is sorted, so if this timer shouldn't fire, none are
ready */
if (timecompare(&NEAREST_TIMEOUT(loop), &loop->now) > 0)
break;
/* we set the last fired time to delay msec after the previous firing,
then re-insert. timers maintain their order and may trigger more
than once if they've waited more than one delay's worth of time.
*/
loop->timers = g_slist_delete_link(loop->timers, it);
g_time_val_add(&curr->last, curr->delay);
if (curr->func(curr->data)) {
g_time_val_add(&curr->timeout, curr->delay);
insert_timer(loop, curr);
} else {
if (curr->destroy)
curr->destroy(curr->data);
g_slice_free(ObtMainLoopTimer, curr);
}
/* the timer queue has been shuffled, start from the beginning
(which is the next one to fire) */
next = loop->timers;
fired = TRUE;
}
if (fired) {
/* if at least one timer fires, then don't wait on X events, as there
may already be some in the queue from the timer callbacks.
*/
loop->ret_wait.tv_sec = loop->ret_wait.tv_usec = 0;
*wait = &loop->ret_wait;
} else if (nearest_timeout_wait(loop, &loop->ret_wait))
*wait = &loop->ret_wait;
else
*wait = NULL;
}

View file

@ -1,81 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
obt/mainloop.h for the Openbox window manager
Copyright (c) 2006 Mikael Magnusson
Copyright (c) 2003-2007 Dana Jansens
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
See the COPYING file for a copy of the GNU General Public License.
*/
#ifndef __obt_mainloop_h
#define __obt_mainloop_h
#include <X11/Xlib.h>
#include <glib.h>
G_BEGIN_DECLS
typedef struct _ObtMainLoop ObtMainLoop;
ObtMainLoop *obt_main_loop_new(void);
void obt_main_loop_ref(ObtMainLoop *loop);
void obt_main_loop_unref(ObtMainLoop *loop);
typedef void (*ObtMainLoopXHandler) (const XEvent *e, gpointer data);
void obt_main_loop_x_add(ObtMainLoop *loop,
ObtMainLoopXHandler handler,
gpointer data,
GDestroyNotify notify);
void obt_main_loop_x_remove(ObtMainLoop *loop,
ObtMainLoopXHandler handler);
typedef void (*ObtMainLoopFdHandler) (gint fd, gpointer data);
void obt_main_loop_fd_add(ObtMainLoop *loop,
gint fd,
ObtMainLoopFdHandler handler,
gpointer data,
GDestroyNotify notify);
void obt_main_loop_fd_remove(ObtMainLoop *loop,
gint fd);
typedef void (*ObtMainLoopSignalHandler) (gint signal, gpointer data);
void obt_main_loop_signal_add(ObtMainLoop *loop,
gint signal,
ObtMainLoopSignalHandler handler,
gpointer data,
GDestroyNotify notify);
void obt_main_loop_signal_remove(ObtMainLoop *loop,
ObtMainLoopSignalHandler handler);
void obt_main_loop_timeout_add(ObtMainLoop *loop,
gulong microseconds,
GSourceFunc handler,
gpointer data,
GEqualFunc cmp,
GDestroyNotify notify);
void obt_main_loop_timeout_remove(ObtMainLoop *loop,
GSourceFunc handler);
void obt_main_loop_timeout_remove_data(ObtMainLoop *loop,
GSourceFunc handler,
gpointer data,
gboolean cancel_dest);
void obt_main_loop_run(ObtMainLoop *loop);
void obt_main_loop_exit(ObtMainLoop *loop);
G_END_DECLS
#endif

View file

@ -1,140 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
obt/xevent.c for the Openbox window manager
Copyright (c) 2007 Dana Jansens
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
See the COPYING file for a copy of the GNU General Public License.
*/
#include "obt/xevent.h"
#include "obt/mainloop.h"
#include "obt/util.h"
typedef struct _ObtXEventBinding ObtXEventBinding;
struct _ObtXEventHandler
{
gint ref;
ObtMainLoop *loop;
/* An array of hash tables where the key is the window, and the value is
the ObtXEventBinding */
GHashTable **bindings;
gint num_event_types; /* the length of the bindings array */
};
struct _ObtXEventBinding
{
Window win;
ObtXEventCallback func;
gpointer data;
};
static void xevent_handler(const XEvent *e, gpointer data);
static guint window_hash(Window *w) { return *w; }
static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
static void binding_free(gpointer b);
ObtXEventHandler* xevent_new(void)
{
ObtXEventHandler *h;
h = g_slice_new0(ObtXEventHandler);
h->ref = 1;
return h;
}
void xevent_ref(ObtXEventHandler *h)
{
++h->ref;
}
void xevent_unref(ObtXEventHandler *h)
{
if (h && --h->ref == 0) {
gint i;
if (h->loop)
obt_main_loop_x_remove(h->loop, xevent_handler);
for (i = 0; i < h->num_event_types; ++i)
g_hash_table_destroy(h->bindings[i]);
g_free(h->bindings);
g_slice_free(ObtXEventHandler, h);
}
}
void xevent_register(ObtXEventHandler *h, ObtMainLoop *loop)
{
h->loop = loop;
obt_main_loop_x_add(loop, xevent_handler, h, NULL);
}
void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
ObtXEventCallback func, gpointer data)
{
ObtXEventBinding *b;
g_assert(func);
/* make sure we have a spot for the event */
if (type + 1 < h->num_event_types) {
gint i;
h->bindings = g_renew(GHashTable*, h->bindings, type + 1);
for (i = h->num_event_types; i < type + 1; ++i)
h->bindings[i] = g_hash_table_new_full((GHashFunc)window_hash,
(GEqualFunc)window_comp,
NULL, binding_free);
h->num_event_types = type + 1;
}
b = g_slice_new(ObtXEventBinding);
b->win = win;
b->func = func;
b->data = data;
g_hash_table_replace(h->bindings[type], &b->win, b);
}
static void binding_free(gpointer b)
{
g_slice_free(ObtXEventBinding, b);
}
void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win)
{
g_assert(type < h->num_event_types);
g_assert(win);
g_hash_table_remove(h->bindings[type], &win);
}
static void xevent_handler(const XEvent *e, gpointer data)
{
ObtXEventHandler *h;
ObtXEventBinding *b;
h = data;
if (e->type < h->num_event_types) {
const gint all = OBT_XEVENT_ALL_WINDOWS;
/* run the all_windows handler first */
b = g_hash_table_lookup(h->bindings[e->xany.type], &all);
if (b) b->func(e, b->data);
/* then run the per-window handler */
b = g_hash_table_lookup(h->bindings[e->xany.type], &e->xany.window);
if (b) b->func(e, b->data);
}
else
g_message("Unhandled X Event type %d", e->xany.type);
}

View file

@ -1,48 +0,0 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
obt/xevent.h for the Openbox window manager
Copyright (c) 2007 Dana Jansens
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
See the COPYING file for a copy of the GNU General Public License.
*/
#ifndef __obt_xevent_h
#define __obt_xevent_h
#include <X11/Xlib.h>
#include <glib.h>
G_BEGIN_DECLS
struct _ObtMainLoop;
typedef struct _ObtXEventHandler ObtXEventHandler;
typedef void (*ObtXEventCallback) (const XEvent *e, gpointer data);
ObtXEventHandler* xevent_new(void);
void xevent_ref(ObtXEventHandler *h);
void xevent_unref(ObtXEventHandler *h);
void xevent_register(ObtXEventHandler *h,
struct _ObtMainLoop *loop);
#define OBT_XEVENT_ALL_WINDOWS None
void xevent_set_handler(ObtXEventHandler *h, gint type, Window win,
ObtXEventCallback func, gpointer data);
void xevent_remove_handler(ObtXEventHandler *h, gint type, Window win);
G_END_DECLS
#endif /*__obt_xevent_h*/

View file

@ -318,3 +318,69 @@ gboolean xqueue_pending_local(void)
if (!qnum) read_events(FALSE);
return qnum != 0;
}
typedef struct _ObtXQueueCB {
ObtXQueueFunc func;
gpointer data;
} ObtXQueueCB;
static ObtXQueueCB *callbacks = NULL;
static guint n_callbacks = 0;
static gboolean event_read(GIOChannel *s, GIOCondition cond, gpointer data)
{
XEvent ev;
while (xqueue_next_local(&ev)) {
guint i;
for (i = 0; i < n_callbacks; ++i)
callbacks[i].func(&ev, callbacks[i].data);
}
return TRUE; /* repeat */
}
void xqueue_listen(void)
{
GIOChannel *ch;
g_assert(obt_display != NULL);
ch = g_io_channel_unix_new(ConnectionNumber(obt_display));
g_io_add_watch(ch, G_IO_IN, event_read, NULL);
g_io_channel_unref(ch);
}
void xqueue_add_callback(ObtXQueueFunc f, gpointer data)
{
guint i;
g_return_if_fail(f != NULL);
for (i = 0; i < n_callbacks; ++i)
if (callbacks[i].func == f && callbacks[i].data == data)
return;
callbacks = g_renew(ObtXQueueCB, callbacks, n_callbacks + 1);
callbacks[n_callbacks].func = f;
callbacks[n_callbacks].data = data;
++n_callbacks;
}
void xqueue_remove_callback(ObtXQueueFunc f, gpointer data)
{
guint i;
g_return_if_fail(f != NULL);
for (i = 0; i < n_callbacks; ++i) {
if (callbacks[i].func == f && callbacks[i].data == data) {
/* remove it */
for (; i < n_callbacks - 1; ++i)
callbacks[i] = callbacks[i+1];
callbacks = g_renew(ObtXQueueCB, callbacks, n_callbacks - 1);
--n_callbacks;
break;
}
}
}

View file

@ -87,6 +87,15 @@ gboolean xqueue_exists_local(xqueue_match_func match, gpointer data);
gboolean xqueue_remove_local(XEvent *event_return,
xqueue_match_func match, gpointer data);
typedef void (*ObtXQueueFunc)(const XEvent *ev, gpointer data);
/*! Begin listening for X events in the default GMainContext, and feed them
to the registered callback functions, added with xqueue_add_callback(). */
void xqueue_listen(void);
void xqueue_add_callback(ObtXQueueFunc f, gpointer data);
void xqueue_remove_callback(ObtXQueueFunc f, gpointer data);
G_END_DECLS
#endif

View file

@ -33,6 +33,8 @@
ButtonMotionMask)
static ObDock *dock;
static guint show_timeout_id;
static guint hide_timeout_id;
StrutPartial dock_strut;
@ -628,15 +630,19 @@ static gboolean hide_timeout(gpointer data)
dock->hidden = TRUE;
dock_configure();
hide_timeout_id = 0;
return FALSE; /* don't repeat */
}
static gboolean show_timeout(gpointer data)
{
/* hide */
/* show */
dock->hidden = FALSE;
dock_configure();
show_timeout_id = 0;
return FALSE; /* don't repeat */
}
@ -644,21 +650,21 @@ void dock_hide(gboolean hide)
{
if (!hide) {
if (dock->hidden && config_dock_hide) {
obt_main_loop_timeout_add(ob_main_loop,
config_dock_show_delay * 1000,
show_timeout, NULL,
g_direct_equal, NULL);
} else if (!dock->hidden && config_dock_hide) {
obt_main_loop_timeout_remove(ob_main_loop, hide_timeout);
show_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
config_dock_show_delay,
show_timeout, NULL, NULL);
} else if (!dock->hidden && config_dock_hide && hide_timeout_id) {
if (hide_timeout_id) g_source_remove(hide_timeout_id);
hide_timeout_id = 0;
}
} else {
if (!dock->hidden && config_dock_hide) {
obt_main_loop_timeout_add(ob_main_loop,
config_dock_hide_delay * 1000,
hide_timeout, NULL,
g_direct_equal, NULL);
} else if (dock->hidden && config_dock_hide) {
obt_main_loop_timeout_remove(ob_main_loop, show_timeout);
hide_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
config_dock_show_delay,
hide_timeout, NULL, NULL);
} else if (dock->hidden && config_dock_hide && show_timeout_id) {
if (show_timeout_id) g_source_remove(show_timeout_id);
show_timeout_id = 0;
}
}
}

View file

@ -93,7 +93,7 @@ static gboolean is_enter_focus_event_ignored(gulong serial);
static void event_ignore_enter_range(gulong start, gulong end);
static void focus_delay_dest(gpointer data);
static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2);
static void unfocus_delay_dest(gpointer data);
static gboolean focus_delay_func(gpointer data);
static gboolean unfocus_delay_func(gpointer data);
static void focus_delay_client_dest(ObClient *client, gpointer data);
@ -112,25 +112,34 @@ static gboolean focus_left_screen = FALSE;
static gboolean waiting_for_focusin = FALSE;
/*! A list of ObSerialRanges which are to be ignored for mouse enter events */
static GSList *ignore_serials = NULL;
static guint focus_delay_timeout_id = 0;
static ObClient *focus_delay_timeout_client = NULL;
static guint unfocus_delay_timeout_id = 0;
static ObClient *unfocus_delay_timeout_client = NULL;
#ifdef USE_SM
static void ice_handler(gint fd, gpointer conn)
static gboolean ice_handler(GIOChannel *source, GIOCondition cond,
gpointer conn)
{
Bool b;
IceProcessMessages(conn, NULL, &b);
return TRUE; /* don't remove the event source */
}
static void ice_watch(IceConn conn, IcePointer data, Bool opening,
IcePointer *watch_data)
{
static gint fd = -1;
static guint id = 0;
if (opening) {
fd = IceConnectionNumber(conn);
obt_main_loop_fd_add(ob_main_loop, fd, ice_handler, conn, NULL);
} else {
obt_main_loop_fd_remove(ob_main_loop, fd);
fd = -1;
GIOChannel *ch;
ch = g_io_channel_unix_new(IceConnectionNumber(conn));
id = g_io_add_watch(ch, G_IO_IN, ice_handler, conn);
g_io_channel_unref(ch);
} else if (id) {
g_source_remove(id);
id = 0;
}
}
#endif
@ -139,7 +148,7 @@ void event_startup(gboolean reconfig)
{
if (reconfig) return;
obt_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
xqueue_add_callback(event_process, NULL);
#ifdef USE_SM
IceAddConnectionWatch(ice_watch, NULL);
@ -806,17 +815,20 @@ void event_enter_client(ObClient *client)
if (config_focus_delay) {
ObFocusDelayData *data;
obt_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
if (focus_delay_timeout_id)
g_source_remove(focus_delay_timeout_id);
data = g_slice_new(ObFocusDelayData);
data->client = client;
data->time = event_time();
data->serial = event_curserial;
obt_main_loop_timeout_add(ob_main_loop,
config_focus_delay * 1000,
focus_delay_func,
data, focus_delay_cmp, focus_delay_dest);
focus_delay_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
config_focus_delay,
focus_delay_func,
data,
focus_delay_dest);
focus_delay_timeout_client = client;
} else {
ObFocusDelayData data;
data.client = client;
@ -841,17 +853,20 @@ void event_leave_client(ObClient *client)
if (config_focus_delay) {
ObFocusDelayData *data;
obt_main_loop_timeout_remove(ob_main_loop, unfocus_delay_func);
if (unfocus_delay_timeout_id)
g_source_remove(unfocus_delay_timeout_id);
data = g_slice_new(ObFocusDelayData);
data->client = client;
data->time = event_time();
data->serial = event_curserial;
obt_main_loop_timeout_add(ob_main_loop,
config_focus_delay * 1000,
unfocus_delay_func,
data, focus_delay_cmp, focus_delay_dest);
unfocus_delay_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
config_focus_delay,
unfocus_delay_func,
data,
unfocus_delay_dest);
unfocus_delay_timeout_client = client;
} else {
ObFocusDelayData data;
data.client = client;
@ -1060,10 +1075,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
delay is up */
e->xcrossing.detail != NotifyInferior)
{
if (config_focus_delay)
obt_main_loop_timeout_remove_data(ob_main_loop,
focus_delay_func,
client, FALSE);
if (config_focus_delay && focus_delay_timeout_id)
g_source_remove(focus_delay_timeout_id);
if (config_unfocus_leave)
event_leave_client(client);
}
@ -1113,10 +1126,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
e->xcrossing.serial,
(client?client->window:0));
if (config_focus_follow) {
if (config_focus_delay)
obt_main_loop_timeout_remove_data(ob_main_loop,
unfocus_delay_func,
client, FALSE);
if (config_focus_delay && unfocus_delay_timeout_id)
g_source_remove(unfocus_delay_timeout_id);
event_enter_client(client);
}
}
@ -2047,12 +2058,15 @@ static gboolean event_handle_user_input(ObClient *client, XEvent *e)
static void focus_delay_dest(gpointer data)
{
g_slice_free(ObFocusDelayData, data);
focus_delay_timeout_id = 0;
focus_delay_timeout_client = NULL;
}
static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2)
static void unfocus_delay_dest(gpointer data)
{
const ObFocusDelayData *f1 = d1;
return f1->client == d2;
g_slice_free(ObFocusDelayData, data);
unfocus_delay_timeout_id = 0;
unfocus_delay_timeout_client = NULL;
}
static gboolean focus_delay_func(gpointer data)
@ -2082,18 +2096,18 @@ static gboolean unfocus_delay_func(gpointer data)
static void focus_delay_client_dest(ObClient *client, gpointer data)
{
obt_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func,
client, FALSE);
obt_main_loop_timeout_remove_data(ob_main_loop, unfocus_delay_func,
client, FALSE);
if (focus_delay_timeout_client == client && focus_delay_timeout_id)
g_source_remove(focus_delay_timeout_id);
if (unfocus_delay_timeout_client == client && unfocus_delay_timeout_id)
g_source_remove(unfocus_delay_timeout_id);
}
void event_halt_focus_delay(void)
{
/* ignore all enter events up till the event which caused this to occur */
if (event_curserial) event_ignore_enter_range(1, event_curserial);
obt_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
obt_main_loop_timeout_remove(ob_main_loop, unfocus_delay_func);
if (focus_delay_timeout_id) g_source_remove(focus_delay_timeout_id);
if (unfocus_delay_timeout_id) g_source_remove(unfocus_delay_timeout_id);
}
gulong event_start_ignore_all_enters(void)

View file

@ -41,7 +41,7 @@
EnterWindowMask | LeaveWindowMask)
#define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */
#define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */
#define FRAME_ANIMATE_ICONIFY_STEP_TIME (1000 / 60) /* 60 Hz */
#define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b)
@ -1060,8 +1060,8 @@ static gboolean find_reparent(XEvent *e, gpointer data)
void frame_release_client(ObFrame *self)
{
/* if there was any animation going on, kill it */
obt_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
self, FALSE);
if (self->iconify_animation_timer)
g_source_remove(self->iconify_animation_timer);
/* check if the app has already reparented its window away */
if (!xqueue_exists_local(find_reparent, self)) {
@ -1118,7 +1118,7 @@ void frame_release_client(ObFrame *self)
window_remove(self->rgriptop);
window_remove(self->rgripbottom);
obt_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self, TRUE);
if (self->flash_timer) g_source_remove(self->flash_timer);
}
/* is there anything present between us and the label? */
@ -1674,12 +1674,9 @@ void frame_flash_start(ObFrame *self)
self->flash_on = self->focused;
if (!self->flashing)
obt_main_loop_timeout_add(ob_main_loop,
G_USEC_PER_SEC * 0.6,
flash_timeout,
self,
g_direct_equal,
flash_done);
self->flash_timer = g_timeout_add_full(G_PRIORITY_DEFAULT,
600, flash_timeout, self,
flash_done);
g_get_current_time(&self->flash_end);
g_time_val_add(&self->flash_end, G_USEC_PER_SEC * 5);
@ -1837,12 +1834,13 @@ void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying)
}
if (new_anim) {
obt_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
self, FALSE);
obt_main_loop_timeout_add(ob_main_loop,
FRAME_ANIMATE_ICONIFY_STEP_TIME,
frame_animate_iconify, self,
g_direct_equal, NULL);
if (self->iconify_animation_timer)
g_source_remove(self->iconify_animation_timer);
self->iconify_animation_timer =
g_timeout_add_full(G_PRIORITY_DEFAULT,
FRAME_ANIMATE_ICONIFY_STEP_TIME,
frame_animate_iconify, self, NULL);
/* do the first step */
frame_animate_iconify(self);

View file

@ -190,12 +190,14 @@ struct _ObFrame
gboolean flashing;
gboolean flash_on;
GTimeVal flash_end;
guint flash_timer;
/*! Is the frame currently in an animation for iconify or restore.
0 means that it is not animating. > 0 means it is animating an iconify.
< 0 means it is animating a restore.
*/
gint iconify_animation_going;
guint iconify_animation_timer;
GTimeVal iconify_animation_end;
};

View file

@ -40,6 +40,7 @@
KeyBindingTree *keyboard_firstnode = NULL;
static ObPopup *popup = NULL;
static KeyBindingTree *curpos;
static guint chain_timer = 0;
static void grab_keys(gboolean grab)
{
@ -68,6 +69,11 @@ static gboolean chain_timeout(gpointer data)
return FALSE; /* don't repeat */
}
static void chain_done(gpointer data)
{
chain_timer = 0;
}
static void set_curpos(KeyBindingTree *newpos)
{
if (curpos == newpos) return;
@ -93,7 +99,7 @@ static void set_curpos(KeyBindingTree *newpos)
a = screen_physical_area_primary(FALSE);
popup_position(popup, NorthWestGravity, a->x + 10, a->y + 10);
/* 1 second delay for the popup to show */
popup_delay_show(popup, G_USEC_PER_SEC, text);
popup_delay_show(popup, 1000, text);
g_free(text);
} else {
popup_hide(popup);
@ -226,7 +232,7 @@ gboolean keyboard_event(ObClient *client, const XEvent *e)
if (e->xkey.keycode == config_keyboard_reset_keycode &&
mods == config_keyboard_reset_state)
{
obt_main_loop_timeout_remove(ob_main_loop, chain_timeout);
if (chain_timer) g_source_remove(chain_timer);
keyboard_reset_chains(-1);
return TRUE;
}
@ -243,11 +249,12 @@ gboolean keyboard_event(ObClient *client, const XEvent *e)
menu_frame_hide_all();
if (p->first_child != NULL) { /* part of a chain */
obt_main_loop_timeout_remove(ob_main_loop, chain_timeout);
if (chain_timer) g_source_remove(chain_timer);
/* 3 second timeout for chains */
obt_main_loop_timeout_add(ob_main_loop, 3 * G_USEC_PER_SEC,
chain_timeout, NULL,
g_direct_equal, NULL);
chain_timer =
g_timeout_add_full(G_PRIORITY_DEFAULT,
3000, chain_timeout, NULL,
chain_done);
set_curpos(p);
} else if (p->chroot) /* an empty chroot */
set_curpos(p);
@ -322,7 +329,7 @@ void keyboard_startup(gboolean reconfig)
void keyboard_shutdown(gboolean reconfig)
{
obt_main_loop_timeout_remove(ob_main_loop, chain_timeout);
if (chain_timer) g_source_remove(chain_timer);
keyboard_unbind_all();
set_curpos(NULL);

View file

@ -486,10 +486,10 @@ void menu_show(gchar *name, gint x, gint y, gboolean mouse, ObClient *client)
menu_can_hide = TRUE;
else {
menu_can_hide = FALSE;
obt_main_loop_timeout_add(ob_main_loop,
config_menu_hide_delay * 1000,
menu_hide_delay_func,
NULL, g_direct_equal, NULL);
g_timeout_add_full(G_PRIORITY_DEFAULT,
config_menu_hide_delay,
menu_hide_delay_func,
NULL, NULL);
}
}
}

View file

@ -44,6 +44,8 @@ GList *menu_frame_visible;
GHashTable *menu_frame_map;
static RrAppearance *a_sep;
static guint submenu_show_timer = 0;
static guint submenu_hide_timer = 0;
static ObMenuEntryFrame* menu_entry_frame_new(ObMenuEntry *entry,
ObMenuFrame *frame);
@ -1009,8 +1011,8 @@ gboolean menu_frame_show_topmenu(ObMenuFrame *self, gint x, gint y,
*/
static void remove_submenu_hide_timeout(ObMenuFrame *child)
{
obt_main_loop_timeout_remove_data(ob_main_loop, submenu_hide_timeout,
child, FALSE);
if (submenu_hide_timer) g_source_remove(submenu_hide_timer);
submenu_hide_timer = 0;
}
gboolean menu_frame_show_submenu(ObMenuFrame *self, ObMenuFrame *parent,
@ -1107,7 +1109,8 @@ void menu_frame_hide_all(void)
if (config_submenu_show_delay) {
/* remove any submenu open requests */
obt_main_loop_timeout_remove(ob_main_loop, submenu_show_timeout);
if (submenu_show_timer) g_source_remove(submenu_show_timer);
submenu_show_timer = 0;
}
if ((it = g_list_last(menu_frame_visible)))
menu_frame_hide(it->data);
@ -1188,7 +1191,8 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry,
if (config_submenu_show_delay) {
/* remove any submenu open requests */
obt_main_loop_timeout_remove(ob_main_loop, submenu_show_timeout);
if (submenu_show_timer) g_source_remove(submenu_show_timer);
submenu_show_timer = 0;
}
self->selected = entry;
@ -1208,12 +1212,13 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry,
submenu */
if (immediate || config_submenu_hide_delay == 0)
menu_frame_hide(oldchild);
else if (config_submenu_hide_delay > 0)
obt_main_loop_timeout_add(ob_main_loop,
config_submenu_hide_delay * 1000,
submenu_hide_timeout,
oldchild, g_direct_equal,
NULL);
else if (config_submenu_hide_delay > 0) {
if (submenu_hide_timer) g_source_remove(submenu_hide_timer);
submenu_hide_timer =
g_timeout_add_full(G_PRIORITY_DEFAULT,
config_submenu_hide_delay,
submenu_hide_timeout, oldchild, NULL);
}
}
}
@ -1225,12 +1230,15 @@ void menu_frame_select(ObMenuFrame *self, ObMenuEntryFrame *entry,
if (oldchild_entry != self->selected) {
if (immediate || config_submenu_hide_delay == 0)
menu_entry_frame_show_submenu(self->selected);
else if (config_submenu_hide_delay > 0)
obt_main_loop_timeout_add(ob_main_loop,
config_submenu_show_delay * 1000,
submenu_show_timeout,
self->selected, g_direct_equal,
NULL);
else if (config_submenu_hide_delay > 0) {
if (submenu_show_timer)
g_source_remove(submenu_show_timer);
submenu_show_timer =
g_timeout_add_full(G_PRIORITY_DEFAULT,
config_submenu_show_delay,
submenu_show_timeout,
self->selected, NULL);
}
}
/* hide the grandchildren of this menu. and move the cursor to
the current menu */

View file

@ -61,9 +61,11 @@ static guint button;
static guint32 corner;
static ObDirection edge_warp_dir = -1;
static gboolean edge_warp_odd = FALSE;
static guint edge_warp_timer = 0;
static ObDirection key_resize_edge = -1;
#ifdef SYNC
static guint waiting_for_sync;
static guint sync_timer = 0;
#endif
static ObPopup *popup = NULL;
@ -319,7 +321,8 @@ void moveresize_end(gboolean cancel)
moveresize_alarm = None;
}
obt_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
if (sync_timer) g_source_remove(sync_timer);
sync_timer = 0;
#endif
}
@ -433,10 +436,8 @@ static void do_resize(void)
waiting_for_sync = 1;
obt_main_loop_timeout_remove(ob_main_loop, sync_timeout_func);
obt_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC * 2,
sync_timeout_func,
NULL, NULL, NULL);
if (sync_timer) g_source_remove(sync_timer);
sync_timer = g_timeout_add(2000, sync_timeout_func, NULL);
}
#endif
@ -461,8 +462,10 @@ static gboolean sync_timeout_func(gpointer data)
++waiting_for_sync; /* we timed out waiting for our sync... */
do_resize(); /* ...so let any pending resizes through */
if (waiting_for_sync > SYNC_TIMEOUTS)
if (waiting_for_sync > SYNC_TIMEOUTS) {
sync_timer = 0;
return FALSE; /* don't repeat */
}
else
return TRUE; /* keep waiting */
}
@ -649,10 +652,8 @@ static void do_edge_warp(gint x, gint y)
cancel_edge_warp();
if (dir != (ObDirection)-1) {
edge_warp_odd = TRUE; /* switch on the first timeout */
obt_main_loop_timeout_add(ob_main_loop,
config_mouse_screenedgetime * 1000,
edge_warp_delay_func,
NULL, NULL, NULL);
edge_warp_timer = g_timeout_add(config_mouse_screenedgetime,
edge_warp_delay_func, NULL);
}
edge_warp_dir = dir;
}
@ -660,7 +661,8 @@ static void do_edge_warp(gint x, gint y)
static void cancel_edge_warp(void)
{
obt_main_loop_timeout_remove(ob_main_loop, edge_warp_delay_func);
if (edge_warp_timer) g_source_remove(edge_warp_timer);
edge_warp_timer = 0;
}
static void move_with_keys(KeySym sym, guint state)

View file

@ -46,6 +46,7 @@
#include "obrender/render.h"
#include "obrender/theme.h"
#include "obt/display.h"
#include "obt/xqueue.h"
#include "obt/prop.h"
#include "obt/keyboard.h"
#include "obt/xml.h"
@ -83,7 +84,7 @@
RrInstance *ob_rr_inst;
RrImageCache *ob_rr_icons;
RrTheme *ob_rr_theme;
ObtMainLoop *ob_main_loop;
GMainLoop *ob_main_loop;
gint ob_screen;
gboolean ob_replace_wm = FALSE;
gboolean ob_sm_use = TRUE;
@ -157,18 +158,18 @@ gint main(gint argc, gchar **argv)
exit(EXIT_SUCCESS);
}
ob_main_loop = obt_main_loop_new();
ob_main_loop = g_main_loop_new(NULL, FALSE);
/* set up signal handler */
obt_main_loop_signal_add(ob_main_loop, SIGUSR1, signal_handler, NULL,NULL);
obt_main_loop_signal_add(ob_main_loop, SIGUSR2, signal_handler, NULL,NULL);
obt_main_loop_signal_add(ob_main_loop, SIGTERM, signal_handler, NULL,NULL);
obt_main_loop_signal_add(ob_main_loop, SIGINT, signal_handler, NULL,NULL);
obt_main_loop_signal_add(ob_main_loop, SIGHUP, signal_handler, NULL,NULL);
obt_main_loop_signal_add(ob_main_loop, SIGPIPE, signal_handler, NULL,NULL);
obt_main_loop_signal_add(ob_main_loop, SIGCHLD, signal_handler, NULL,NULL);
obt_main_loop_signal_add(ob_main_loop, SIGTTIN, signal_handler, NULL,NULL);
obt_main_loop_signal_add(ob_main_loop, SIGTTOU, signal_handler, NULL,NULL);
// obt_main_loop_signal_add(ob_main_loop, SIGUSR1, signal_handler, NULL,NULL);
// obt_main_loop_signal_add(ob_main_loop, SIGUSR2, signal_handler, NULL,NULL);
// obt_main_loop_signal_add(ob_main_loop, SIGTERM, signal_handler, NULL,NULL);
// obt_main_loop_signal_add(ob_main_loop, SIGINT, signal_handler, NULL,NULL);
// obt_main_loop_signal_add(ob_main_loop, SIGHUP, signal_handler, NULL,NULL);
// obt_main_loop_signal_add(ob_main_loop, SIGPIPE, signal_handler, NULL,NULL);
// obt_main_loop_signal_add(ob_main_loop, SIGCHLD, signal_handler, NULL,NULL);
// obt_main_loop_signal_add(ob_main_loop, SIGTTIN, signal_handler, NULL,NULL);
// obt_main_loop_signal_add(ob_main_loop, SIGTTOU, signal_handler, NULL,NULL);
ob_screen = DefaultScreen(obt_display);
@ -316,6 +317,10 @@ gint main(gint argc, gchar **argv)
menu_startup(reconfigure);
prompt_startup(reconfigure);
/* do this after everything is started so no events will get
missed */
xqueue_listen();
if (!reconfigure) {
guint32 xid;
ObWindow *w;
@ -367,7 +372,7 @@ gint main(gint argc, gchar **argv)
}
}
obt_main_loop_run(ob_main_loop);
g_main_loop_run(ob_main_loop);
ob_set_state(reconfigure ?
OB_STATE_RECONFIGURING : OB_STATE_EXITING);
@ -741,14 +746,14 @@ void ob_reconfigure(void)
void ob_exit(gint code)
{
exitcode = code;
obt_main_loop_exit(ob_main_loop);
g_main_loop_quit(ob_main_loop);
}
void ob_exit_replace(void)
{
exitcode = 0;
being_replaced = TRUE;
obt_main_loop_exit(ob_main_loop);
g_main_loop_quit(ob_main_loop);
}
Cursor ob_cursor(ObCursor cursor)

View file

@ -23,7 +23,6 @@
#include "obrender/render.h"
#include "obrender/theme.h"
#include "obt/mainloop.h"
#include "obt/display.h"
#include <glib.h>
@ -32,7 +31,7 @@ extern RrInstance *ob_rr_inst;
extern RrImageCache *ob_rr_icons;
extern RrTheme *ob_rr_theme;
extern ObtMainLoop *ob_main_loop;
extern GMainLoop *ob_main_loop;
/*! The number of the screen on which we're running */
extern gint ob_screen;

View file

@ -22,7 +22,6 @@
#include "event.h"
#include "debug.h"
#include "openbox.h"
#include "obt/mainloop.h"
#include "obt/prop.h"
typedef struct _ObPingTarget
@ -30,13 +29,14 @@ typedef struct _ObPingTarget
ObClient *client;
ObPingEventHandler h;
guint32 id;
guint loopid;
gint waiting;
} ObPingTarget;
static GHashTable *ping_ids = NULL;
static guint32 ping_next_id = 1;
#define PING_TIMEOUT (G_USEC_PER_SEC * 3)
#define PING_TIMEOUT 3000 /* in MS */
/*! Warn the user after this many PING_TIMEOUT intervals */
#define PING_TIMEOUT_WARN 2
@ -79,8 +79,8 @@ void ping_start(struct _ObClient *client, ObPingEventHandler h)
t->client = client;
t->h = h;
obt_main_loop_timeout_add(ob_main_loop, PING_TIMEOUT, ping_timeout,
t, g_direct_equal, NULL);
t->loopid = g_timeout_add_full(G_PRIORITY_DEFAULT, PING_TIMEOUT,
ping_timeout, t, NULL);
/* act like we just timed out immediately, to start the pinging process
now instead of after the first delay. this makes sure the client
ends up in the ping_ids hash table now. */
@ -158,8 +158,7 @@ static void ping_end(ObClient *client, gpointer data)
if ((t = g_hash_table_find(ping_ids, find_client, client))) {
g_hash_table_remove(ping_ids, &t->id);
obt_main_loop_timeout_remove_data(ob_main_loop, ping_timeout,
t, FALSE);
g_source_remove(t->loopid);
g_slice_free(ObPingTarget, t);
}

View file

@ -146,11 +146,12 @@ static gboolean popup_show_timeout(gpointer data)
stacking_raise(INTERNAL_AS_WINDOW(self));
self->mapped = TRUE;
self->delay_mapped = FALSE;
self->delay_timer = 0;
return FALSE; /* don't repeat */
}
void popup_delay_show(ObPopup *self, gulong usec, gchar *text)
void popup_delay_show(ObPopup *self, gulong msec, gchar *text)
{
gint l, t, r, b;
gint x, y, w, h;
@ -292,12 +293,11 @@ void popup_delay_show(ObPopup *self, gulong usec, gchar *text)
/* do the actual showing */
if (!self->mapped) {
if (usec) {
if (msec) {
/* don't kill previous show timers */
if (!self->delay_mapped) {
obt_main_loop_timeout_add(ob_main_loop, usec,
popup_show_timeout, self,
g_direct_equal, NULL);
self->delay_timer =
g_timeout_add(msec, popup_show_timeout, self);
self->delay_mapped = TRUE;
}
} else {
@ -319,7 +319,8 @@ void popup_hide(ObPopup *self)
event_end_ignore_all_enters(ignore_start);
} else if (self->delay_mapped) {
obt_main_loop_timeout_remove_data(ob_main_loop, popup_show_timeout, self, FALSE);
g_source_remove(self->delay_timer);
self->delay_timer = 0;
self->delay_mapped = FALSE;
}
}
@ -365,7 +366,7 @@ void icon_popup_free(ObIconPopup *self)
}
}
void icon_popup_delay_show(ObIconPopup *self, gulong usec,
void icon_popup_delay_show(ObIconPopup *self, gulong msec,
gchar *text, RrImage *icon)
{
if (icon) {
@ -378,7 +379,7 @@ void icon_popup_delay_show(ObIconPopup *self, gulong usec,
self->a_icon->texture[0].type = RR_TEXTURE_NONE;
}
popup_delay_show(self->popup, usec, text);
popup_delay_show(self->popup, msec, text);
}
void icon_popup_icon_size_multiplier(ObIconPopup *self, guint wm, guint hm)
@ -528,7 +529,7 @@ void pager_popup_free(ObPagerPopup *self)
}
}
void pager_popup_delay_show(ObPagerPopup *self, gulong usec,
void pager_popup_delay_show(ObPagerPopup *self, gulong msec,
gchar *text, guint desk)
{
guint i;
@ -557,7 +558,7 @@ void pager_popup_delay_show(ObPagerPopup *self, gulong usec,
self->desks = screen_num_desktops;
self->curdesk = desk;
popup_delay_show(self->popup, usec, text);
popup_delay_show(self->popup, msec, text);
}
void pager_popup_icon_size_multiplier(ObPagerPopup *self, guint wm, guint hm)

View file

@ -53,6 +53,7 @@ struct _ObPopup
guint iconhm; /* icon height multiplier. multipled by the normal height */
gboolean mapped;
gboolean delay_mapped;
guint delay_timer;
void (*draw_icon)(gint x, gint y, gint w, gint h, gpointer data);
gpointer draw_icon_data;
@ -99,7 +100,7 @@ void popup_text_width_to_strings(ObPopup *self, gchar **strings, gint num);
void popup_set_text_align(ObPopup *self, RrJustify align);
#define popup_show(s, t) popup_delay_show((s),0,(t))
void popup_delay_show(ObPopup *self, gulong usec, gchar *text);
void popup_delay_show(ObPopup *self, gulong msec, gchar *text);
void popup_hide(ObPopup *self);
RrAppearance *popup_icon_appearance(ObPopup *self);
@ -109,7 +110,7 @@ ObIconPopup *icon_popup_new(void);
void icon_popup_free(ObIconPopup *self);
#define icon_popup_show(s, t, i) icon_popup_delay_show((s),0,(t),(i))
void icon_popup_delay_show(ObIconPopup *self, gulong usec,
void icon_popup_delay_show(ObIconPopup *self, gulong msec,
gchar *text, RrImage *icon);
#define icon_popup_hide(p) popup_hide((p)->popup)
#define icon_popup_position(p, g, x, y) popup_position((p)->popup,(g),(x),(y))
@ -128,7 +129,7 @@ ObPagerPopup *pager_popup_new(void);
void pager_popup_free(ObPagerPopup *self);
#define pager_popup_show(s, t, d) pager_popup_delay_show((s),0,(t),(d))
void pager_popup_delay_show(ObPagerPopup *self, gulong usec,
void pager_popup_delay_show(ObPagerPopup *self, gulong msec,
gchar *text, guint desk);
#define pager_popup_hide(p) popup_hide((p)->popup)
#define pager_popup_position(p, g, x, y) popup_position((p)->popup,(g),(x),(y))

View file

@ -38,7 +38,6 @@
#include "obt/display.h"
#include "obt/xqueue.h"
#include "obt/prop.h"
#include "obt/mainloop.h"
#include <X11/Xlib.h>
#ifdef HAVE_UNISTD_H
@ -71,6 +70,7 @@ Time screen_desktop_user_time = CurrentTime;
static Size screen_physical_size;
static guint screen_old_desktop;
static gboolean screen_desktop_timeout = TRUE;
static guint screen_desktop_timer = 0;
/*! An array of desktops, holding an array of areas per monitor */
static Rect *monitor_area = NULL;
/*! An array of desktops, holding an array of struts */
@ -80,11 +80,12 @@ static GSList *struts_right = NULL;
static GSList *struts_bottom = NULL;
static ObPagerPopup *desktop_popup;
static guint desktop_popup_timer = 0;
static gboolean desktop_popup_perm;
/*! The number of microseconds that you need to be on a desktop before it will
replace the remembered "last desktop" */
#define REMEMBER_LAST_DESKTOP_TIME 750000
#define REMEMBER_LAST_DESKTOP_TIME 750
static gboolean replace_wm(void)
{
@ -601,7 +602,8 @@ static void screen_fallback_focus(void)
static gboolean last_desktop_func(gpointer data)
{
screen_desktop_timeout = TRUE;
return FALSE;
screen_desktop_timer = 0;
return FALSE; /* don't repeat */
}
void screen_set_desktop(guint num, gboolean dofocus)
@ -683,9 +685,9 @@ void screen_set_desktop(guint num, gboolean dofocus)
}
}
screen_desktop_timeout = FALSE;
obt_main_loop_timeout_remove(ob_main_loop, last_desktop_func);
obt_main_loop_timeout_add(ob_main_loop, REMEMBER_LAST_DESKTOP_TIME,
last_desktop_func, NULL, NULL, NULL);
if (screen_desktop_timer) g_source_remove(screen_desktop_timer);
screen_desktop_timer = g_timeout_add(REMEMBER_LAST_DESKTOP_TIME,
last_desktop_func, NULL);
ob_debug("Moving to desktop %d", num+1);
@ -937,6 +939,7 @@ static guint translate_row_col(guint r, guint c)
static gboolean hide_desktop_popup_func(gpointer data)
{
pager_popup_hide(desktop_popup);
desktop_popup_timer = 0;
return FALSE; /* don't repeat */
}
@ -959,21 +962,21 @@ void screen_show_desktop_popup(guint d, gboolean perm)
MAX(a->width/3, POPUP_WIDTH));
pager_popup_show(desktop_popup, screen_desktop_names[d], d);
obt_main_loop_timeout_remove(ob_main_loop, hide_desktop_popup_func);
if (desktop_popup_timer) g_source_remove(desktop_popup_timer);
desktop_popup_timer = 0;
if (!perm && !desktop_popup_perm)
/* only hide if its not already being show permanently */
obt_main_loop_timeout_add(ob_main_loop,
config_desktop_popup_time * 1000,
hide_desktop_popup_func, desktop_popup,
g_direct_equal, NULL);
desktop_popup_timer = g_timeout_add(config_desktop_popup_time,
hide_desktop_popup_func,
desktop_popup);
if (perm)
desktop_popup_perm = TRUE;
}
void screen_hide_desktop_popup(void)
{
obt_main_loop_timeout_remove_data(ob_main_loop, hide_desktop_popup_func,
desktop_popup, FALSE);
if (desktop_popup_timer) g_source_remove(desktop_popup_timer);
desktop_popup_timer = 0;
pager_popup_hide(desktop_popup);
desktop_popup_perm = FALSE;
}

View file

@ -20,6 +20,7 @@
#include "startupnotify.h"
#include "gettext.h"
#include "event.h"
#include "obt/xqueue.h"
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
@ -67,7 +68,7 @@ void sn_startup(gboolean reconfig)
sn_event_func, NULL, NULL);
sn_launcher = sn_launcher_context_new(sn_display, ob_screen);
obt_main_loop_x_add(ob_main_loop, sn_handler, NULL, NULL);
xqueue_add_callback(sn_handler, NULL);
}
void sn_shutdown(gboolean reconfig)
@ -76,7 +77,7 @@ void sn_shutdown(gboolean reconfig)
if (reconfig) return;
obt_main_loop_x_remove(ob_main_loop, sn_handler);
xqueue_remove_callback(sn_handler, NULL);
for (it = sn_waits; it; it = g_slist_next(it))
sn_startup_sequence_unref((SnStartupSequence*)it->data);
@ -139,10 +140,9 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
sn_waits = g_slist_prepend(sn_waits, seq);
/* 20 second timeout for apps to start if the launcher doesn't
have a timeout */
obt_main_loop_timeout_add(ob_main_loop, 20 * G_USEC_PER_SEC,
sn_wait_timeout, seq,
g_direct_equal,
(GDestroyNotify)sn_startup_sequence_unref);
g_timeout_add_full(G_PRIORITY_DEFAULT,
20 * 1000, sn_wait_timeout, seq,
(GDestroyNotify)sn_startup_sequence_unref);
change = TRUE;
break;
case SN_MONITOR_EVENT_CHANGED:
@ -153,8 +153,7 @@ static void sn_event_func(SnMonitorEvent *ev, gpointer data)
case SN_MONITOR_EVENT_CANCELED:
if ((seq = sequence_find(sn_startup_sequence_get_id(seq)))) {
sn_waits = g_slist_remove(sn_waits, seq);
obt_main_loop_timeout_remove_data(ob_main_loop, sn_wait_timeout,
seq, FALSE);
g_source_remove_by_user_data(seq);
change = TRUE;
}
break;
@ -260,10 +259,9 @@ void sn_setup_spawn_environment(const gchar *program, const gchar *name,
/* 20 second timeout for apps to start */
sn_launcher_context_ref(sn_launcher);
obt_main_loop_timeout_add(ob_main_loop, 20 * G_USEC_PER_SEC,
sn_launch_wait_timeout, sn_launcher,
g_direct_equal,
(GDestroyNotify)sn_launcher_context_unref);
g_timeout_add_full(G_PRIORITY_DEFAULT,
20 * 1000, sn_launch_wait_timeout, sn_launcher,
(GDestroyNotify)sn_launcher_context_unref);
setenv("DESKTOP_STARTUP_ID", id, TRUE);