~profzoom/ubuntu/quantal/wmaker/bug-1079925

« back to all changes in this revision

Viewing changes to WINGs/handlers.c

  • Committer: Bazaar Package Importer
  • Author(s): Marcelo E. Magallon
  • Date: 2004-11-10 14:05:30 UTC
  • Revision ID: james.westby@ubuntu.com-20041110140530-qpd66b5lm38x7apk
Tags: upstream-0.91.0
ImportĀ upstreamĀ versionĀ 0.91.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * WINGs internal handlers: timer, idle and input handlers
 
4
 */
 
5
 
 
6
#include "WINGsP.h"
 
7
 
 
8
#include "../src/config.h"
 
9
 
 
10
#include <sys/types.h>
 
11
#include <unistd.h>
 
12
 
 
13
#include <X11/Xos.h>
 
14
 
 
15
#ifdef HAVE_SYS_SELECT_H
 
16
# include <sys/select.h>
 
17
#endif
 
18
 
 
19
#include <time.h>
 
20
 
 
21
#ifndef X_GETTIMEOFDAY
 
22
#define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
 
23
#endif
 
24
 
 
25
 
 
26
 
 
27
 
 
28
typedef struct TimerHandler {
 
29
    WMCallback          *callback;             /* procedure to call */
 
30
    struct timeval      when;                  /* when to call the callback */
 
31
    void                *clientData;
 
32
    struct TimerHandler *next;
 
33
    int                 nextDelay;             /* 0 if it's one-shot */
 
34
} TimerHandler;
 
35
 
 
36
 
 
37
typedef struct IdleHandler {
 
38
    WMCallback          *callback;
 
39
    void                *clientData;
 
40
} IdleHandler;
 
41
 
 
42
 
 
43
typedef struct InputHandler {
 
44
    WMInputProc         *callback;
 
45
    void                *clientData;
 
46
    int                 fd;
 
47
    int                 mask;
 
48
} InputHandler;
 
49
 
 
50
 
 
51
/* queue of timer event handlers */
 
52
static TimerHandler *timerHandler=NULL;
 
53
 
 
54
static WMArray *idleHandler=NULL;
 
55
 
 
56
static WMArray *inputHandler=NULL;
 
57
 
 
58
#define timerPending()  (timerHandler)
 
59
 
 
60
 
 
61
 
 
62
static void
 
63
rightNow(struct timeval *tv)
 
64
{
 
65
    X_GETTIMEOFDAY(tv);
 
66
}
 
67
 
 
68
/* is t1 after t2 ? */
 
69
#define IS_AFTER(t1, t2)        (((t1).tv_sec > (t2).tv_sec) || \
 
70
    (((t1).tv_sec == (t2).tv_sec) \
 
71
    && ((t1).tv_usec > (t2).tv_usec)))
 
72
 
 
73
#define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0)
 
74
 
 
75
#define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0
 
76
 
 
77
static void
 
78
addmillisecs(struct timeval *tv, int milliseconds)
 
79
{
 
80
    tv->tv_usec += milliseconds*1000;
 
81
 
 
82
    tv->tv_sec += tv->tv_usec/1000000;
 
83
    tv->tv_usec = tv->tv_usec%1000000;
 
84
}
 
85
 
 
86
 
 
87
static void
 
88
enqueueTimerHandler(TimerHandler *handler)
 
89
{
 
90
    TimerHandler *tmp;
 
91
 
 
92
    /* insert callback in queue, sorted by time left */
 
93
    if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) {
 
94
        /* first in the queue */
 
95
        handler->next = timerHandler;
 
96
        timerHandler = handler;
 
97
    } else {
 
98
        tmp = timerHandler;
 
99
        while (tmp->next && IS_AFTER(handler->when, tmp->next->when)) {
 
100
            tmp = tmp->next;
 
101
        }
 
102
        handler->next = tmp->next;
 
103
        tmp->next = handler;
 
104
    }
 
105
}
 
106
 
 
107
 
 
108
static void
 
109
delayUntilNextTimerEvent(struct timeval *delay)
 
110
{
 
111
    struct timeval now;
 
112
    TimerHandler *handler;
 
113
 
 
114
    handler = timerHandler;
 
115
    while (handler && IS_ZERO(handler->when)) handler = handler->next;
 
116
 
 
117
    if (!handler) {
 
118
        /* The return value of this function is only valid if there _are_
 
119
         timers active. */
 
120
        delay->tv_sec = 0;
 
121
        delay->tv_usec = 0;
 
122
        return;
 
123
    }
 
124
 
 
125
    rightNow(&now);
 
126
    if (IS_AFTER(now, handler->when)) {
 
127
        delay->tv_sec = 0;
 
128
        delay->tv_usec = 0;
 
129
    } else {
 
130
        delay->tv_sec = handler->when.tv_sec - now.tv_sec;
 
131
        delay->tv_usec = handler->when.tv_usec - now.tv_usec;
 
132
        if (delay->tv_usec < 0) {
 
133
            delay->tv_usec += 1000000;
 
134
            delay->tv_sec--;
 
135
        }
 
136
    }
 
137
}
 
