make an event queue for X events. the queue's min size is 16 XEvents (~3k)

This commit is contained in:
Dana Jansens 2010-04-28 12:57:51 -04:00
parent 029628087f
commit 55b84316bb
11 changed files with 590 additions and 187 deletions

View file

@ -148,7 +148,9 @@ obt_libobt_la_SOURCES = \
obt/prop.c \
obt/util.h \
obt/xevent.h \
obt/xevent.c
obt/xevent.c \
obt/xqueue.h \
obt/xqueue.c
## openbox ##
@ -441,7 +443,8 @@ obtpubinclude_HEADERS = \
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 \

View file

@ -20,6 +20,7 @@
#include "obt/prop.h"
#include "obt/internal.h"
#include "obt/keyboard.h"
#include "obt/xqueue.h"
#ifdef HAVE_STRING_H
# include <string.h>
@ -31,6 +32,10 @@
# 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;
@ -116,13 +121,19 @@ gboolean obt_display_open(const char *display_name)
}
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)

View file

@ -19,6 +19,7 @@
#include "obt/mainloop.h"
#include "obt/display.h"
#include "obt/xqueue.h"
#include "obt/util.h"
#ifdef HAVE_STDIO_H
@ -296,10 +297,8 @@ void obt_main_loop_run(ObtMainLoop *loop)
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);
@ -307,10 +306,9 @@ void obt_main_loop_run(ObtMainLoop *loop)
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;

320
obt/xqueue.c Normal file
View file

@ -0,0 +1,320 @@
/* -*- 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;
}

92
obt/xqueue.h Normal file
View file

@ -0,0 +1,92 @@
/* -*- 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

View file

@ -42,6 +42,7 @@
#include "obrender/render.h"
#include "gettext.h"
#include "obt/display.h"
#include "obt/xqueue.h"
#include "obt/prop.h"
#ifdef HAVE_UNISTD_H
@ -3620,36 +3621,31 @@ ObClient *client_search_modal_child(ObClient *self)
return NULL;
}
static gboolean client_validate_unmap(ObClient *self, int n)
struct ObClientFindDestroyUnmap {
Window window;
gint ignore_unmaps;
};
static gboolean find_destroy_unmap(XEvent *e, gpointer data)
{
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
/* put them back on the event stack so they end up in the same order */
XPutBackEvent(obt_display, &e);
}
return ret;
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;
@ -3841,6 +3837,8 @@ gboolean client_can_focus(ObClient *self)
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);

View file

@ -40,6 +40,7 @@
#include "stacking.h"
#include "ping.h"
#include "obt/display.h"
#include "obt/xqueue.h"
#include "obt/prop.h"
#include "obt/keyboard.h"
@ -108,6 +109,7 @@ static Time event_sourcetime;
/*! 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;
@ -288,8 +290,11 @@ static void event_hack_mods(XEvent *e)
/* 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;
@ -389,12 +394,12 @@ static gboolean wanted_focusevent(XEvent *e, gboolean in_client_only)
}
}
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);
}
@ -437,28 +442,9 @@ static void print_focusevent(XEvent *e)
}
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;
@ -502,21 +488,23 @@ static void event_process(const XEvent *ec, gpointer data)
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)
{
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 the frame window");
"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;
@ -533,8 +521,6 @@ static void event_process(const XEvent *ec, gpointer data)
e->xfocus.detail == NotifyInferior ||
e->xfocus.detail == NotifyNonlinear)
{
XEvent ce;
ob_debug_type(OB_DEBUG_FOCUS,
"Focus went to root or pointer root/none");
@ -557,10 +543,7 @@ static void event_process(const XEvent *ec, gpointer data)
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 {
@ -593,11 +576,14 @@ static void event_process(const XEvent *ec, gpointer data)
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;
@ -619,24 +605,16 @@ static void event_process(const XEvent *ec, gpointer data)
/* 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);
@ -739,13 +717,15 @@ static void event_process(const XEvent *ec, gpointer data)
}
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 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;
}
@ -918,25 +898,48 @@ static gboolean *context_to_button(ObFrame *f, ObFrameContext con, gboolean pres
}
}
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);
}
e->xclient = ce->xclient;
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;
}
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;
@ -1372,14 +1375,16 @@ static void event_handle_client(ObClient *client, XEvent *e)
msgtype = e->xclient.message_type;
if (msgtype == OBT_PROP_ATOM(WM_CHANGE_STATE)) {
compress_client_message_event(e, &ce, client->window, msgtype);
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;
@ -1566,35 +1571,15 @@ static void event_handle_client(ObClient *client, XEvent *e)
/* 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;
msgtype = e->xproperty.atom;
/* 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;
XPutBackEvent(obt_display, &ce);
/* 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;
}
@ -1974,13 +1959,13 @@ static gboolean event_handle_menu_input(XEvent *ev)
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)
@ -2005,16 +1990,10 @@ 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;
@ -2218,16 +2197,19 @@ gboolean event_time_after(guint32 t1, guint32 t2)
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 :(
@ -2240,10 +2222,12 @@ Time event_time(void)
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)

View file

@ -30,6 +30,7 @@
#include "screen.h"
#include "obrender/theme.h"
#include "obt/display.h"
#include "obt/xqueue.h"
#include "obt/prop.h"
#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
@ -1042,33 +1043,24 @@ void frame_grab_client(ObFrame *self)
window_add(&self->rgripbottom, CLIENT_AS_WINDOW(self->client));
}
static gboolean find_reparent(XEvent *e, gpointer data)
{
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)
{
XEvent ev;
gboolean reparent = TRUE;
/* 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),

View file

@ -32,6 +32,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"
@ -672,7 +673,8 @@ static void move_with_keys(KeySym sym, guint state)
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);
@ -831,7 +833,8 @@ static void resize_with_keys(KeySym sym, guint state)
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);

View file

@ -36,6 +36,7 @@
#include "obrender/render.h"
#include "gettext.h"
#include "obt/display.h"
#include "obt/xqueue.h"
#include "obt/prop.h"
#include "obt/mainloop.h"
@ -129,14 +130,16 @@ static gboolean replace_wm(void)
/* 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;

View file

@ -26,6 +26,7 @@
#include "prompt.h"
#include "debug.h"
#include "grab.h"
#include "obt/xqueue.h"
static GHashTable *window_map;
@ -146,16 +147,15 @@ void window_manage_all(void)
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;
@ -165,12 +165,11 @@ void window_manage(Window win)
/* 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;