OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tk/] [unix/] [tkUnixEvent.c] - Blame information for rev 1770

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkUnixEvent.c --
3
 *
4
 *      This file implements an event source for X displays for the
5
 *      UNIX version of Tk.
6
 *
7
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
8
 *
9
 * See the file "license.terms" for information on usage and redistribution
10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11
 *
12
 * RCS: @(#) $Id: tkUnixEvent.c,v 1.1.1.1 2002-01-16 10:26:01 markom Exp $
13
 */
14
 
15
#include "tkInt.h"
16
#include "tkUnixInt.h"
17
#include <signal.h>
18
 
19
/*
20
 * The following static indicates whether this module has been initialized.
21
 */
22
 
23
static int initialized = 0;
24
 
25
/*
26
 * Prototypes for procedures that are referenced only in this file:
27
 */
28
 
29
static void             DisplayCheckProc _ANSI_ARGS_((ClientData clientData,
30
                            int flags));
31
static void             DisplayExitHandler _ANSI_ARGS_((
32
                            ClientData clientData));
33
static void             DisplayFileProc _ANSI_ARGS_((ClientData clientData,
34
                            int flags));
35
static void             DisplaySetupProc _ANSI_ARGS_((ClientData clientData,
36
                            int flags));
37
 
38
/*
39
 *----------------------------------------------------------------------
40
 *
41
 * TkCreateXEventSource --
42
 *
43
 *      This procedure is called during Tk initialization to create
44
 *      the event source for X Window events.
45
 *
46
 * Results:
47
 *      None.
48
 *
49
 * Side effects:
50
 *      A new event source is created.
51
 *
52
 *----------------------------------------------------------------------
53
 */
54
 
55
void
56
TkCreateXEventSource()
57
{
58
    if (!initialized) {
59
        initialized = 1;
60
        Tcl_CreateEventSource(DisplaySetupProc, DisplayCheckProc, NULL);
61
        Tcl_CreateExitHandler(DisplayExitHandler, NULL);
62
    }
63
}
64
 
65
/*
66
 *----------------------------------------------------------------------
67
 *
68
 * DisplayExitHandler --
69
 *
70
 *      This function is called during finalization to clean up the
71
 *      display module.
72
 *
73
 * Results:
74
 *      None.
75
 *
76
 * Side effects:
77
 *      None.
78
 *
79
 *----------------------------------------------------------------------
80
 */
81
 
82
static void
83
DisplayExitHandler(clientData)
84
    ClientData clientData;      /* Not used. */
85
{
86
    Tcl_DeleteEventSource(DisplaySetupProc, DisplayCheckProc, NULL);
87
    initialized = 0;
88
}
89
 
90
/*
91
 *----------------------------------------------------------------------
92
 *
93
 * TkpOpenDisplay --
94
 *
95
 *      Allocates a new TkDisplay, opens the X display, and establishes
96
 *      the file handler for the connection.
97
 *
98
 * Results:
99
 *      A pointer to a Tk display structure.
100
 *
101
 * Side effects:
102
 *      Opens a display.
103
 *
104
 *----------------------------------------------------------------------
105
 */
106
 
107
TkDisplay *
108
TkpOpenDisplay(display_name)
109
    char *display_name;
110
{
111
    TkDisplay *dispPtr;
112
    Display *display = XOpenDisplay(display_name);
113
 
114
    if (display == NULL) {
115
        return NULL;
116
    }
117
    dispPtr = (TkDisplay *) ckalloc(sizeof(TkDisplay));
118
    dispPtr->display = display;
119
    Tcl_CreateFileHandler(ConnectionNumber(display), TCL_READABLE,
120
            DisplayFileProc, (ClientData) dispPtr);
121
    return dispPtr;
122
}
123
 
124
/*
125
 *----------------------------------------------------------------------
126
 *
127
 * TkpCloseDisplay --
128
 *
129
 *      Cancels notifier callbacks and closes a display.
130
 *
131
 * Results:
132
 *      None.
133
 *
134
 * Side effects:
135
 *      Deallocates the displayPtr.
136
 *
137
 *----------------------------------------------------------------------
138
 */
139
 
140
void
141
TkpCloseDisplay(displayPtr)
142
    TkDisplay *displayPtr;
143
{
144
    TkDisplay *dispPtr = (TkDisplay *) displayPtr;
145
 
146
    if (dispPtr->display != 0) {
147
        Tcl_DeleteFileHandler(ConnectionNumber(dispPtr->display));
148
 
149
        (void) XSync(dispPtr->display, False);
150
        (void) XCloseDisplay(dispPtr->display);
151
    }
152
 
153
    ckfree((char *) dispPtr);
154
}
155
 
156
/*
157
 *----------------------------------------------------------------------
158
 *
159
 * DisplaySetupProc --
160
 *
161
 *      This procedure implements the setup part of the UNIX X display
162
 *      event source.  It is invoked by Tcl_DoOneEvent before entering
163
 *      the notifier to check for events on all displays.
164
 *
165
 * Results:
166
 *      None.
167
 *
168
 * Side effects:
169
 *      If data is queued on a display inside Xlib, then the maximum
170
 *      block time will be set to 0 to ensure that the notifier returns
171
 *      control to Tcl even if there is no more data on the X connection.
172
 *
173
 *----------------------------------------------------------------------
174
 */
175
 
176
static void
177
DisplaySetupProc(clientData, flags)
178
    ClientData clientData;      /* Not used. */
179
    int flags;
180
{
181
    TkDisplay *dispPtr;
182
    static Tcl_Time blockTime = { 0, 0 };
183
 
184
    if (!(flags & TCL_WINDOW_EVENTS)) {
185
        return;
186
    }
187
 
188
    for (dispPtr = tkDisplayList; dispPtr != NULL;
189
         dispPtr = dispPtr->nextPtr) {
190
 
191
        /*
192
         * Flush the display. If data is pending on the X queue, set
193
         * the block time to zero.  This ensures that we won't block
194
         * in the notifier if there is data in the X queue, but not on
195
         * the server socket.
196
         */
197
 
198
        XFlush(dispPtr->display);
199
        if (XQLength(dispPtr->display) > 0) {
200
            Tcl_SetMaxBlockTime(&blockTime);
201
        }
202
    }
203
}
204
 
205
/*
206
 *----------------------------------------------------------------------
207
 *
208
 * DisplayCheckProc --
209
 *
210
 *      This procedure checks for events sitting in the X event
211
 *      queue.
212
 *
213
 * Results:
214
 *      None.
215
 *
216
 * Side effects:
217
 *      Moves queued events onto the Tcl event queue.
218
 *
219
 *----------------------------------------------------------------------
220
 */
221
 
222
static void
223
DisplayCheckProc(clientData, flags)
224
    ClientData clientData;      /* Not used. */
225
    int flags;
226
{
227
    TkDisplay *dispPtr;
228
    XEvent event;
229
    int numFound;
230
 
231
    if (!(flags & TCL_WINDOW_EVENTS)) {
232
        return;
233
    }
234
 
235
    for (dispPtr = tkDisplayList; dispPtr != NULL;
236
         dispPtr = dispPtr->nextPtr) {
237
        XFlush(dispPtr->display);
238
        numFound = XQLength(dispPtr->display);
239
 
240
        /*
241
         * Transfer events from the X event queue to the Tk event queue.
242
         */
243
 
244
        while (numFound > 0) {
245
            XNextEvent(dispPtr->display, &event);
246
            Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
247
            numFound--;
248
        }
249
    }
250
}
251
 
252
/*
253
 *----------------------------------------------------------------------
254
 *
255
 * DisplayFileProc --
256
 *
257
 *      This procedure implements the file handler for the X connection.
258
 *
259
 * Results:
260
 *      None.
261
 *
262
 * Side effects:
263
 *      Makes entries on the Tcl event queue for all the events available
264
 *      from all the displays.
265
 *
266
 *----------------------------------------------------------------------
267
 */
268
 
269
static void
270
DisplayFileProc(clientData, flags)
271
    ClientData clientData;              /* The display pointer. */
272
    int flags;                          /* Should be TCL_READABLE. */
273
{
274
    TkDisplay *dispPtr = (TkDisplay *) clientData;
275
    Display *display = dispPtr->display;
276
    XEvent event;
277
    int numFound;
278
 
279
    XFlush(display);
280
    numFound = XEventsQueued(display, QueuedAfterReading);
281
    if (numFound == 0) {
282
 
283
        /*
284
         * Things are very tricky if there aren't any events readable
285
         * at this point (after all, there was supposedly data
286
         * available on the connection).  A couple of things could
287
         * have occurred:
288
         *
289
         * One possibility is that there were only error events in the
290
         * input from the server.  If this happens, we should return
291
         * (we don't want to go to sleep in XNextEvent below, since
292
         * this would block out other sources of input to the
293
         * process).
294
         *
295
         * Another possibility is that our connection to the server
296
         * has been closed.  This will not necessarily be detected in
297
         * XEventsQueued (!!), so if we just return then there will be
298
         * an infinite loop.  To detect such an error, generate a NoOp
299
         * protocol request to exercise the connection to the server,
300
         * then return.  However, must disable SIGPIPE while sending
301
         * the request, or else the process will die from the signal
302
         * and won't invoke the X error function to print a nice (?!)
303
         * message.
304
         */
305
 
306
        void (*oldHandler)();
307
 
308
        oldHandler = (void (*)()) signal(SIGPIPE, SIG_IGN);
309
        XNoOp(display);
310
        XFlush(display);
311
        (void) signal(SIGPIPE, oldHandler);
312
    }
313
 
314
    /*
315
     * Transfer events from the X event queue to the Tk event queue.
316
     */
317
 
318
    while (numFound > 0) {
319
        XNextEvent(display, &event);
320
        Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
321
        numFound--;
322
    }
323
}
324
 
325
/*
326
 *----------------------------------------------------------------------
327
 *
328
 * TkUnixDoOneXEvent --
329
 *
330
 *      This routine waits for an X event to be processed or for
331
 *      a timeout to occur.  The timeout is specified as an absolute
332
 *      time.  This routine is called when Tk needs to wait for a
333
 *      particular X event without letting arbitrary events be
334
 *      processed.  The caller will typically call Tk_RestrictEvents
335
 *      to set up an event filter before calling this routine.  This
336
 *      routine will service at most one event per invocation.
337
 *
338
 * Results:
339
 *      Returns 0 if the timeout has expired, otherwise returns 1.
340
 *
341
 * Side effects:
342
 *      Can invoke arbitrary Tcl scripts.
343
 *
344
 *----------------------------------------------------------------------
345
 */
346
 
347
int
348
TkUnixDoOneXEvent(timePtr)
349
    Tcl_Time *timePtr;          /* Specifies the absolute time when the
350
                                 * call should time out. */
351
{
352
    TkDisplay *dispPtr;
353
    static fd_mask readMask[MASK_SIZE];
354
    struct timeval blockTime, *timeoutPtr;
355
    Tcl_Time now;
356
    int fd, index, bit, numFound, numFdBits = 0;
357
 
358
    /*
359
     * Look for queued events first.
360
     */
361
 
362
    if (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {
363
        return 1;
364
    }
365
 
366
    /*
367
     * Compute the next block time and check to see if we have timed out.
368
     * Note that HP-UX defines tv_sec to be unsigned so we have to be
369
     * careful in our arithmetic.
370
     */
371
 
372
    if (timePtr) {
373
        TclpGetTime(&now);
374
        blockTime.tv_sec = timePtr->sec;
375
        blockTime.tv_usec = timePtr->usec - now.usec;
376
        if (blockTime.tv_usec < 0) {
377
            now.sec += 1;
378
            blockTime.tv_usec += 1000000;
379
        }
380
        if (blockTime.tv_sec < now.sec) {
381
            blockTime.tv_sec = 0;
382
            blockTime.tv_usec = 0;
383
        } else {
384
            blockTime.tv_sec -= now.sec;
385
        }
386
        timeoutPtr = &blockTime;
387
    } else {
388
        timeoutPtr = NULL;
389
    }
390
 
391
    /*
392
     * Set up the select mask for all of the displays.  If a display has
393
     * data pending, then we want to poll instead of blocking.
394
     */
395
 
396
    memset((VOID *) readMask, 0, MASK_SIZE*sizeof(fd_mask));
397
    for (dispPtr = tkDisplayList; dispPtr != NULL;
398
         dispPtr = dispPtr->nextPtr) {
399
        XFlush(dispPtr->display);
400
        if (XQLength(dispPtr->display) > 0) {
401
            blockTime.tv_sec = 0;
402
            blockTime.tv_usec = 0;
403
        }
404
        fd = ConnectionNumber(dispPtr->display);
405
        index = fd/(NBBY*sizeof(fd_mask));
406
        bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
407
        readMask[index] |= bit;
408
        if (numFdBits <= fd) {
409
            numFdBits = fd+1;
410
        }
411
    }
412
 
413
    numFound = select(numFdBits, (SELECT_MASK *) &readMask[0], NULL, NULL,
414
            timeoutPtr);
415
    if (numFound <= 0) {
416
        /*
417
         * Some systems don't clear the masks after an error, so
418
         * we have to do it here.
419
         */
420
 
421
        memset((VOID *) readMask, 0, MASK_SIZE*sizeof(fd_mask));
422
    }
423
 
424
    /*
425
     * Process any new events on the display connections.
426
     */
427
 
428
    for (dispPtr = tkDisplayList; dispPtr != NULL;
429
         dispPtr = dispPtr->nextPtr) {
430
        fd = ConnectionNumber(dispPtr->display);
431
        index = fd/(NBBY*sizeof(fd_mask));
432
        bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
433
        if ((readMask[index] & bit) || (XQLength(dispPtr->display) > 0)) {
434
            DisplayFileProc((ClientData)dispPtr, TCL_READABLE);
435
        }
436
    }
437
    if (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {
438
        return 1;
439
    }
440
 
441
    /*
442
     * Check to see if we timed out.
443
     */
444
 
445
    if (timePtr) {
446
        TclpGetTime(&now);
447
        if ((now.sec > timePtr->sec) || ((now.sec == timePtr->sec)
448
                && (now.usec > timePtr->usec))) {
449
            return 0;
450
        }
451
    }
452
 
453
    /*
454
     * We had an event but we did not generate a Tcl event from it. Behave
455
     * as though we dealt with it. (JYL&SS)
456
     */
457
 
458
    return 1;
459
}
460
 
461
/*
462
 *----------------------------------------------------------------------
463
 *
464
 * TkpSync --
465
 *
466
 *      This routine ensures that all pending X requests have been
467
 *      seen by the server, and that any pending X events have been
468
 *      moved onto the Tk event queue.
469
 *
470
 * Results:
471
 *      None.
472
 *
473
 * Side effects:
474
 *      Places new events on the Tk event queue.
475
 *
476
 *----------------------------------------------------------------------
477
 */
478
 
479
void
480
TkpSync(display)
481
    Display *display;           /* Display to sync. */
482
{
483
    int numFound = 0;
484
    XEvent event;
485
 
486
    XSync(display, False);
487
 
488
    /*
489
     * Transfer events from the X event queue to the Tk event queue.
490
     */
491
 
492
    numFound = XQLength(display);
493
    while (numFound > 0) {
494
        XNextEvent(display, &event);
495
        Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
496
        numFound--;
497
    }
498
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.