138
 
 
139
 
 
140
WMHandlerID
 
141
WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
 
142
{
 
143
    TimerHandler *handler;
 
144
 
 
145
    handler = malloc(sizeof(TimerHandler));
 
146
    if (!handler)
 
147
        return NULL;
 
148
 
 
149
    rightNow(&handler->when);
 
150
    addmillisecs(&handler->when, milliseconds);
 
151
    handler->callback = callback;
 
152
    handler->clientData = cdata;
 
153
    handler->nextDelay = 0;
 
154
 
 
155
    enqueueTimerHandler(handler);
 
156
 
 
157
    return handler;
 
158
}
 
159
 
 
160
 
 
161
WMHandlerID
 
162
WMAddPersistentTimerHandler(int milliseconds, WMCallback *callback, void *cdata)
 
163
{
 
164
    TimerHandler *handler = WMAddTimerHandler(milliseconds, callback, cdata);
 
165
 
 
166
    if (handler != NULL)
 
167
        handler->nextDelay = milliseconds;
 
168
 
 
169
    return handler;
 
170
}
 
171
 
 
172
 
 
173
 
 
174
void
 
175
WMDeleteTimerWithClientData(void *cdata)
 
176
{
 
177
    TimerHandler *handler, *tmp;
 
178
 
 
179
    if (!cdata || !timerHandler)
 
180
        return;
 
181
 
 
182
    tmp = timerHandler;
 
183
    if (tmp->clientData==cdata) {
 
184
        tmp->nextDelay = 0;
 
185
        if (!IS_ZERO(tmp->when)) {
 
186
            timerHandler = tmp->next;
 
187
            wfree(tmp);
 
188
        }
 
189
    } else {
 
190
        while (tmp->next) {
 
191
            if (tmp->next->clientData==cdata) {
 
192
                handler = tmp->next;
 
193
                handler->nextDelay = 0;
 
194
                if (IS_ZERO(handler->when))
 
195
                    break;
 
196
                tmp->next = handler->next;
 
197
                wfree(handler);
 
198
                break;
 
199
            }
 
200
            tmp = tmp->next;
 
201
        }
 
202
    }
 
203
}
 
204
 
 
205
 
 
206
 
 
207
void
 
208
WMDeleteTimerHandler(WMHandlerID handlerID)
 
209
{
 
210
    TimerHandler *tmp, *handler=(TimerHandler*)handlerID;
 
211
 
 
212
    if (!handler || !timerHandler)
 
213
        return;
 
214
 
 
215
    tmp = timerHandler;
 
216
 
 
217
    handler->nextDelay = 0;
 
218
 
 
219
    if (IS_ZERO(handler->when))
 
220
        return;
 
221
 
 
222
    if (tmp==handler) {
 
223
        timerHandler = handler->next;
 
224
        wfree(handler);
 
225
    } else {
 
226
        while (tmp->next) {
 
227
            if (tmp->next==handler) {
 
228
                tmp->next=handler->next;
 
229
                wfree(handler);
 
230
                break;
 
231
            }
 
232
            tmp = tmp->next;
 
233
        }
 
234
    }
 
235
}
 
236
 
 
237
 
 
238
 
 
239
WMHandlerID
 
240
WMAddIdleHandler(WMCallback *callback, void *cdata)
 
241
{
 
242
    IdleHandler *handler;
 
243
 
 
244
    handler = malloc(sizeof(IdleHandler));
 
245
    if (!handler)
 
246
        return NULL;
 
247
 
 
248
    handler->callback = callback;
 
249
    handler->clientData = cdata;
 
250
    /* add handler at end of queue */
 
251
    if (!idleHandler) {
 
252
        idleHandler = WMCreateArrayWithDestructor(16, wfree);
 
253
    }
 
254
    WMAddToArray(idleHandler, handler);
 
255
 
 
256
    return handler;
 
257
}
 
258
 
 
259
 
 
260
void
 
261
WMDeleteIdleHandler(WMHandlerID handlerID)
 
