~ubuntu-branches/debian/sid/openbox/sid

« back to all changes in this revision

Viewing changes to obt/xqueue.c

  • Committer: Bazaar Package Importer
  • Author(s): Nico Golde, Nico Golde, Eugenio Paolantonio
  • Date: 2011-10-03 22:59:30 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20111003225930-tdvyax5tx63dyoez
Tags: 3.5.0-1
[Nico Golde]
* New upstream release (Closes: #638783).
  - Fix crashes in the menu code (Closes: #563891).
* Add Brazilian translation to openbox.desktop,
  thanks Sérgio Cipolla (Closes: #627912).
* Remove 06_fix_swap_byte_order.patch, applied upstream.
* Bump debhelper dependency to >= 7.0.50~ due to override.
* Remove CHANGELOG from openbox.docs to prevent double installation.
* Add 02_fix_freedesktop_compliance.dpatch desktop file to
  /usr/share/applications.

[Eugenio Paolantonio]
* debian/patches:
  - Disabled 03_place_windows_in_quadrants.patch
  - Updated 01_rc.xml.patch and 06_fix_swap_byte_order.patch
  - Removed 04_fix_ftbfs_no-add-needed.patch and 20_24bits_support.patch
* debian/control:
  - Added myself to the Uploaders.
  - Build-Depends: removed libxau-dev, libxft-dev and python-xdg;
    added libimlib2-dev
  - openbox Suggests: added python-xdg
  - libobrender21 renamed to libobrender27
  - libobparser21 renamed to libobt0
* debian/rules:
  - Rewrote using a simpler debhelper syntax
  - Moved the install pass to openbox.install
* debian/*.{install,links,dirs}:
  - Updated.
* debian/openbox.xsession:
  - Removed. Openbox now ships it by default.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
 
2
 
 
3
   obt/display.c for the Openbox window manager
 
4
   Copyright (c) 2007        Dana Jansens
 
5
 
 
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.
 
10
 
 
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.
 
15
 
 
16
   See the COPYING file for a copy of the GNU General Public License.
 
17
*/
 
18
 
 
19
#include "obt/xqueue.h"
 
20
#include "obt/display.h"
 
21
 
 
22
#define MINSZ 16
 
23
 
 
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;
 
29
 
 
30
static inline void shrink(void) {
 
31
    if (qsz > MINSZ && qnum < qsz / 4) {
 
32
        const gulong newsz = qsz/2;
 
33
        gulong i;
 
34
 
 
35
        if (qnum == 0) {
 
36
            qstart = 0;
 
37
            qend = -1;
 
38
        }
 
39
 
 
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)
 
43
                q[i] = q[qstart+i];
 
44
            qstart = 0;
 
45
            qend = qnum - 1;
 
46
        }
 
47
 
 
48
        /* it wraps around to 0 right now, move the part between newsz and qsz
 
49
           to be before newsz */
 
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];
 
54
            qstart = newsz-n;
 
55
        }
 
56
 
 
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)
 
61
                q[i] = q[newsz+i];
 
62
            qend = n - 1;
 
63
        }
 
64
 
 
65
        q = g_renew(XEvent, q, newsz);
 
66
        qsz = newsz;
 
67
    }
 
68
}
 
69
 
 
70
static inline void grow(void) {
 
71
    if (qnum == qsz) {
 
72
        const gulong newsz = qsz*2;
 
73
        gulong i;
 
74
 
 
75
        q = g_renew(XEvent, q, newsz);
 
76
 
 
77
        g_assert(qnum > 0);
 
78
 
 
79
        if (qend < qstart) { /* it wraps around to 0 right now */
 
80
            for (i = 0; i <= qend; ++i)
 
81
                q[qsz+i] = q[i];
 
82
            qend = qsz + qend;
 
83
        }
 
84
 
 
85
        qsz = newsz;
 
86
    }
 
87
}
 
88
 
 
89
/* Grab all pending X events */
 
90
static gboolean read_events(gboolean block)
 
91
{
 
92
    gint sth, n;
 
93
 
 
94
    n = XEventsQueued(obt_display, QueuedAfterFlush) > 0;
 
95
    sth = FALSE;
 
96
 
 
97
    while ((block && !sth) || n > 0) {
 
98
        XEvent e;
 
99
 
 
100
        if (XNextEvent(obt_display, &e) != Success)
 
101
            return FALSE;
 
102
 
 
103
        grow(); /* make sure there is room */
 
104
 
 
105
        ++qnum;
 
106
        qend = (qend + 1) % qsz; /* move the end */
 
107
        q[qend] = e; /* stick the event at the end */
 
108
 
 
109
        --n;
 
110
        sth = TRUE;
 
111
    }
 
112
 
 
113
    return sth; /* return if we read anything */
 
114
}
 
115
 
 
116
static void pop(const gulong p)
 
