1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 obt/display.c for the Openbox window manager
4 Copyright (c) 2007 Dana Jansens
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 See the COPYING file for a copy of the GNU General Public License.
19 #include "obt/xqueue.h"
20 #include "obt/display.h"
24 static XEvent
*q
= NULL
;
25 static gulong qsz
= 0;
26 static gulong qstart
; /* the first event in the queue */
27 static gulong qend
; /* the last event in the queue */
28 static gulong qnum
= 0;
30 static inline void shrink(void) {
31 if (qsz
> MINSZ
&& qnum
< qsz
/ 4) {
32 const gulong newsz
= qsz
/2;
40 /* all in the shinking part, move it to pos 0 */
41 else if (qstart
>= newsz
&& qend
>= newsz
) {
42 for (i
= 0; i
< qnum
; ++i
)
48 /* it wraps around to 0 right now, move the part between newsz and qsz
50 else if (qstart
>= newsz
) {
51 const gulong n
= qsz
- qstart
;
52 for (i
= 0; i
< n
; ++i
)
53 q
[newsz
-n
+i
] = q
[qstart
+i
];
57 /* it needs to wrap around to 0, move the stuff after newsz to pos 0 */
58 else if (qend
>= newsz
) {
59 const gulong n
= qend
+ 1 - newsz
;
60 for (i
= 0; i
< n
; ++i
)
65 q
= g_renew(XEvent
, q
, newsz
);
70 static inline void grow(void) {
72 const gulong newsz
= qsz
*2;
75 q
= g_renew(XEvent
, q
, newsz
);
79 if (qend
< qstart
) { /* it wraps around to 0 right now */
80 for (i
= 0; i
<= qend
; ++i
)
89 /* Grab all pending X events */
90 static gboolean
read_events(gboolean block
)
94 n
= XEventsQueued(obt_display
, QueuedAfterFlush
) > 0;
97 while ((block
&& !sth
) || n
> 0) {
100 if (XNextEvent(obt_display
, &e
) != Success
)
103 grow(); /* make sure there is room */
106 qend
= (qend
+ 1) % qsz
; /* move the end */
107 q
[qend
] = e
; /* stick the event at the end */
113 return sth
; /* return if we read anything */
116 static void pop(const gulong p
)
118 /* remove the event */
124 else if (p
== qstart
)
125 qstart
= (qstart
+ 1) % qsz
;
129 /* is it cheaper to move the start or the end ? */
130 if ((p
>= qstart
&& p
< qstart
+ qnum
/2) ||
131 (p
< qstart
&& p
< (qstart
+ qnum
/2) % qsz
))
135 while (pi
!= qstart
) {
136 const gulong pi_next
= (pi
== 0 ? qsz
-1 : pi
-1);
141 qstart
= (qstart
+ 1) % qsz
;
147 const gulong pi_next
= (pi
+ 1) % qsz
;
152 qend
= (qend
== 0 ? qsz
-1 : qend
-1);
156 shrink(); /* shrink the q if too little in it */
159 void xqueue_init(void)
161 if (q
!= NULL
) return;
163 q
= g_new(XEvent
, qsz
);
168 void xqueue_destroy(void)
170 if (q
== NULL
) return;
176 gboolean
xqueue_match_window(XEvent
*e
, gpointer data
)
178 const Window w
= *(Window
*)data
;
179 return e
->xany
.window
== w
;
182 gboolean
xqueue_match_type(XEvent
*e
, gpointer data
)
184 return e
->type
== GPOINTER_TO_INT(data
);
187 gboolean
xqueue_match_window_type(XEvent
*e
, gpointer data
)
189 const ObtXQueueWindowType x
= *(ObtXQueueWindowType
*)data
;
190 return e
->xany
.window
== x
.window
&& e
->type
== x
.type
;
193 gboolean
xqueue_match_window_message(XEvent
*e
, gpointer data
)
195 const ObtXQueueWindowMessage x
= *(ObtXQueueWindowMessage
*)data
;
196 return e
->xany
.window
== x
.window
&& e
->type
== ClientMessage
&&
197 e
->xclient
.message_type
== x
.message
;
200 gboolean
xqueue_peek(XEvent
*event_return
)
202 g_return_val_if_fail(q
!= NULL
, FALSE
);
203 g_return_val_if_fail(event_return
!= NULL
, FALSE
);
205 if (!qnum
) read_events(TRUE
);
206 if (!qnum
) return FALSE
;
207 *event_return
= q
[qstart
]; /* get the head */
211 gboolean
xqueue_peek_local(XEvent
*event_return
)
213 g_return_val_if_fail(q
!= NULL
, FALSE
);
214 g_return_val_if_fail(event_return
!= NULL
, FALSE
);
216 if (!qnum
) read_events(FALSE
);
217 if (!qnum
) return FALSE
;
218 *event_return
= q
[qstart
]; /* get the head */
222 gboolean
xqueue_next(XEvent
*event_return
)
224 g_return_val_if_fail(q
!= NULL
, FALSE
);
225 g_return_val_if_fail(event_return
!= NULL
, FALSE
);
227 if (!qnum
) read_events(TRUE
);
229 *event_return
= q
[qstart
]; /* get the head */
237 gboolean
xqueue_next_local(XEvent
*event_return
)
239 g_return_val_if_fail(q
!= NULL
, FALSE
);
240 g_return_val_if_fail(event_return
!= NULL
, FALSE
);
242 if (!qnum
) read_events(FALSE
);
244 *event_return
= q
[qstart
]; /* get the head */
252 gboolean
xqueue_exists(xqueue_match_func match
, gpointer data
)
256 g_return_val_if_fail(q
!= NULL
, FALSE
);
257 g_return_val_if_fail(match
!= NULL
, FALSE
);
261 for (i
= checked
; i
< qnum
; ++i
, ++checked
) {
262 const gulong p
= (qstart
+ i
) % qsz
;
263 if (match(&q
[p
], data
))
266 if (!read_events(TRUE
)) break; /* error */
271 gboolean
xqueue_exists_local(xqueue_match_func match
, gpointer data
)
275 g_return_val_if_fail(q
!= NULL
, FALSE
);
276 g_return_val_if_fail(match
!= NULL
, FALSE
);
280 for (i
= checked
; i
< qnum
; ++i
, ++checked
) {
281 const gulong p
= (qstart
+ i
) % qsz
;
282 if (match(&q
[p
], data
))
285 if (!read_events(FALSE
)) break;
290 gboolean
xqueue_remove_local(XEvent
*event_return
,
291 xqueue_match_func match
, gpointer data
)
295 g_return_val_if_fail(q
!= NULL
, FALSE
);
296 g_return_val_if_fail(event_return
!= NULL
, FALSE
);
297 g_return_val_if_fail(match
!= NULL
, FALSE
);
301 for (i
= checked
; i
< qnum
; ++i
, ++checked
) {
302 const gulong p
= (qstart
+ i
) % qsz
;
303 if (match(&q
[p
], data
)) {
304 *event_return
= q
[p
];
309 if (!read_events(FALSE
)) break;
314 gboolean
xqueue_pending_local(void)
316 g_return_val_if_fail(q
!= NULL
, FALSE
);
318 if (!qnum
) read_events(FALSE
);
322 typedef struct _ObtXQueueCB
{
327 static ObtXQueueCB
*callbacks
= NULL
;
328 static guint n_callbacks
= 0;
330 static gboolean
event_read(GSource
*source
, GSourceFunc callback
,
335 while (xqueue_next_local(&ev
)) {
337 for (i
= 0; i
< n_callbacks
; ++i
)
338 callbacks
[i
].func(&ev
, callbacks
[i
].data
);
341 return TRUE
; /* repeat */
344 static gboolean
x_source_prepare(GSource
*source
, gint
*timeout
)
347 return XPending(obt_display
);
350 static gboolean
x_source_check(GSource
*source
)
352 return XPending(obt_display
);
361 static GSourceFuncs x_source_funcs
= {
368 void xqueue_listen(void)
370 GSource
*source
= g_source_new(&x_source_funcs
, sizeof(struct x_source
));
371 struct x_source
*x_source
= (struct x_source
*)source
;
372 GPollFD
*pfd
= &x_source
->pfd
;
374 *pfd
= (GPollFD
){ ConnectionNumber(obt_display
), G_IO_IN
, G_IO_IN
};
375 g_source_add_poll(source
, pfd
);
376 g_source_attach(source
, NULL
);
379 void xqueue_add_callback(ObtXQueueFunc f
, gpointer data
)
383 g_return_if_fail(f
!= NULL
);
385 for (i
= 0; i
< n_callbacks
; ++i
)
386 if (callbacks
[i
].func
== f
&& callbacks
[i
].data
== data
)
389 callbacks
= g_renew(ObtXQueueCB
, callbacks
, n_callbacks
+ 1);
390 callbacks
[n_callbacks
].func
= f
;
391 callbacks
[n_callbacks
].data
= data
;
395 void xqueue_remove_callback(ObtXQueueFunc f
, gpointer data
)
399 g_return_if_fail(f
!= NULL
);
401 for (i
= 0; i
< n_callbacks
; ++i
) {
402 if (callbacks
[i
].func
== f
&& callbacks
[i
].data
== data
) {
404 for (; i
< n_callbacks
- 1; ++i
)
405 callbacks
[i
] = callbacks
[i
+1];
406 callbacks
= g_renew(ObtXQueueCB
, callbacks
, n_callbacks
- 1);