262
{
 
263
    IdleHandler *handler = (IdleHandler*)handlerID;
 
264
 
 
265
    if (!handler || !idleHandler)
 
266
        return;
 
267
 
 
268
    WMRemoveFromArray(idleHandler, handler);
 
269
}
 
270
 
 
271
 
 
272
 
 
273
WMHandlerID
 
274
WMAddInputHandler(int fd, int condition, WMInputProc *proc, void *clientData)
 
275
{
 
276
    InputHandler *handler;
 
277
 
 
278
    handler = wmalloc(sizeof(InputHandler));
 
279
 
 
280
    handler->fd = fd;
 
281
    handler->mask = condition;
 
282
    handler->callback = proc;
 
283
    handler->clientData = clientData;
 
284
 
 
285
    if (!inputHandler)
 
286
        inputHandler = WMCreateArrayWithDestructor(16, wfree);
 
287
    WMAddToArray(inputHandler, handler);
 
288
 
 
289
    return handler;
 
290
}
 
291
 
 
292
 
 
293
 
 
294
void
 
295
WMDeleteInputHandler(WMHandlerID handlerID)
 
296
{
 
297
    InputHandler *handler = (InputHandler*)handlerID;
 
298
 
 
299
    if (!handler || !inputHandler)
 
300
        return;
 
301
 
 
302
    WMRemoveFromArray(inputHandler, handler);
 
303
}
 
304
 
 
305
 
 
306
Bool
 
307
W_CheckIdleHandlers(void)
 
308
{
 
309
    IdleHandler *handler;
 
310
    WMArray *handlerCopy;
 
311
    WMArrayIterator iter;
 
312
 
 
313
    if (!idleHandler || WMGetArrayItemCount(idleHandler)==0) {
 
314
        W_FlushIdleNotificationQueue();
 
315
        /* make sure an observer in queue didn't added an idle handler */
 
316
        return (idleHandler!=NULL && WMGetArrayItemCount(idleHandler)>0);
 
317
    }
 
318
 
 
319
    handlerCopy = WMDuplicateArray(idleHandler);
 
320
 
 
321
    WM_ITERATE_ARRAY(handlerCopy, handler, iter) {
 
322
        /* check if the handler still exist or was removed by a callback */
 
323
        if (WMGetFirstInArray(idleHandler, handler) == WANotFound)
 
324
            continue;
 
325
 
 
326
        (*handler->callback)(handler->clientData);
 
327
        WMDeleteIdleHandler(handler);
 
328
    }
 
329
 
 
330
    WMFreeArray(handlerCopy);
 
331
 
 
332
    W_FlushIdleNotificationQueue();
 
333
 
 
334
    /* this is not necesarrily False, because one handler can re-add itself */
 
335
    return (WMGetArrayItemCount(idleHandler)>0);
 
336
}
 
337
 
 
338
 
 
339
 
 
340
void
 
341
W_CheckTimerHandlers(void)
 
342
{
 
343
    TimerHandler *handler;
 
344
    struct timeval now;
 
345
 
 
346
    if (!timerHandler) {
 
347
        W_FlushASAPNotificationQueue();
 
348
        return;
 
349
    }
 
350
 
 
351
    rightNow(&now);
 
352
 
 
353
    handler = timerHandler;
 
354
    while (handler && IS_AFTER(now, handler->when)) {
 
355
        if (!IS_ZERO(handler->when)) {
 
356
            SET_ZERO(handler->when);
 
357
            (*handler->callback)(handler->clientData);
 
358
        }
 
359
        handler = handler->next;
 
360
    }
 
361
 
 
362
    while (timerHandler && IS_ZERO(timerHandler->when)) {
 
363
        handler = timerHandler;
 
364
        timerHandler = timerHandler->next;
 
365
 
 
366
        if (handler->nextDelay > 0) {
 
367
            handler->when = now;
 
368
            addmillisecs(&handler->when, handler->nextDelay);
 
369
            enqueueTimerHandler(handler);
 
370
        } else {
 
371
            wfree(handler);
 
372
        }
 
373
    }
 
374
 
 
375
    W_FlushASAPNotificationQueue();
 
376
}
 