117
{
 
118
    /* remove the event */
 
119
    --qnum;
 
120
    if (qnum == 0) {
 
121
        qstart = 0;
 
122
        qend = -1;
 
123
    }
 
124
    else if (p == qstart)
 
125
        qstart = (qstart + 1) % qsz;
 
126
    else {
 
127
        gulong pi;
 
128
 
 
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))
 
132
        {
 
133
            /* move the start */
 
134
            pi = p;
 
135
            while (pi != qstart) {
 
136
                const gulong pi_next = (pi == 0 ? qsz-1 : pi-1);
 
137
 
 
138
                q[pi] = q[pi_next];
 
139
                pi = pi_next;
 
140
            }
 
141
            qstart = (qstart + 1) % qsz;
 
142
        }
 
143
        else {
 
144
            /* move the end */
 
145
            pi = p;
 
146
            while (pi != qend) {
 
147
                const gulong pi_next = (pi + 1) % qsz;
 
148
 
 
149
                q[pi] = q[pi_next];
 
150
                pi = pi_next;
 
151
            }
 
152
            qend = (qend == 0 ? qsz-1 : qend-1);
 
153
        }
 
154
    }
 
155
 
 
156
    shrink(); /* shrink the q if too little in it */
 
157
}
 
158
 
 
159
void xqueue_init(void)
 
160
{
 
161
    if (q != NULL) return;
 
162
    qsz = MINSZ;
 
163
    q = g_new(XEvent, qsz);
 
164
    qstart = 0;
 
165
    qend = -1;
 
166
}
 
167
 
 
168
void xqueue_destroy(void)
 
169
{
 
170
    if (q == NULL) return;
 
171
    g_free(q);
 
172
    q = NULL;
 
173
    qsz = 0;
 
174
}
 
175
 
 
176
gboolean xqueue_match_window(XEvent *e, gpointer data)
 
177
{
 
178
    const Window w = *(Window*)data;
 
179
    return e->xany.window == w;
 
180
}
 
181
 
 
182
gboolean xqueue_match_type(XEvent *e, gpointer data)
 
183
{
 
184
    return e->type == GPOINTER_TO_INT(data);
 
185
}
 
186
 
 
187
gboolean xqueue_match_window_type(XEvent *e, gpointer data)
 
188
{
 
189
    const ObtXQueueWindowType x = *(ObtXQueueWindowType*)data;
 
190
    return e->xany.window == x.window && e->type == x.type;
 
191
}
 
192
 
 
193
gboolean xqueue_match_window_message(XEvent *e, gpointer data)
 
194
{
 
195
    const ObtXQueueWindowMessage x = *(ObtXQueueWindowMessage*)data;
 
196
    return e->xany.window == x.window && e->type == ClientMessage &&
 
197
        e->xclient.message_type == x.message;
 
198
}
 
199
 
 
200
gboolean xqueue_peek(XEvent *event_return)
 
201
{
 
202
    g_return_val_if_fail(q != NULL, FALSE);
 
203
    g_return_val_if_fail(event_return != NULL, FALSE);
 
204
 
 
205
    if (!qnum) read_events(TRUE);
 
206
    if (!qnum) return FALSE;
 
207
    *event_return = q[qstart]; /* get the head */
 
208
    return TRUE;
 
209
}
 
210
 
 
211
gboolean xqueue_peek_local(XEvent *event_return)
 
212
{
 
213
    g_return_val_if_fail(q != NULL, FALSE);
 
214
    g_return_val_if_fail(event_return != NULL, FALSE);
 
215
 
 
216
    if (!qnum) read_events(FALSE);
 
217
    if (!qnum) return FALSE;
 
218
    *event_return = q[qstart]; /* get the head */
 
219
    return TRUE;
 
220
}
 
221
 
 
222
gboolean xqueue_next(XEvent *event_return)
 
223
{
 
224
    g_return_val_if_fail(q != NULL, FALSE);
 
225
    g_return_val_if_fail(event_return != NULL, FALSE);
 
226
 
 
227
    if (!qnum) read_events(TRUE);
 
228
    if (qnum) {
 
229
        *event_return = q[qstart]; /* get the head */
 
230
        pop(qstart);
 
231
        return TRUE;
 
232
    }
 
233
 
 
234
    return FALSE;
 
235
}
 
236
 
 
237
gboolean xqueue_next_local(XEvent *event_return)
 
238
{
 
239
    g_return_val_if_fail(q != NULL, FALSE);
 
240
    g_return_val_if_fail(event_return != NULL, FALSE);
 
241
 
 
242
    if (!qnum) read_events(FALSE);
 
243
    if (qnum) {
 
244
        *event_return = q[qstart]; /* get the head */
 
245
        pop(qstart);
 
246
        return TRUE;
 
247
    }
 
248
 
 
249
    return FALSE;
 
250
}
 
251
 
 
252
gboolean xqueue_exists(xqueue_match_func match, gpointer data)
 
