obt/prop.c \
obt/util.h \
obt/xevent.h \
- obt/xevent.c
+ obt/xevent.c \
+ obt/xqueue.h \
+ obt/xqueue.c
## openbox ##
obt/prop.h \
obt/util.h \
obt/version.h \
- obt/xevent.h
+ obt/xevent.h \
+ obt/xqueue.h
nodist_pkgconfig_DATA = \
obrender/obrender-3.5.pc \
#include "obt/prop.h"
#include "obt/internal.h"
#include "obt/keyboard.h"
+#include "obt/xqueue.h"
#ifdef HAVE_STRING_H
# include <string.h>
# include <unistd.h>
#endif
+/* from xqueue.c */
+extern void xqueue_init(void);
+extern void xqueue_destroy(void);
+
Display* obt_display = NULL;
gboolean obt_display_error_occured = FALSE;
}
g_free(n);
+ if (obt_display)
+ xqueue_init();
+
return obt_display != NULL;
}
void obt_display_close(void)
{
obt_keyboard_shutdown();
- if (obt_display) XCloseDisplay(obt_display);
+ if (obt_display) {
+ xqueue_destroy();
+ XCloseDisplay(obt_display);
+ }
}
static gint xerror_handler(Display *d, XErrorEvent *e)
#include "obt/mainloop.h"
#include "obt/display.h"
+#include "obt/xqueue.h"
#include "obt/util.h"
#ifdef HAVE_STDIO_H
loop->signal_fired = FALSE;
sigprocmask(SIG_SETMASK, &oldset, NULL);
- } else if (loop->display && XPending(loop->display)) {
- do {
- XNextEvent(loop->display, &e);
-
+ } else if (loop->display && xqueue_pending_local()) {
+ while (xqueue_next_local(&e) && loop->run) {
if (e.type == MappingNotify)
XRefreshKeyboardMapping(&e.xmapping);
ObtMainLoopXHandlerType *h = it->data;
h->func(&e, h->data);
}
- } while (XPending(loop->display) && loop->run);
+ }
} else {
/* this only runs if there were no x events received */
-
timer_dispatch(loop, (GTimeVal**)&wait);
selset = loop->fd_set;
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/display.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/xqueue.h"
+#include "obt/display.h"
+
+#define MINSZ 16
+
+static XEvent *q = NULL;
+static gulong qsz = 0;
+static gulong qstart; /* the first event in the queue */
+static gulong qend; /* the last event in the queue */
+static gulong qnum = 0;
+
+static inline void shrink(void) {
+ if (qsz > MINSZ && qnum < qsz / 4) {
+ const gulong newsz = qsz/2;
+ gulong i;
+
+ if (qnum == 0) {
+ qstart = 0;
+ qend = -1;
+ }
+
+ /* all in the shinking part, move it to pos 0 */
+ else if (qstart >= newsz && qend >= newsz) {
+ for (i = 0; i < qnum; ++i)
+ q[i] = q[qstart+i];
+ qstart = 0;
+ qend = qnum - 1;
+ }
+
+ /* it wraps around to 0 right now, move the part between newsz and qsz
+ to be before newsz */
+ else if (qstart >= newsz) {
+ const gulong n = qsz - qstart;
+ for (i = 0; i < n; ++i)
+ q[newsz-n+i] = q[qstart+i];
+ qstart = newsz-n;
+ }
+
+ /* it needs to wrap around to 0, move the stuff after newsz to pos 0 */
+ else if (qend >= newsz) {
+ const gulong n = qend + 1 - newsz;
+ for (i = 0; i < n; ++i)
+ q[i] = q[newsz+i];
+ qend = n - 1;
+ }
+
+ q = g_renew(XEvent, q, newsz);
+ qsz = newsz;
+ }
+}
+
+static inline void grow(void) {
+ if (qnum == qsz) {
+ const gulong newsz = qsz*2;
+ gulong i;
+
+ q = g_renew(XEvent, q, newsz);
+
+ g_assert(qnum > 0);
+
+ if (qend < qstart) { /* it wraps around to 0 right now */
+ for (i = 0; i <= qend; ++i)
+ q[newsz+i] = q[i];
+ qend = newsz + qend;
+ }
+
+ qsz = newsz;
+ }
+}
+
+/* Grab all pending X events */
+static gboolean read_events(gboolean block)
+{
+ gint sth, n;
+
+ n = XEventsQueued(obt_display, QueuedAfterFlush) > 0;
+ sth = FALSE;
+
+ while ((block && !sth) || n > 0) {
+ XEvent e;
+
+ if (XNextEvent(obt_display, &e) != Success)
+ return FALSE;
+
+ grow(); /* make sure there is room */
+
+ ++qnum;
+ qend = (qend + 1) % qsz; /* move the end */
+ q[qend] = e; /* stick the event at the end */
+
+ --n;
+ sth = TRUE;
+ }
+
+ return sth; /* return if we read anything */
+}
+
+static void pop(gulong p)
+{
+ /* remove the event */
+ --qnum;
+ if (qnum == 0) {
+ qstart = 0;
+ qend = -1;
+ }
+ else if (p == qstart)
+ qstart = (qstart + 1) % qsz;
+ else {
+ gulong pi;
+
+ /* is it cheaper to move the start or the end ? */
+ if ((p >= qstart && p < qstart + qnum/2) ||
+ (p < qstart && p < (qstart + qnum/2) % qsz))
+ {
+ /* move the start */
+ pi = p;
+ while (pi != qstart) {
+ const gulong pi_next = (pi == 0 ? qsz-1 : pi-1);
+
+ q[pi] = q[pi_next];
+ pi = pi_next;
+ }
+ qstart = (qstart + 1) % qsz;
+ }
+ else {
+ /* move the end */
+ pi = p;
+ while (pi != qend) {
+ const gulong pi_next = (pi + 1) % qsz;
+
+ q[pi] = q[pi_next];
+ pi = pi_next;
+ }
+ qend = (qend == 0 ? qsz-1 : qend-1);
+ }
+ }
+
+ shrink(); /* shrink the q if too little in it */
+}
+
+void xqueue_init(void)
+{
+ if (q != NULL) return;
+ qsz = MINSZ;
+ q = g_new(XEvent, qsz);
+ qstart = 0;
+ qend = -1;
+}
+
+void xqueue_destroy(void)
+{
+ if (q == NULL) return;
+ g_free(q);
+ q = NULL;
+ qsz = 0;
+}
+
+gboolean xqueue_match_window(XEvent *e, gpointer data)
+{
+ const Window w = *(Window*)data;
+ return e->xany.window == w;
+}
+
+gboolean xqueue_match_type(XEvent *e, gpointer data)
+{
+ return e->type == GPOINTER_TO_INT(data);
+}
+
+gboolean xqueue_match_window_type(XEvent *e, gpointer data)
+{
+ const ObtXQueueWindowType x = *(ObtXQueueWindowType*)data;
+ return e->xany.window == x.window && e->type == x.type;
+}
+
+gboolean xqueue_match_window_message(XEvent *e, gpointer data)
+{
+ const ObtXQueueWindowMessage x = *(ObtXQueueWindowMessage*)data;
+ return e->xany.window == x.window && e->type == ClientMessage &&
+ e->xclient.message_type == x.message;
+}
+
+gboolean xqueue_peek(XEvent *event_return)
+{
+ g_return_val_if_fail(q != NULL, FALSE);
+ g_return_val_if_fail(event_return != NULL, FALSE);
+
+ if (!qnum) read_events(TRUE);
+ if (!qnum) return FALSE;
+ *event_return = q[qstart]; /* get the head */
+ return TRUE;
+}
+
+gboolean xqueue_peek_local(XEvent *event_return)
+{
+ g_return_val_if_fail(q != NULL, FALSE);
+ g_return_val_if_fail(event_return != NULL, FALSE);
+
+ if (!qnum) read_events(FALSE);
+ if (!qnum) return FALSE;
+ *event_return = q[qstart]; /* get the head */
+ return TRUE;
+}
+
+gboolean xqueue_next(XEvent *event_return)
+{
+ g_return_val_if_fail(q != NULL, FALSE);
+ g_return_val_if_fail(event_return != NULL, FALSE);
+
+ if (!qnum) read_events(TRUE);
+ if (qnum) {
+ *event_return = q[qstart]; /* get the head */
+ pop(qstart);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean xqueue_next_local(XEvent *event_return)
+{
+ g_return_val_if_fail(q != NULL, FALSE);
+ g_return_val_if_fail(event_return != NULL, FALSE);
+
+ if (!qnum) read_events(FALSE);
+ if (qnum) {
+ *event_return = q[qstart]; /* get the head */
+ pop(qstart);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean xqueue_exists(xqueue_match_func match, gpointer data)
+{
+ gulong i, checked;
+
+ g_return_val_if_fail(q != NULL, FALSE);
+ g_return_val_if_fail(match != NULL, FALSE);
+
+ checked = 0;
+ while (TRUE) {
+ for (i = checked; i < qnum; ++i, ++checked) {
+ const gulong p = (qstart + i) % qsz;
+ if (match(&q[p], data))
+ return TRUE;
+ }
+ if (!read_events(TRUE)) break; /* error */
+ }
+ return FALSE;
+}
+
+gboolean xqueue_exists_local(xqueue_match_func match, gpointer data)
+{
+ gulong i, checked;
+
+ g_return_val_if_fail(q != NULL, FALSE);
+ g_return_val_if_fail(match != NULL, FALSE);
+
+ checked = 0;
+ while (TRUE) {
+ for (i = checked; i < qnum; ++i, ++checked) {
+ const gulong p = (qstart + i) % qsz;
+ if (match(&q[p], data))
+ return TRUE;
+ }
+ if (!read_events(FALSE)) break;
+ }
+ return FALSE;
+}
+
+gboolean xqueue_remove_local(XEvent *event_return,
+ xqueue_match_func match, gpointer data)
+{
+ gulong i, checked;
+
+ g_return_val_if_fail(q != NULL, FALSE);
+ g_return_val_if_fail(event_return != NULL, FALSE);
+ g_return_val_if_fail(match != NULL, FALSE);
+
+ checked = 0;
+ while (TRUE) {
+ for (i = checked; i < qnum; ++i, ++checked) {
+ const gulong p = (qstart + i) % qsz;
+ if (match(&q[p], data)) {
+ *event_return = q[p];
+ pop(p);
+ return TRUE;
+ }
+ }
+ if (!read_events(FALSE)) break;
+ }
+ return FALSE;
+}
+
+gboolean xqueue_pending_local(void)
+{
+ g_return_val_if_fail(q != NULL, FALSE);
+
+ if (!qnum) read_events(FALSE);
+ return qnum != 0;
+}
--- /dev/null
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ obt/xqueue.h for the Openbox window manager
+ Copyright (c) 2010 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_xqueue_h
+#define __obt_xqueue_h
+
+#include <glib.h>
+#include <X11/Xlib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ObtXQueueWindowType {
+ Window window;
+ int type;
+} ObtXQueueWindowType;
+
+typedef struct _ObtXQueueWindowMessage {
+ Window window;
+ Atom message;
+} ObtXQueueWindowMessage;
+
+typedef gboolean (*xqueue_match_func)(XEvent *e, gpointer data);
+
+/*! Returns TRUE if the event matches the window pointed to by @data */
+gboolean xqueue_match_window(XEvent *e, gpointer data);
+
+/*! Returns TRUE if the event matches the type contained in the value of @data */
+gboolean xqueue_match_type(XEvent *e, gpointer data);
+
+/*! Returns TRUE if the event matches the type and window in the
+ ObtXQueueWindowType pointed to by @data */
+gboolean xqueue_match_window_type(XEvent *e, gpointer data);
+
+/*! Returns TRUE if a ClientMessage event matches the message and window in the
+ ObtXQueueWindowMessage pointed to by @data */
+gboolean xqueue_match_window_message(XEvent *e, gpointer data);
+
+/*! Returns TRUE and passes the next event in the queue and removes it from
+ the queue. On error, returns FALSE */
+gboolean xqueue_next(XEvent *event_return);
+
+/*! Returns TRUE and passes the next event in the local queue and removes it
+ from the queue. If no event is in the local queue, it returns FALSE. */
+gboolean xqueue_next_local(XEvent *event_return);
+
+/*! Returns TRUE if there is anything in the local event queue, and FALSE
+ otherwise. */
+gboolean xqueue_pending_local(void);
+
+/*! Returns TRUE and passes the next event in the queue, or FALSE if there
+ is an error */
+gboolean xqueue_peek(XEvent *event_return);
+
+/*! Returns TRUE and passes the next event in the queue, if there is one,
+ and returns FALSE otherwise. */
+gboolean xqueue_peek_local(XEvent *event_return);
+
+/*! Returns TRUE if xqueue_match_func returns TRUE for some event in the
+ current event queue or in the stream of events from the server,
+ and passes the matching event without removing it from the queue.
+ This blocks until an event is found or an error occurs. */
+gboolean xqueue_exists(xqueue_match_func match, gpointer data);
+
+/*! Returns TRUE if xqueue_match_func returns TRUE for some event in the
+ current event queue, and passes the matching event without removing it
+ from the queue. */
+gboolean xqueue_exists_local(xqueue_match_func match, gpointer data);
+
+/*! Returns TRUE if xqueue_match_func returns TRUE for some event in the
+ current event queue, and passes the matching event while removing it
+ from the queue. */
+gboolean xqueue_remove_local(XEvent *event_return,
+ xqueue_match_func match, gpointer data);
+
+G_END_DECLS
+
+#endif
#include "obrender/render.h"
#include "gettext.h"
#include "obt/display.h"
+#include "obt/xqueue.h"
#include "obt/prop.h"
#ifdef HAVE_UNISTD_H
return NULL;
}
-static gboolean client_validate_unmap(ObClient *self, int n)
-{
- XEvent e;
- gboolean ret = TRUE;
-
- if (XCheckTypedWindowEvent(obt_display, self->window, UnmapNotify, &e)) {
- if (n < self->ignore_unmaps) // ignore this one, but look for more
- ret = client_validate_unmap(self, n+1);
- else
- ret = FALSE; // the window is going to become unmanaged
+struct ObClientFindDestroyUnmap {
+ Window window;
+ gint ignore_unmaps;
+};
- /* put them back on the event stack so they end up in the same order */
- XPutBackEvent(obt_display, &e);
- }
-
- return ret;
+static gboolean find_destroy_unmap(XEvent *e, gpointer data)
+{
+ struct ObClientFindDestroyUnmap *find = data;
+ if (e->type == DestroyNotify)
+ return e->xdestroywindow.window == find->window;
+ if (e->type == UnmapNotify && e->xunmap.window == find->window)
+ /* ignore the first $find->ignore_unmaps$ many unmap events */
+ return --find->ignore_unmaps < 0;
+ return FALSE;
}
gboolean client_validate(ObClient *self)
{
- XEvent e;
+ struct ObClientFindDestroyUnmap find;
XSync(obt_display, FALSE); /* get all events on the server */
- if (XCheckTypedWindowEvent(obt_display, self->window, DestroyNotify, &e)) {
- XPutBackEvent(obt_display, &e);
- return FALSE;
- }
-
- if (!client_validate_unmap(self, 0))
+ find.window = self->window;
+ find.ignore_unmaps = self->ignore_unmaps;
+ if (xqueue_exists_local(find_destroy_unmap, &find))
return FALSE;
return TRUE;
gboolean client_focus(ObClient *self)
{
+ if (!client_validate(self)) return FALSE;
+
/* we might not focus this window, so if we have modal children which would
be focused instead, bring them to this desktop */
client_bring_modal_windows(self);
#include "stacking.h"
#include "ping.h"
#include "obt/display.h"
+#include "obt/xqueue.h"
#include "obt/prop.h"
#include "obt/keyboard.h"
/*! The serial of the current X event */
static gulong event_curserial;
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;
/* compress events */
{
XEvent ce;
- while (XCheckTypedWindowEvent(obt_display, e->xmotion.window,
- e->type, &ce)) {
+ ObtXQueueWindowType wt;
+
+ wt.window = e->xmotion.window;
+ wt.type = MotionNotify;
+ while (xqueue_remove_local(&ce, xqueue_match_window_type, &wt)) {
e->xmotion.x = ce.xmotion.x;
e->xmotion.y = ce.xmotion.y;
e->xmotion.x_root = ce.xmotion.x_root;
}
}
-static Bool event_look_for_focusin(Display *d, XEvent *e, XPointer arg)
+static gboolean event_look_for_focusin(XEvent *e, gpointer data)
{
return e->type == FocusIn && wanted_focusevent(e, FALSE);
}
-static Bool event_look_for_focusin_client(Display *d, XEvent *e, XPointer arg)
+static gboolean event_look_for_focusin_client(XEvent *e, gpointer data)
{
return e->type == FocusIn && wanted_focusevent(e, TRUE);
}
}
-static gboolean event_ignore(XEvent *e, ObClient *client)
-{
- switch(e->type) {
- case FocusIn:
- print_focusevent(e);
- if (!wanted_focusevent(e, FALSE))
- return TRUE;
- break;
- case FocusOut:
- print_focusevent(e);
- if (!wanted_focusevent(e, FALSE))
- return TRUE;
- break;
- }
- return FALSE;
-}
-
static void event_process(const XEvent *ec, gpointer data)
{
XEvent ee, *e;
- ObEventData *ed = data;
-
Window window;
ObClient *client = NULL;
ObDock *dock = NULL;
event_set_curtime(e);
event_curserial = e->xany.serial;
event_hack_mods(e);
- if (event_ignore(e, client)) {
- if (ed)
- ed->ignored = TRUE;
- return;
- } else if (ed)
- ed->ignored = FALSE;
/* deal with it in the kernel */
if (e->type == FocusIn) {
- if (client &&
- e->xfocus.detail == NotifyInferior)
- {
- ob_debug_type(OB_DEBUG_FOCUS,
- "Focus went to the frame window");
+ print_focusevent(e);
+ if (!wanted_focusevent(e, FALSE)) {
+ if (waiting_for_focusin) {
+ /* We were waiting for this FocusIn, since we got a FocusOut
+ earlier, but it went to a window that isn't a client. */
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Focus went to an unmanaged window 0x%x !",
+ e->xfocus.window);
+ focus_fallback(TRUE, config_focus_under_mouse, TRUE, TRUE);
+ }
+ }
+ else if (client && e->xfocus.detail == NotifyInferior) {
+ ob_debug_type(OB_DEBUG_FOCUS, "Focus went to the frame window");
focus_left_screen = FALSE;
e->xfocus.detail == NotifyInferior ||
e->xfocus.detail == NotifyNonlinear)
{
- XEvent ce;
-
ob_debug_type(OB_DEBUG_FOCUS,
"Focus went to root or pointer root/none");
But if the other focus in is something like PointerRoot then we
still want to fall back.
*/
- if (XCheckIfEvent(obt_display, &ce, event_look_for_focusin_client,
- NULL))
- {
- XPutBackEvent(obt_display, &ce);
+ if (xqueue_exists_local(event_look_for_focusin_client, NULL)) {
ob_debug_type(OB_DEBUG_FOCUS,
" but another FocusIn is coming");
} else {
client_calc_layer(client);
client_bring_helper_windows(client);
}
- } else if (e->type == FocusOut) {
- XEvent ce;
+ waiting_for_focusin = FALSE;
+ } else if (e->type == FocusOut) {
+ print_focusevent(e);
+ if (!wanted_focusevent(e, FALSE))
+ ; /* skip this one */
/* Look for the followup FocusIn */
- if (!XCheckIfEvent(obt_display, &ce, event_look_for_focusin, NULL)) {
+ else if (!xqueue_exists_local(event_look_for_focusin, NULL)) {
/* There is no FocusIn, this means focus went to a window that
is not being managed, or a window on another screen. */
Window win, root;
/* nothing is focused */
focus_set_client(NULL);
} else {
- /* Focus moved, so process the FocusIn event */
- ObEventData ed = { .ignored = FALSE };
- event_process(&ce, &ed);
- if (ed.ignored) {
- /* The FocusIn was ignored, this means it was on a window
- that isn't a client. */
- ob_debug_type(OB_DEBUG_FOCUS,
- "Focus went to an unmanaged window 0x%x !",
- ce.xfocus.window);
- focus_fallback(TRUE, config_focus_under_mouse, TRUE, TRUE);
- }
+ /* Focus moved, so mark that we are waiting to process that
+ FocusIn */
+ waiting_for_focusin = TRUE;
+
+ /* nothing is focused right now, but will be again shortly */
+ focus_set_client(NULL);
}
- if (client && client != focus_client) {
+ if (client && client != focus_client)
frame_adjust_focus(client->frame, FALSE);
- /* focus_set_client(NULL) has already been called in this
- section or by focus_fallback */
- }
}
else if (client)
event_handle_client(client, e);
}
else if (e->type == KeyPress || e->type == KeyRelease ||
e->type == MotionNotify)
+ {
used = event_handle_user_input(client, e);
- if (prompt && !used)
- used = event_handle_prompt(prompt, e);
+ if (prompt && !used)
+ used = event_handle_prompt(prompt, e);
+ }
/* if something happens and it's not from an XEvent, then we don't know
- the time */
+ the time, so clear it here until the next event is handled */
event_curtime = event_sourcetime = CurrentTime;
event_curserial = 0;
}
}
}
-static void compress_client_message_event(XEvent *e, XEvent *ce, Window window,
- Atom msgtype)
+static gboolean more_client_message_event(Window window, Atom msgtype)
{
- /* compress changes into a single change */
- while (XCheckTypedWindowEvent(obt_display, window, e->type, ce)) {
- /* XXX: it would be nice to compress ALL messages of a
- type, not just messages in a row without other
- message types between. */
- if (ce->xclient.message_type != msgtype) {
- XPutBackEvent(obt_display, ce);
- break;
+ ObtXQueueWindowMessage wm;
+ wm.window = window;
+ wm.message = msgtype;
+ return xqueue_exists_local(xqueue_match_window_message, &wm);
+}
+
+struct ObSkipPropertyChange {
+ Window window;
+ Atom prop;
+};
+
+static gboolean skip_property_change(XEvent *e, gpointer data)
+{
+ const struct ObSkipPropertyChange s = *(struct ObSkipPropertyChange*)data;
+
+ if (e->type == PropertyNotify && e->xproperty.window == s.window) {
+ const Atom a = e->xproperty.atom;
+ const Atom b = s.prop;
+
+ /* these are all updated together */
+ if ((a == OBT_PROP_ATOM(NET_WM_NAME) ||
+ a == OBT_PROP_ATOM(WM_NAME) ||
+ a == OBT_PROP_ATOM(NET_WM_ICON_NAME) ||
+ a == OBT_PROP_ATOM(WM_ICON_NAME))
+ &&
+ (b == OBT_PROP_ATOM(NET_WM_NAME) ||
+ b == OBT_PROP_ATOM(WM_NAME) ||
+ b == OBT_PROP_ATOM(NET_WM_ICON_NAME) ||
+ b == OBT_PROP_ATOM(WM_ICON_NAME)))
+ {
+ return TRUE;
}
- e->xclient = ce->xclient;
+ else if (a == b && a == OBT_PROP_ATOM(NET_WM_ICON))
+ return TRUE;
}
+ return FALSE;
}
static void event_handle_client(ObClient *client, XEvent *e)
{
- XEvent ce;
Atom msgtype;
ObFrameContext con;
gboolean *but;
msgtype = e->xclient.message_type;
if (msgtype == OBT_PROP_ATOM(WM_CHANGE_STATE)) {
- compress_client_message_event(e, &ce, client->window, msgtype);
- client_set_wm_state(client, e->xclient.data.l[0]);
+ if (!more_client_message_event(client->window, msgtype))
+ client_set_wm_state(client, e->xclient.data.l[0]);
} else if (msgtype == OBT_PROP_ATOM(NET_WM_DESKTOP)) {
- compress_client_message_event(e, &ce, client->window, msgtype);
- if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
- (unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
+ if (!more_client_message_event(client->window, msgtype) &&
+ ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
+ (unsigned)e->xclient.data.l[0] == DESKTOP_ALL))
+ {
client_set_desktop(client, (unsigned)e->xclient.data.l[0],
FALSE, FALSE);
+ }
} else if (msgtype == OBT_PROP_ATOM(NET_WM_STATE)) {
gulong ignore_start;
/* validate cuz we query stuff off the client here */
if (!client_validate(client)) break;
- /* compress changes to a single property into a single change */
- while (XCheckTypedWindowEvent(obt_display, client->window,
- e->type, &ce)) {
- Atom a, b;
-
- /* XXX: it would be nice to compress ALL changes to a property,
- not just changes in a row without other props between. */
-
- a = ce.xproperty.atom;
- b = e->xproperty.atom;
-
- if (a == b)
- continue;
- if ((a == OBT_PROP_ATOM(NET_WM_NAME) ||
- a == OBT_PROP_ATOM(WM_NAME) ||
- a == OBT_PROP_ATOM(NET_WM_ICON_NAME) ||
- a == OBT_PROP_ATOM(WM_ICON_NAME))
- &&
- (b == OBT_PROP_ATOM(NET_WM_NAME) ||
- b == OBT_PROP_ATOM(WM_NAME) ||
- b == OBT_PROP_ATOM(NET_WM_ICON_NAME) ||
- b == OBT_PROP_ATOM(WM_ICON_NAME))) {
- continue;
- }
- if (a == OBT_PROP_ATOM(NET_WM_ICON) &&
- b == OBT_PROP_ATOM(NET_WM_ICON))
- continue;
+ msgtype = e->xproperty.atom;
- XPutBackEvent(obt_display, &ce);
- break;
+ /* ignore changes to some properties if there is another change
+ coming in the queue */
+ {
+ struct ObSkipPropertyChange s;
+ s.window = client->window;
+ s.prop = msgtype;
+ if (xqueue_exists_local(skip_property_change, &s))
+ break;
}
msgtype = e->xproperty.atom;
return ret;
}
-static Bool event_look_for_menu_enter(Display *d, XEvent *ev, XPointer arg)
+static gboolean event_look_for_menu_enter(XEvent *ev, gpointer data)
{
- ObMenuFrame *f = (ObMenuFrame*)arg;
+ const ObMenuFrame *f = (ObMenuFrame*)data;
ObMenuEntryFrame *e;
return ev->type == EnterNotify &&
(e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)) &&
- !e->ignore_enters && e->frame == f;
+ e->frame == f && !e->ignore_enters;
}
static void event_handle_menu(ObMenuFrame *frame, XEvent *ev)
if (ev->xcrossing.detail == NotifyInferior)
break;
- if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)))
- {
- XEvent ce;
-
+ if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window))) {
/* check if an EnterNotify event is coming, and if not, then select
nothing in the menu */
- if (XCheckIfEvent(obt_display, &ce, event_look_for_menu_enter,
- (XPointer)e->frame))
- XPutBackEvent(obt_display, &ce);
- else
+ if (!xqueue_exists_local(event_look_for_menu_enter, e->frame))
menu_frame_select(e->frame, NULL, FALSE);
}
break;
return t1 >= t2 && t1 < (t2 + TIME_HALF);
}
-Bool find_timestamp(Display *d, XEvent *e, XPointer a)
+gboolean find_timestamp(XEvent *e, gpointer data)
{
const Time t = event_get_timestamp(e);
- return t != CurrentTime;
+ if (t != CurrentTime) {
+ event_curtime = t;
+ return TRUE;
+ }
+ else
+ return FALSE;
}
Time event_time(void)
{
- XEvent event;
-
if (event_curtime) return event_curtime;
/* Some events don't come with timestamps :(
8, PropModeAppend, NULL, 0);
/* Grab the first timestamp available */
- XPeekIfEvent(obt_display, &event, find_timestamp, NULL);
+ xqueue_exists(find_timestamp, NULL);
+
+ /*g_assert(event_curtime != CurrentTime);*/
/* Save the time so we don't have to do this again for this event */
- return event_curtime = event.xproperty.time;
+ return event_curtime;
}
Time event_source_time(void)
#include "screen.h"
#include "obrender/theme.h"
#include "obt/display.h"
+#include "obt/xqueue.h"
#include "obt/prop.h"
#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
window_add(&self->rgripbottom, CLIENT_AS_WINDOW(self->client));
}
-void frame_release_client(ObFrame *self)
+static gboolean find_reparent(XEvent *e, gpointer data)
{
- XEvent ev;
- gboolean reparent = TRUE;
+ const ObFrame *self = data;
+
+ /* Find ReparentNotify events for the window that aren't being reparented into the
+ frame, thus the client reparenting itself off the frame. */
+ return e->type == ReparentNotify && e->xreparent.window == self->client->window &&
+ e->xreparent.parent != self->window;
+}
+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);
/* check if the app has already reparented its window away */
- while (XCheckTypedWindowEvent(obt_display, self->client->window,
- ReparentNotify, &ev))
- {
- /* This check makes sure we don't catch our own reparent action to
- our frame window. This doesn't count as the app reparenting itself
- away of course.
-
- Reparent events that are generated by us are just discarded here.
- They are of no consequence to us anyhow.
- */
- if (ev.xreparent.parent != self->window) {
- reparent = FALSE;
- break;
- }
- }
-
- if (reparent) {
+ if (!xqueue_exists_local(find_reparent, self)) {
/* according to the ICCCM - if the client doesn't reparent itself,
then we will reparent the window to root for them */
XReparentWindow(obt_display, self->client->window, obt_root(ob_screen),
#include "obrender/render.h"
#include "obrender/theme.h"
#include "obt/display.h"
+#include "obt/xqueue.h"
#include "obt/prop.h"
#include "obt/keyboard.h"
XSync(obt_display, FALSE);
{
XEvent ce;
- while (XCheckTypedEvent(obt_display, MotionNotify, &ce));
+ while (xqueue_remove_local(&ce, xqueue_match_type,
+ GINT_TO_POINTER(MotionNotify)));
}
screen_pointer_pos(&px, &py);
XSync(obt_display, FALSE);
{
XEvent ce;
- while (XCheckTypedEvent(obt_display, MotionNotify, &ce));
+ while (xqueue_remove_local(&ce, xqueue_match_type,
+ GINT_TO_POINTER(MotionNotify)));
}
screen_pointer_pos(&px, &py);
#include "obrender/render.h"
#include "gettext.h"
#include "obt/display.h"
+#include "obt/xqueue.h"
#include "obt/prop.h"
#include "obt/mainloop.h"
/* Wait for old window manager to go away */
if (current_wm_sn_owner) {
- XEvent event;
gulong wait = 0;
const gulong timeout = G_USEC_PER_SEC * 15; /* wait for 15s max */
+ ObtXQueueWindowType wt;
+
+ wt.window = current_wm_sn_owner;
+ wt.type = DestroyNotify;
while (wait < timeout) {
- if (XCheckWindowEvent(obt_display, current_wm_sn_owner,
- StructureNotifyMask, &event) &&
- event.type == DestroyNotify)
+ /* Checks the local queue and incoming events for this event */
+ if (xqueue_exists_local(xqueue_match_window_type, &wt))
break;
g_usleep(G_USEC_PER_SEC / 10);
wait += G_USEC_PER_SEC / 10;
#include "prompt.h"
#include "debug.h"
#include "grab.h"
+#include "obt/xqueue.h"
static GHashTable *window_map;
if (children) XFree(children);
}
-static Bool check_unmap(Display *d, XEvent *e, XPointer arg)
+static gboolean check_unmap(XEvent *e, gpointer data)
{
- const Window win = *(Window*)arg;
+ const Window win = *(Window*)data;
return ((e->type == DestroyNotify && e->xdestroywindow.window == win) ||
(e->type == UnmapNotify && e->xunmap.window == win));
}
void window_manage(Window win)
{
- XEvent e;
XWindowAttributes attrib;
gboolean no_manage = FALSE;
gboolean is_dockapp = FALSE;
/* check if it has already been unmapped by the time we started
mapping. the grab does a sync so we don't have to here */
- if (XCheckIfEvent(obt_display, &e, check_unmap, (XPointer)&win)) {
+ if (xqueue_exists_local(check_unmap, &win)) {
ob_debug("Trying to manage unmapped window. Aborting that.");
no_manage = TRUE;
}
-
- if (!XGetWindowAttributes(obt_display, win, &attrib))
+ else if (!XGetWindowAttributes(obt_display, win, &attrib))
no_manage = TRUE;
else {
XWMHints *wmhints;