377
 
 
378
 
 
379
/*
 
380
 * This functions will handle input events on all registered file descriptors.
 
381
 * Input:
 
382
 *    - waitForInput - True if we want the function to wait until an event
 
383
 *                     appears on a file descriptor we watch, False if we
 
384
 *                     want the function to immediately return if there is
 
385
 *                     no data available on the file descriptors we watch.
 
386
 *    - inputfd      - Extra input file descriptor to watch for input.
 
387
 *                     This is only used when called from wevent.c to watch
 
388
 *                     on ConnectionNumber(dpy) to avoid blocking of X events
 
389
 *                     if we wait for input from other file handlers.
 
390
 * Output:
 
391
 *    if waitForInput is False, the function will return False if there are no
 
392
 *                     input handlers registered, or if there is no data
 
393
 *                     available on the registered ones, and will return True
 
394
 *                     if there is at least one input handler that has data
 
395
 *                     available.
 
396
 *    if waitForInput is True, the function will return False if there are no
 
397
 *                     input handlers registered, else it will block until an
 
398
 *                     event appears on one of the file descriptors it watches
 
399
 *                     and then it will return True.
 
400
 *
 
401
 * If the retured value is True, the input handlers for the corresponding file
 
402
 * descriptors are also called.
 
403
 *
 
404
 * Parametersshould be passed like this:
 
405
 * - from wevent.c:
 
406
 *   waitForInput - apropriate value passed by the function who called us
 
407
 *   inputfd = ConnectionNumber(dpy)
 
408
 * - from wutil.c:
 
409
 *   waitForInput - apropriate value passed by the function who called us
 
410
 *   inputfd = -1
 
411
 *
 
412
 */
 
413
Bool
 
414
W_HandleInputEvents(Bool waitForInput, int inputfd)
 