253
{
 
254
    gulong i, checked;
 
255
 
 
256
    g_return_val_if_fail(q != NULL, FALSE);
 
257
    g_return_val_if_fail(match != NULL, FALSE);
 
258
 
 
259
    checked = 0;
 
260
    while (TRUE) {
 
261
        for (i = checked; i < qnum; ++i, ++checked) {
 
262
            const gulong p = (qstart + i) % qsz;
 
263
            if (match(&q[p], data))
 
264
                return TRUE;
 
265
        }
 
266
        if (!read_events(TRUE)) break; /* error */
 
267
    }
 
268
    return FALSE;
 
269
}
 
270
 
 
271
gboolean xqueue_exists_local(xqueue_match_func match, gpointer data)
 
272
{
 
273
    gulong i, checked;
 
274
 
 
275
    g_return_val_if_fail(q != NULL, FALSE);
 
276
    g_return_val_if_fail(match != NULL, FALSE);
 
277
 
 
278
    checked = 0;
 
279
    while (TRUE) {
 
280
        for (i = checked; i < qnum; ++i, ++checked) {
 
281
            const gulong p = (qstart + i) % qsz;
 
282
            if (match(&q[p], data))
 
283
                return TRUE;
 
284
        }
 
285
        if (!read_events(FALSE)) break;
 
286
    }
 
287
    return FALSE;
 
288
}
 
289
 
 
290
gboolean xqueue_remove_local(XEvent *event_return,
 
291
                             xqueue_match_func match, gpointer data)
 
292
{
 
293
    gulong i, checked;
 
294
 
 
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);
 
298
 
 
299
    checked = 0;
 
300
    while (TRUE) {
 
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];
 
305
                pop(p);
 
306
                return TRUE;
 
307
            }
 
308
        }
 
309
        if (!read_events(FALSE)) break;
 
310
    }
 
311
    return FALSE;
 
312
}
 
313
 
 
314
gboolean xqueue_pending_local(void)
 
315
{
 
316
    g_return_val_if_fail(q != NULL, FALSE);
 
317
    
 
318
    if (!qnum) read_events(FALSE);
 
319
    return qnum != 0;
 
320
}
 
321
 
 
322
typedef struct _ObtXQueueCB {
 
323
    ObtXQueueFunc func;
 
324
    gpointer data;
 
325
} ObtXQueueCB;
 
326
 
 
327
static ObtXQueueCB *callbacks = NULL;
 
328
static guint n_callbacks = 0;
 
329
 
 
330
static gboolean event_read(GSource *source, GSourceFunc callback,
 
331
                           gpointer data)
 
332
{
 
333
    XEvent ev;
 
334
 
 
335
    while (xqueue_next_local(&ev)) {
 
336
        guint i;
 
337
        for (i = 0; i < n_callbacks; ++i)
 
338
            callbacks[i].func(&ev, callbacks[i].data);
 
339
    }
 
340
 
 
341
    return TRUE; /* repeat */
 
342
}
 
343
 
 
344
static gboolean x_source_prepare(GSource *source, gint *timeout)
 
345
{
 
346
    *timeout = -1;
 
347
    return XPending(obt_display);
 
348
}
 
349
 
 
350
static gboolean x_source_check(GSource *source)
 
351
{
 
352
    return XPending(obt_display);
 
353
}
 
354
 
 
355
struct x_source {
 
356
    GSource source;
 
357
 
 
358
    GPollFD pfd;
 
359
};
 
360
 
 
361
static GSourceFuncs x_source_funcs = {
 
362
    x_source_prepare,
 
363
    x_source_check,
 
364
    event_read,
 
365
    NULL
 
366
};
 
367
 
 
368
void xqueue_listen(void)
 
369
{
 
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;
 
373
 
 
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);
 
377
}
 
378
 
 
379
void xqueue_add_callback(ObtXQueueFunc f, gpointer data)
 
380
{
 
381
    guint i;
 
382
 
 
383
    g_return_if_fail(f != NULL);
 
384
 
 
385
    for (i = 0; i < n_callbacks; ++i)
 
386
        if (callbacks[i].func == f && callbacks[i].data == data)
 
387
            return;
 
388
 
 
389
    callbacks = g_renew(ObtXQueueCB, callbacks, n_callbacks + 1);
 
390
    callbacks[n_callbacks].func = f;
 
391
    callbacks[n_callbacks].data = data;
 
392
    ++n_callbacks;
 
393
}
 
394
 
 
395
void xqueue_remove_callback(ObtXQueueFunc f, gpointer data)
 
396
{
 
397
    guint i;
 
398
 
 
399
    g_return_if_fail(f != NULL);
 
400
 
 
401
    for (i = 0; i < n_callbacks; ++i) {
 
402
        if (callbacks[i].func == f && callbacks[i].data == data) {
 
403
            /* remove it */
 
404
            for (; i < n_callbacks - 1; ++i)
 
405
                callbacks[i] = callbacks[i+1];
 
406
            callbacks = g_renew(ObtXQueueCB, callbacks, n_callbacks - 1);
 
407
            --n_callbacks;
 
408
            break;
 
409
        }
 
410
    }
 
411
}