make an event queue for X events. the queue's min size is 16 XEvents (~3k)
This commit is contained in:
parent
029628087f
commit
55b84316bb
11 changed files with 590 additions and 187 deletions
|
@ -148,7 +148,9 @@ obt_libobt_la_SOURCES = \
|
||||||
obt/prop.c \
|
obt/prop.c \
|
||||||
obt/util.h \
|
obt/util.h \
|
||||||
obt/xevent.h \
|
obt/xevent.h \
|
||||||
obt/xevent.c
|
obt/xevent.c \
|
||||||
|
obt/xqueue.h \
|
||||||
|
obt/xqueue.c
|
||||||
|
|
||||||
## openbox ##
|
## openbox ##
|
||||||
|
|
||||||
|
@ -441,7 +443,8 @@ obtpubinclude_HEADERS = \
|
||||||
obt/prop.h \
|
obt/prop.h \
|
||||||
obt/util.h \
|
obt/util.h \
|
||||||
obt/version.h \
|
obt/version.h \
|
||||||
obt/xevent.h
|
obt/xevent.h \
|
||||||
|
obt/xqueue.h
|
||||||
|
|
||||||
nodist_pkgconfig_DATA = \
|
nodist_pkgconfig_DATA = \
|
||||||
obrender/obrender-3.5.pc \
|
obrender/obrender-3.5.pc \
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "obt/prop.h"
|
#include "obt/prop.h"
|
||||||
#include "obt/internal.h"
|
#include "obt/internal.h"
|
||||||
#include "obt/keyboard.h"
|
#include "obt/keyboard.h"
|
||||||
|
#include "obt/xqueue.h"
|
||||||
|
|
||||||
#ifdef HAVE_STRING_H
|
#ifdef HAVE_STRING_H
|
||||||
# include <string.h>
|
# include <string.h>
|
||||||
|
@ -31,6 +32,10 @@
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* from xqueue.c */
|
||||||
|
extern void xqueue_init(void);
|
||||||
|
extern void xqueue_destroy(void);
|
||||||
|
|
||||||
Display* obt_display = NULL;
|
Display* obt_display = NULL;
|
||||||
|
|
||||||
gboolean obt_display_error_occured = FALSE;
|
gboolean obt_display_error_occured = FALSE;
|
||||||
|
@ -116,13 +121,19 @@ gboolean obt_display_open(const char *display_name)
|
||||||
}
|
}
|
||||||
g_free(n);
|
g_free(n);
|
||||||
|
|
||||||
|
if (obt_display)
|
||||||
|
xqueue_init();
|
||||||
|
|
||||||
return obt_display != NULL;
|
return obt_display != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void obt_display_close(void)
|
void obt_display_close(void)
|
||||||
{
|
{
|
||||||
obt_keyboard_shutdown();
|
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)
|
static gint xerror_handler(Display *d, XErrorEvent *e)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "obt/mainloop.h"
|
#include "obt/mainloop.h"
|
||||||
#include "obt/display.h"
|
#include "obt/display.h"
|
||||||
|
#include "obt/xqueue.h"
|
||||||
#include "obt/util.h"
|
#include "obt/util.h"
|
||||||
|
|
||||||
#ifdef HAVE_STDIO_H
|
#ifdef HAVE_STDIO_H
|
||||||
|
@ -296,10 +297,8 @@ void obt_main_loop_run(ObtMainLoop *loop)
|
||||||
loop->signal_fired = FALSE;
|
loop->signal_fired = FALSE;
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
} else if (loop->display && XPending(loop->display)) {
|
} else if (loop->display && xqueue_pending_local()) {
|
||||||
do {
|
while (xqueue_next_local(&e) && loop->run) {
|
||||||
XNextEvent(loop->display, &e);
|
|
||||||
|
|
||||||
if (e.type == MappingNotify)
|
if (e.type == MappingNotify)
|
||||||
XRefreshKeyboardMapping(&e.xmapping);
|
XRefreshKeyboardMapping(&e.xmapping);
|
||||||
|
|
||||||
|
@ -307,10 +306,9 @@ void obt_main_loop_run(ObtMainLoop *loop)
|
||||||
ObtMainLoopXHandlerType *h = it->data;
|
ObtMainLoopXHandlerType *h = it->data;
|
||||||
h->func(&e, h->data);
|
h->func(&e, h->data);
|
||||||
}
|
}
|
||||||
} while (XPending(loop->display) && loop->run);
|
}
|
||||||
} else {
|
} else {
|
||||||
/* this only runs if there were no x events received */
|
/* this only runs if there were no x events received */
|
||||||
|
|
||||||
timer_dispatch(loop, (GTimeVal**)&wait);
|
timer_dispatch(loop, (GTimeVal**)&wait);
|
||||||
|
|
||||||
selset = loop->fd_set;
|
selset = loop->fd_set;
|
||||||
|
|
320
obt/xqueue.c
Normal file
320
obt/xqueue.c
Normal 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
92
obt/xqueue.h
Normal 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
|
|
@ -42,6 +42,7 @@
|
||||||
#include "obrender/render.h"
|
#include "obrender/render.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "obt/display.h"
|
#include "obt/display.h"
|
||||||
|
#include "obt/xqueue.h"
|
||||||
#include "obt/prop.h"
|
#include "obt/prop.h"
|
||||||
|
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
|
@ -3620,36 +3621,31 @@ ObClient *client_search_modal_child(ObClient *self)
|
||||||
return NULL;
|
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;
|
struct ObClientFindDestroyUnmap *find = data;
|
||||||
gboolean ret = TRUE;
|
if (e->type == DestroyNotify)
|
||||||
|
return e->xdestroywindow.window == find->window;
|
||||||
if (XCheckTypedWindowEvent(obt_display, self->window, UnmapNotify, &e)) {
|
if (e->type == UnmapNotify && e->xunmap.window == find->window)
|
||||||
if (n < self->ignore_unmaps) // ignore this one, but look for more
|
/* ignore the first $find->ignore_unmaps$ many unmap events */
|
||||||
ret = client_validate_unmap(self, n+1);
|
return --find->ignore_unmaps < 0;
|
||||||
else
|
return FALSE;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean client_validate(ObClient *self)
|
gboolean client_validate(ObClient *self)
|
||||||
{
|
{
|
||||||
XEvent e;
|
struct ObClientFindDestroyUnmap find;
|
||||||
|
|
||||||
XSync(obt_display, FALSE); /* get all events on the server */
|
XSync(obt_display, FALSE); /* get all events on the server */
|
||||||
|
|
||||||
if (XCheckTypedWindowEvent(obt_display, self->window, DestroyNotify, &e)) {
|
find.window = self->window;
|
||||||
XPutBackEvent(obt_display, &e);
|
find.ignore_unmaps = self->ignore_unmaps;
|
||||||
return FALSE;
|
if (xqueue_exists_local(find_destroy_unmap, &find))
|
||||||
}
|
|
||||||
|
|
||||||
if (!client_validate_unmap(self, 0))
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -3841,6 +3837,8 @@ gboolean client_can_focus(ObClient *self)
|
||||||
|
|
||||||
gboolean client_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
|
/* we might not focus this window, so if we have modal children which would
|
||||||
be focused instead, bring them to this desktop */
|
be focused instead, bring them to this desktop */
|
||||||
client_bring_modal_windows(self);
|
client_bring_modal_windows(self);
|
||||||
|
|
232
openbox/event.c
232
openbox/event.c
|
@ -40,6 +40,7 @@
|
||||||
#include "stacking.h"
|
#include "stacking.h"
|
||||||
#include "ping.h"
|
#include "ping.h"
|
||||||
#include "obt/display.h"
|
#include "obt/display.h"
|
||||||
|
#include "obt/xqueue.h"
|
||||||
#include "obt/prop.h"
|
#include "obt/prop.h"
|
||||||
#include "obt/keyboard.h"
|
#include "obt/keyboard.h"
|
||||||
|
|
||||||
|
@ -108,6 +109,7 @@ static Time event_sourcetime;
|
||||||
/*! The serial of the current X event */
|
/*! The serial of the current X event */
|
||||||
static gulong event_curserial;
|
static gulong event_curserial;
|
||||||
static gboolean focus_left_screen = FALSE;
|
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 */
|
/*! A list of ObSerialRanges which are to be ignored for mouse enter events */
|
||||||
static GSList *ignore_serials = NULL;
|
static GSList *ignore_serials = NULL;
|
||||||
|
|
||||||
|
@ -288,8 +290,11 @@ static void event_hack_mods(XEvent *e)
|
||||||
/* compress events */
|
/* compress events */
|
||||||
{
|
{
|
||||||
XEvent ce;
|
XEvent ce;
|
||||||
while (XCheckTypedWindowEvent(obt_display, e->xmotion.window,
|
ObtXQueueWindowType wt;
|
||||||
e->type, &ce)) {
|
|
||||||
|
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.x = ce.xmotion.x;
|
||||||
e->xmotion.y = ce.xmotion.y;
|
e->xmotion.y = ce.xmotion.y;
|
||||||
e->xmotion.x_root = ce.xmotion.x_root;
|
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);
|
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);
|
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)
|
static void event_process(const XEvent *ec, gpointer data)
|
||||||
{
|
{
|
||||||
XEvent ee, *e;
|
XEvent ee, *e;
|
||||||
ObEventData *ed = data;
|
|
||||||
|
|
||||||
Window window;
|
Window window;
|
||||||
ObClient *client = NULL;
|
ObClient *client = NULL;
|
||||||
ObDock *dock = NULL;
|
ObDock *dock = NULL;
|
||||||
|
@ -502,21 +488,23 @@ static void event_process(const XEvent *ec, gpointer data)
|
||||||
event_set_curtime(e);
|
event_set_curtime(e);
|
||||||
event_curserial = e->xany.serial;
|
event_curserial = e->xany.serial;
|
||||||
event_hack_mods(e);
|
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 */
|
/* deal with it in the kernel */
|
||||||
|
|
||||||
if (e->type == FocusIn) {
|
if (e->type == FocusIn) {
|
||||||
if (client &&
|
print_focusevent(e);
|
||||||
e->xfocus.detail == NotifyInferior)
|
if (!wanted_focusevent(e, FALSE)) {
|
||||||
{
|
if (waiting_for_focusin) {
|
||||||
ob_debug_type(OB_DEBUG_FOCUS,
|
/* We were waiting for this FocusIn, since we got a FocusOut
|
||||||
"Focus went to the frame window");
|
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;
|
focus_left_screen = FALSE;
|
||||||
|
|
||||||
|
@ -533,8 +521,6 @@ static void event_process(const XEvent *ec, gpointer data)
|
||||||
e->xfocus.detail == NotifyInferior ||
|
e->xfocus.detail == NotifyInferior ||
|
||||||
e->xfocus.detail == NotifyNonlinear)
|
e->xfocus.detail == NotifyNonlinear)
|
||||||
{
|
{
|
||||||
XEvent ce;
|
|
||||||
|
|
||||||
ob_debug_type(OB_DEBUG_FOCUS,
|
ob_debug_type(OB_DEBUG_FOCUS,
|
||||||
"Focus went to root or pointer root/none");
|
"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
|
But if the other focus in is something like PointerRoot then we
|
||||||
still want to fall back.
|
still want to fall back.
|
||||||
*/
|
*/
|
||||||
if (XCheckIfEvent(obt_display, &ce, event_look_for_focusin_client,
|
if (xqueue_exists_local(event_look_for_focusin_client, NULL)) {
|
||||||
NULL))
|
|
||||||
{
|
|
||||||
XPutBackEvent(obt_display, &ce);
|
|
||||||
ob_debug_type(OB_DEBUG_FOCUS,
|
ob_debug_type(OB_DEBUG_FOCUS,
|
||||||
" but another FocusIn is coming");
|
" but another FocusIn is coming");
|
||||||
} else {
|
} else {
|
||||||
|
@ -593,11 +576,14 @@ static void event_process(const XEvent *ec, gpointer data)
|
||||||
client_calc_layer(client);
|
client_calc_layer(client);
|
||||||
client_bring_helper_windows(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 */
|
/* 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
|
/* There is no FocusIn, this means focus went to a window that
|
||||||
is not being managed, or a window on another screen. */
|
is not being managed, or a window on another screen. */
|
||||||
Window win, root;
|
Window win, root;
|
||||||
|
@ -619,24 +605,16 @@ static void event_process(const XEvent *ec, gpointer data)
|
||||||
/* nothing is focused */
|
/* nothing is focused */
|
||||||
focus_set_client(NULL);
|
focus_set_client(NULL);
|
||||||
} else {
|
} else {
|
||||||
/* Focus moved, so process the FocusIn event */
|
/* Focus moved, so mark that we are waiting to process that
|
||||||
ObEventData ed = { .ignored = FALSE };
|
FocusIn */
|
||||||
event_process(&ce, &ed);
|
waiting_for_focusin = TRUE;
|
||||||
if (ed.ignored) {
|
|
||||||
/* The FocusIn was ignored, this means it was on a window
|
/* nothing is focused right now, but will be again shortly */
|
||||||
that isn't a client. */
|
focus_set_client(NULL);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client && client != focus_client) {
|
if (client && client != focus_client)
|
||||||
frame_adjust_focus(client->frame, FALSE);
|
frame_adjust_focus(client->frame, FALSE);
|
||||||
/* focus_set_client(NULL) has already been called in this
|
|
||||||
section or by focus_fallback */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (client)
|
else if (client)
|
||||||
event_handle_client(client, e);
|
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 ||
|
else if (e->type == KeyPress || e->type == KeyRelease ||
|
||||||
e->type == MotionNotify)
|
e->type == MotionNotify)
|
||||||
|
{
|
||||||
used = event_handle_user_input(client, e);
|
used = event_handle_user_input(client, e);
|
||||||
|
|
||||||
if (prompt && !used)
|
if (prompt && !used)
|
||||||
used = event_handle_prompt(prompt, e);
|
used = event_handle_prompt(prompt, e);
|
||||||
|
}
|
||||||
|
|
||||||
/* if something happens and it's not from an XEvent, then we don't know
|
/* 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_curtime = event_sourcetime = CurrentTime;
|
||||||
event_curserial = 0;
|
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,
|
static gboolean more_client_message_event(Window window, Atom msgtype)
|
||||||
Atom msgtype)
|
|
||||||
{
|
{
|
||||||
/* compress changes into a single change */
|
ObtXQueueWindowMessage wm;
|
||||||
while (XCheckTypedWindowEvent(obt_display, window, e->type, ce)) {
|
wm.window = window;
|
||||||
/* XXX: it would be nice to compress ALL messages of a
|
wm.message = msgtype;
|
||||||
type, not just messages in a row without other
|
return xqueue_exists_local(xqueue_match_window_message, &wm);
|
||||||
message types between. */
|
}
|
||||||
if (ce->xclient.message_type != msgtype) {
|
|
||||||
XPutBackEvent(obt_display, ce);
|
struct ObSkipPropertyChange {
|
||||||
break;
|
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)
|
static void event_handle_client(ObClient *client, XEvent *e)
|
||||||
{
|
{
|
||||||
XEvent ce;
|
|
||||||
Atom msgtype;
|
Atom msgtype;
|
||||||
ObFrameContext con;
|
ObFrameContext con;
|
||||||
gboolean *but;
|
gboolean *but;
|
||||||
|
@ -1372,14 +1375,16 @@ static void event_handle_client(ObClient *client, XEvent *e)
|
||||||
|
|
||||||
msgtype = e->xclient.message_type;
|
msgtype = e->xclient.message_type;
|
||||||
if (msgtype == OBT_PROP_ATOM(WM_CHANGE_STATE)) {
|
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]);
|
client_set_wm_state(client, e->xclient.data.l[0]);
|
||||||
} else if (msgtype == OBT_PROP_ATOM(NET_WM_DESKTOP)) {
|
} else if (msgtype == OBT_PROP_ATOM(NET_WM_DESKTOP)) {
|
||||||
compress_client_message_event(e, &ce, client->window, msgtype);
|
if (!more_client_message_event(client->window, msgtype) &&
|
||||||
if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
|
((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
|
||||||
(unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
|
(unsigned)e->xclient.data.l[0] == DESKTOP_ALL))
|
||||||
|
{
|
||||||
client_set_desktop(client, (unsigned)e->xclient.data.l[0],
|
client_set_desktop(client, (unsigned)e->xclient.data.l[0],
|
||||||
FALSE, FALSE);
|
FALSE, FALSE);
|
||||||
|
}
|
||||||
} else if (msgtype == OBT_PROP_ATOM(NET_WM_STATE)) {
|
} else if (msgtype == OBT_PROP_ATOM(NET_WM_STATE)) {
|
||||||
gulong ignore_start;
|
gulong ignore_start;
|
||||||
|
|
||||||
|
@ -1566,36 +1571,16 @@ static void event_handle_client(ObClient *client, XEvent *e)
|
||||||
/* validate cuz we query stuff off the client here */
|
/* validate cuz we query stuff off the client here */
|
||||||
if (!client_validate(client)) break;
|
if (!client_validate(client)) break;
|
||||||
|
|
||||||
/* compress changes to a single property into a single change */
|
msgtype = e->xproperty.atom;
|
||||||
while (XCheckTypedWindowEvent(obt_display, client->window,
|
|
||||||
e->type, &ce)) {
|
|
||||||
Atom a, b;
|
|
||||||
|
|
||||||
/* XXX: it would be nice to compress ALL changes to a property,
|
/* ignore changes to some properties if there is another change
|
||||||
not just changes in a row without other props between. */
|
coming in the queue */
|
||||||
|
{
|
||||||
a = ce.xproperty.atom;
|
struct ObSkipPropertyChange s;
|
||||||
b = e->xproperty.atom;
|
s.window = client->window;
|
||||||
|
s.prop = msgtype;
|
||||||
if (a == b)
|
if (xqueue_exists_local(skip_property_change, &s))
|
||||||
continue;
|
break;
|
||||||
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);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msgtype = e->xproperty.atom;
|
msgtype = e->xproperty.atom;
|
||||||
|
@ -1974,13 +1959,13 @@ static gboolean event_handle_menu_input(XEvent *ev)
|
||||||
return ret;
|
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;
|
ObMenuEntryFrame *e;
|
||||||
return ev->type == EnterNotify &&
|
return ev->type == EnterNotify &&
|
||||||
(e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)) &&
|
(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)
|
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)
|
if (ev->xcrossing.detail == NotifyInferior)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)))
|
if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window))) {
|
||||||
{
|
|
||||||
XEvent ce;
|
|
||||||
|
|
||||||
/* check if an EnterNotify event is coming, and if not, then select
|
/* check if an EnterNotify event is coming, and if not, then select
|
||||||
nothing in the menu */
|
nothing in the menu */
|
||||||
if (XCheckIfEvent(obt_display, &ce, event_look_for_menu_enter,
|
if (!xqueue_exists_local(event_look_for_menu_enter, e->frame))
|
||||||
(XPointer)e->frame))
|
|
||||||
XPutBackEvent(obt_display, &ce);
|
|
||||||
else
|
|
||||||
menu_frame_select(e->frame, NULL, FALSE);
|
menu_frame_select(e->frame, NULL, FALSE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2218,16 +2197,19 @@ gboolean event_time_after(guint32 t1, guint32 t2)
|
||||||
return t1 >= t2 && t1 < (t2 + TIME_HALF);
|
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);
|
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)
|
Time event_time(void)
|
||||||
{
|
{
|
||||||
XEvent event;
|
|
||||||
|
|
||||||
if (event_curtime) return event_curtime;
|
if (event_curtime) return event_curtime;
|
||||||
|
|
||||||
/* Some events don't come with timestamps :(
|
/* Some events don't come with timestamps :(
|
||||||
|
@ -2240,10 +2222,12 @@ Time event_time(void)
|
||||||
8, PropModeAppend, NULL, 0);
|
8, PropModeAppend, NULL, 0);
|
||||||
|
|
||||||
/* Grab the first timestamp available */
|
/* 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 */
|
/* 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)
|
Time event_source_time(void)
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "obrender/theme.h"
|
#include "obrender/theme.h"
|
||||||
#include "obt/display.h"
|
#include "obt/display.h"
|
||||||
|
#include "obt/xqueue.h"
|
||||||
#include "obt/prop.h"
|
#include "obt/prop.h"
|
||||||
|
|
||||||
#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
|
#define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \
|
||||||
|
@ -1042,33 +1043,24 @@ void frame_grab_client(ObFrame *self)
|
||||||
window_add(&self->rgripbottom, CLIENT_AS_WINDOW(self->client));
|
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)
|
void frame_release_client(ObFrame *self)
|
||||||
{
|
{
|
||||||
XEvent ev;
|
|
||||||
gboolean reparent = TRUE;
|
|
||||||
|
|
||||||
/* if there was any animation going on, kill it */
|
/* if there was any animation going on, kill it */
|
||||||
obt_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
|
obt_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify,
|
||||||
self, FALSE);
|
self, FALSE);
|
||||||
|
|
||||||
/* check if the app has already reparented its window away */
|
/* check if the app has already reparented its window away */
|
||||||
while (XCheckTypedWindowEvent(obt_display, self->client->window,
|
if (!xqueue_exists_local(find_reparent, self)) {
|
||||||
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) {
|
|
||||||
/* according to the ICCCM - if the client doesn't reparent itself,
|
/* according to the ICCCM - if the client doesn't reparent itself,
|
||||||
then we will reparent the window to root for them */
|
then we will reparent the window to root for them */
|
||||||
XReparentWindow(obt_display, self->client->window, obt_root(ob_screen),
|
XReparentWindow(obt_display, self->client->window, obt_root(ob_screen),
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "obrender/render.h"
|
#include "obrender/render.h"
|
||||||
#include "obrender/theme.h"
|
#include "obrender/theme.h"
|
||||||
#include "obt/display.h"
|
#include "obt/display.h"
|
||||||
|
#include "obt/xqueue.h"
|
||||||
#include "obt/prop.h"
|
#include "obt/prop.h"
|
||||||
#include "obt/keyboard.h"
|
#include "obt/keyboard.h"
|
||||||
|
|
||||||
|
@ -672,7 +673,8 @@ static void move_with_keys(KeySym sym, guint state)
|
||||||
XSync(obt_display, FALSE);
|
XSync(obt_display, FALSE);
|
||||||
{
|
{
|
||||||
XEvent ce;
|
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);
|
screen_pointer_pos(&px, &py);
|
||||||
|
|
||||||
|
@ -831,7 +833,8 @@ static void resize_with_keys(KeySym sym, guint state)
|
||||||
XSync(obt_display, FALSE);
|
XSync(obt_display, FALSE);
|
||||||
{
|
{
|
||||||
XEvent ce;
|
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);
|
screen_pointer_pos(&px, &py);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "obrender/render.h"
|
#include "obrender/render.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "obt/display.h"
|
#include "obt/display.h"
|
||||||
|
#include "obt/xqueue.h"
|
||||||
#include "obt/prop.h"
|
#include "obt/prop.h"
|
||||||
#include "obt/mainloop.h"
|
#include "obt/mainloop.h"
|
||||||
|
|
||||||
|
@ -129,14 +130,16 @@ static gboolean replace_wm(void)
|
||||||
|
|
||||||
/* Wait for old window manager to go away */
|
/* Wait for old window manager to go away */
|
||||||
if (current_wm_sn_owner) {
|
if (current_wm_sn_owner) {
|
||||||
XEvent event;
|
|
||||||
gulong wait = 0;
|
gulong wait = 0;
|
||||||
const gulong timeout = G_USEC_PER_SEC * 15; /* wait for 15s max */
|
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) {
|
while (wait < timeout) {
|
||||||
if (XCheckWindowEvent(obt_display, current_wm_sn_owner,
|
/* Checks the local queue and incoming events for this event */
|
||||||
StructureNotifyMask, &event) &&
|
if (xqueue_exists_local(xqueue_match_window_type, &wt))
|
||||||
event.type == DestroyNotify)
|
|
||||||
break;
|
break;
|
||||||
g_usleep(G_USEC_PER_SEC / 10);
|
g_usleep(G_USEC_PER_SEC / 10);
|
||||||
wait += G_USEC_PER_SEC / 10;
|
wait += G_USEC_PER_SEC / 10;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "prompt.h"
|
#include "prompt.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "grab.h"
|
#include "grab.h"
|
||||||
|
#include "obt/xqueue.h"
|
||||||
|
|
||||||
static GHashTable *window_map;
|
static GHashTable *window_map;
|
||||||
|
|
||||||
|
@ -146,16 +147,15 @@ void window_manage_all(void)
|
||||||
if (children) XFree(children);
|
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) ||
|
return ((e->type == DestroyNotify && e->xdestroywindow.window == win) ||
|
||||||
(e->type == UnmapNotify && e->xunmap.window == win));
|
(e->type == UnmapNotify && e->xunmap.window == win));
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_manage(Window win)
|
void window_manage(Window win)
|
||||||
{
|
{
|
||||||
XEvent e;
|
|
||||||
XWindowAttributes attrib;
|
XWindowAttributes attrib;
|
||||||
gboolean no_manage = FALSE;
|
gboolean no_manage = FALSE;
|
||||||
gboolean is_dockapp = 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
|
/* 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 */
|
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.");
|
ob_debug("Trying to manage unmapped window. Aborting that.");
|
||||||
no_manage = TRUE;
|
no_manage = TRUE;
|
||||||
}
|
}
|
||||||
|
else if (!XGetWindowAttributes(obt_display, win, &attrib))
|
||||||
if (!XGetWindowAttributes(obt_display, win, &attrib))
|
|
||||||
no_manage = TRUE;
|
no_manage = TRUE;
|
||||||
else {
|
else {
|
||||||
XWMHints *wmhints;
|
XWMHints *wmhints;
|
||||||
|
|
Loading…
Reference in a new issue