415
{
 
416
#if defined(HAVE_POLL) && defined(HAVE_POLL_H) && !defined(HAVE_SELECT)
 
417
    struct poll fd *fds;
 
418
    InputHandler *handler;
 
419
    int count, timeout, nfds, i, extrafd;
 
420
 
 
421
    extrafd = (inputfd < 0) ? 0 : 1;
 
422
 
 
423
    if (inputHandler)
 
424
        nfds = WMGetArrayItemCount(inputHandler);
 
425
    else
 
426
        nfds = 0;
 
427
 
 
428
    if (!extrafd && nfds==0) {
 
429
        W_FlushASAPNotificationQueue();
 
430
        return False;
 
431
    }
 
432
 
 
433
    fds = wmalloc((nfds+extrafd) * sizeof(struct pollfd));
 
434
    if (extrafd) {
 
435
        /* put this to the end of array to avoid using ranges from 1 to nfds+1 */
 
436
        fds[nfds].fd = inputfd;
 
437
        fds[nfds].events = POLLIN;
 
438
    }
 
439
 
 
440
    /* use WM_ITERATE_ARRAY() here */
 
441
    for (i = 0; i<nfds; i++) {
 
442
        handler = WMGetFromArray(inputHandler, i);
 
443
        fds[i].fd = handler->fd;
 
444
        fds[i].events = 0;
 
445
        if (handler->mask & WIReadMask)
 
446
            fds[i].events |= POLLIN;
 
447
 
 
448
        if (handler->mask & WIWriteMask)
 
449
            fds[i].events |= POLLOUT;
 
450
 
 
451
#if 0 /* FIXME */
 
452
        if (handler->mask & WIExceptMask)
 
453
            FD_SET(handler->fd, &eset);
 
454
#endif
 
455
    }
 
456
 
 
457
    /*
 
458
     * Setup the timeout to the estimated time until the
 
459
     * next timer expires.
 
460
     */
 
461
    if (!waitForInput) {
 
462
        timeout = 0;
 
463
    } else if (timerPending()) {
 
464
        struct timeval tv;
 
465
        delayUntilNextTimerEvent(&tv);
 
466
        timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 
467
    } else {
 
468
        timeout = -1;
 
469
    }
 
470
 
 
471
    count = poll(fds, nfds+extrafd, timeout);
 
472
 
 
473
    if (count>0 && nfds>0) {
 
474
        WMArray *handlerCopy = WMDuplicateArray(inputHandler);
 
475
        int mask;
 
476
 
 
477
        /* use WM_ITERATE_ARRAY() here */
 
478
        for (i=0; i<nfds; i++) {
 
479
            handler = WMGetFromArray(handlerCopy, i);
 
480
            /* check if the handler still exist or was removed by a callback */
 
481
            if (WMGetFirstInArray(inputHandler, handler) == WANotFound)
 
482
                continue;
 
483
 
 
484
            mask = 0;
 
485
 
 
486
            if ((handler->mask & WIReadMask) &&
 
487
                (fds[i].revents & (POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI)))
 
488
                mask |= WIReadMask;
 
489
 
 
490
            if ((handler->mask & WIWriteMask) &&
 
491
                (fds[i].revents & (POLLOUT | POLLWRBAND)))
 
492
                mask |= WIWriteMask;
 
493
 
 
494
            if ((handler->mask & WIExceptMask) &&
 
495
                (fds[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
 
496
                mask |= WIExceptMask;
 
497
 
 
498
            if (mask!=0 && handler->callback) {
 
499
                (*handler->callback)(handler->fd, mask,
 
500
                                     handler->clientData);
 
501
            }
 
502
        }
 
503
 
 
504
        WMFreeArray(handlerCopy);
 
505
    }
 
506
 
 
507
    wfree(fds);
 
508
 
 
509
    W_FlushASAPNotificationQueue();
 
510
 
 
511
    return (count > 0);
 
512
#else
 
513
#ifdef HAVE_SELECT
 
514
    struct timeval timeout;
 
515
    struct timeval *timeoutPtr;
 
516
    fd_set rset, wset, eset;
 
517
    int maxfd, nfds, i;
 
518
    int count;
 
519
    InputHandler *handler;
 
520
 
 
521
    if (inputHandler)
 
522
        nfds = WMGetArrayItemCount(inputHandler);
 
523
    else
 
524
        nfds = 0;
 
525
 
 
526
    if (inputfd<0 && nfds==0) {
 
527
        W_FlushASAPNotificationQueue();
 
528
        return False;
 
529
    }
 
530
 
 
531
    FD_ZERO(&rset);
 
532
    FD_ZERO(&wset);
 
533
    FD_ZERO(&eset);
 
534
 
 
535
    if (inputfd < 0) {
 
536
        maxfd = 0;
 
537
    } else {
 
538
        FD_SET(inputfd, &rset);
 
539
        maxfd = inputfd;
 
540
    }
 
541
 
 
542
    /* use WM_ITERATE_ARRAY() here */
 
543
    for (i=0; i<nfds; i++) {
 
544
        handler = WMGetFromArray(inputHandler, i);
 
545
        if (handler->mask & WIReadMask)
 
546
            FD_SET(handler->fd, &rset);
 
547
 
 
548
        if (handler->mask & WIWriteMask)
 
549
            FD_SET(handler->fd, &wset);
 
550
 
 
551
        if (handler->mask & WIExceptMask)
 
552
            FD_SET(handler->fd, &eset);
 
553
 
 
554
        if (maxfd < handler->fd)
 
555
            maxfd = handler->fd;
 
556
    }
 
557
 
 
558
    /*
 
559
     * Setup the timeout to the estimated time until the
 
560
     * next timer expires.
 
561
     */
 
562
    if (!waitForInput) {
 
563
        SET_ZERO(timeout);
 
564
        timeoutPtr = &timeout;
 
565
    } else if (timerPending()) {
 
566
        delayUntilNextTimerEvent(&timeout);
 
567
        timeoutPtr = &timeout;
 
568
    } else {
 
569
        timeoutPtr = (struct timeval*)0;
 
570
    }
 
571
 
 
572
    count = select(1 + maxfd, &rset, &wset, &eset, timeoutPtr);
 
573
 
 
574
    if (count>0 && nfds>0) {
 
575
        WMArray *handlerCopy = WMDuplicateArray(inputHandler);
 
576
        int mask;
 
577
 
 
578
        /* use WM_ITERATE_ARRAY() here */
 
579
        for (i=0; i<nfds; i++) {
 
580
            handler = WMGetFromArray(handlerCopy, i);
 
581
            /* check if the handler still exist or was removed by a callback */
 
582
            if (WMGetFirstInArray(inputHandler, handler) == WANotFound)
 
583
                continue;
 
584
 
 
585
            mask = 0;
 
586
 
 
587
            if ((handler->mask & WIReadMask) && FD_ISSET(handler->fd, &rset))
 
588
                mask |= WIReadMask;
 
589
 
 
590
            if ((handler->mask & WIWriteMask) && FD_ISSET(handler->fd, &wset))
 
591
                mask |= WIWriteMask;
 
592
 
 
593
            if ((handler->mask & WIExceptMask) && FD_ISSET(handler->fd, &eset))
 
594
                mask |= WIExceptMask;
 
595
 
 
596
            if (mask!=0 && handler->callback) {
 
597
                (*handler->callback)(handler->fd, mask,
 
598
                                     handler->clientData);
 
599
            }
 
600
        }
 
601
 
 
602
        WMFreeArray(handlerCopy);
 
603
    }
 
604
 
 
605
    W_FlushASAPNotificationQueue();
 
606
 
 
607
    return (count > 0);
 
608
#else /* not HAVE_SELECT, not HAVE_POLL */
 
609
# error   Neither select nor poll. You lose.
 
610
#endif /* HAVE_SELECT */
 
611
#endif /* HAVE_POLL */
 
612
}
 
613
 
 
614