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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkEvent.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkEvent.c --
3
 *
4
 *      This file provides basic low-level facilities for managing
5
 *      X events in Tk.
6
 *
7
 * Copyright (c) 1990-1994 The Regents of the University of California.
8
 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
9
 * Copyright (c) 1998 by Scriptics Corporation.
10
 *
11
 * See the file "license.terms" for information on usage and redistribution
12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
 *
14
 * RCS: @(#) $Id: tkEvent.c,v 1.1.1.1 2002-01-16 10:25:51 markom Exp $
15
 */
16
 
17
#include "tkPort.h"
18
#include "tkInt.h"
19
#include <signal.h>
20
 
21
/*
22
 * There's a potential problem if a handler is deleted while it's
23
 * current (i.e. its procedure is executing), since Tk_HandleEvent
24
 * will need to read the handler's "nextPtr" field when the procedure
25
 * returns.  To handle this problem, structures of the type below
26
 * indicate the next handler to be processed for any (recursively
27
 * nested) dispatches in progress.  The nextHandler fields get
28
 * updated if the handlers pointed to are deleted.  Tk_HandleEvent
29
 * also needs to know if the entire window gets deleted;  the winPtr
30
 * field is set to zero if that particular window gets deleted.
31
 */
32
 
33
typedef struct InProgress {
34
    XEvent *eventPtr;            /* Event currently being handled. */
35
    TkWindow *winPtr;            /* Window for event.  Gets set to None if
36
                                  * window is deleted while event is being
37
                                  * handled. */
38
    TkEventHandler *nextHandler; /* Next handler in search. */
39
    struct InProgress *nextPtr;  /* Next higher nested search. */
40
} InProgress;
41
 
42
static InProgress *pendingPtr = NULL;
43
                                /* Topmost search in progress, or
44
                                 * NULL if none. */
45
 
46
/*
47
 * For each call to Tk_CreateGenericHandler, an instance of the following
48
 * structure will be created.  All of the active handlers are linked into a
49
 * list.
50
 */
51
 
52
typedef struct GenericHandler {
53
    Tk_GenericProc *proc;       /* Procedure to dispatch on all X events. */
54
    ClientData clientData;      /* Client data to pass to procedure. */
55
    int deleteFlag;             /* Flag to set when this handler is deleted. */
56
    struct GenericHandler *nextPtr;
57
                                /* Next handler in list of all generic
58
                                 * handlers, or NULL for end of list. */
59
} GenericHandler;
60
 
61
static GenericHandler *genericList = NULL;
62
                                /* First handler in the list, or NULL. */
63
static GenericHandler *lastGenericPtr = NULL;
64
                                /* Last handler in list. */
65
 
66
/*
67
 * There's a potential problem if Tk_HandleEvent is entered recursively.
68
 * A handler cannot be deleted physically until we have returned from
69
 * calling it.  Otherwise, we're looking at unallocated memory in advancing to
70
 * its `next' entry.  We deal with the problem by using the `delete flag' and
71
 * deleting handlers only when it's known that there's no handler active.
72
 *
73
 * The following variable has a non-zero value when a handler is active.
74
 */
75
 
76
static int genericHandlersActive = 0;
77
 
78
/*
79
 * The following structure is used for queueing X-style events on the
80
 * Tcl event queue.
81
 */
82
 
83
typedef struct TkWindowEvent {
84
    Tcl_Event header;           /* Standard information for all events. */
85
    XEvent event;               /* The X event. */
86
} TkWindowEvent;
87
 
88
/*
89
 * Array of event masks corresponding to each X event:
90
 */
91
 
92
static unsigned long eventMasks[TK_LASTEVENT] = {
93
    0,
94
    0,
95
    KeyPressMask,                       /* KeyPress */
96
    KeyReleaseMask,                     /* KeyRelease */
97
    ButtonPressMask,                    /* ButtonPress */
98
    ButtonReleaseMask,                  /* ButtonRelease */
99
    PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
100
            |Button1MotionMask|Button2MotionMask|Button3MotionMask
101
            |Button4MotionMask|Button5MotionMask,
102
                                        /* MotionNotify */
103
    EnterWindowMask,                    /* EnterNotify */
104
    LeaveWindowMask,                    /* LeaveNotify */
105
    FocusChangeMask,                    /* FocusIn */
106
    FocusChangeMask,                    /* FocusOut */
107
    KeymapStateMask,                    /* KeymapNotify */
108
    ExposureMask,                       /* Expose */
109
    ExposureMask,                       /* GraphicsExpose */
110
    ExposureMask,                       /* NoExpose */
111
    VisibilityChangeMask,               /* VisibilityNotify */
112
    SubstructureNotifyMask,             /* CreateNotify */
113
    StructureNotifyMask,                /* DestroyNotify */
114
    StructureNotifyMask,                /* UnmapNotify */
115
    StructureNotifyMask,                /* MapNotify */
116
    SubstructureRedirectMask,           /* MapRequest */
117
    StructureNotifyMask,                /* ReparentNotify */
118
    StructureNotifyMask,                /* ConfigureNotify */
119
    SubstructureRedirectMask,           /* ConfigureRequest */
120
    StructureNotifyMask,                /* GravityNotify */
121
    ResizeRedirectMask,                 /* ResizeRequest */
122
    StructureNotifyMask,                /* CirculateNotify */
123
    SubstructureRedirectMask,           /* CirculateRequest */
124
    PropertyChangeMask,                 /* PropertyNotify */
125
    0,                                   /* SelectionClear */
126
    0,                                   /* SelectionRequest */
127
    0,                                   /* SelectionNotify */
128
    ColormapChangeMask,                 /* ColormapNotify */
129
    0,                                   /* ClientMessage */
130
    0,                                   /* Mapping Notify */
131
    VirtualEventMask,                   /* VirtualEvents */
132
    ActivateMask,                       /* ActivateNotify */
133
    ActivateMask,                       /* DeactivateNotify */
134
    MouseWheelMask                      /* MouseWheelEvent */
135
};
136
 
137
/*
138
 * If someone has called Tk_RestrictEvents, the information below
139
 * keeps track of it.
140
 */
141
 
142
static Tk_RestrictProc *restrictProc;
143
                                /* Procedure to call.  NULL means no
144
                                 * restrictProc is currently in effect. */
145
static ClientData restrictArg;  /* Argument to pass to restrictProc. */
146
 
147
/*
148
 * Prototypes for procedures that are only referenced locally within
149
 * this file.
150
 */
151
 
152
static void             DelayedMotionProc _ANSI_ARGS_((ClientData clientData));
153
static int              WindowEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
154
                            int flags));
155
 
156
/*
157
 *--------------------------------------------------------------
158
 *
159
 * Tk_CreateEventHandler --
160
 *
161
 *      Arrange for a given procedure to be invoked whenever
162
 *      events from a given class occur in a given window.
163
 *
164
 * Results:
165
 *      None.
166
 *
167
 * Side effects:
168
 *      From now on, whenever an event of the type given by
169
 *      mask occurs for token and is processed by Tk_HandleEvent,
170
 *      proc will be called.  See the manual entry for details
171
 *      of the calling sequence and return value for proc.
172
 *
173
 *--------------------------------------------------------------
174
 */
175
 
176
void
177
Tk_CreateEventHandler(token, mask, proc, clientData)
178
    Tk_Window token;            /* Token for window in which to
179
                                 * create handler. */
180
    unsigned long mask;         /* Events for which proc should
181
                                 * be called. */
182
    Tk_EventProc *proc;         /* Procedure to call for each
183
                                 * selected event */
184
    ClientData clientData;      /* Arbitrary data to pass to proc. */
185
{
186
    register TkEventHandler *handlerPtr;
187
    register TkWindow *winPtr = (TkWindow *) token;
188
    int found;
189
 
190
    /*
191
     * Skim through the list of existing handlers to (a) compute the
192
     * overall event mask for the window (so we can pass this new
193
     * value to the X system) and (b) see if there's already a handler
194
     * declared with the same callback and clientData (if so, just
195
     * change the mask).  If no existing handler matches, then create
196
     * a new handler.
197
     */
198
 
199
    found = 0;
200
    if (winPtr->handlerList == NULL) {
201
        handlerPtr = (TkEventHandler *) ckalloc(
202
                (unsigned) sizeof(TkEventHandler));
203
        winPtr->handlerList = handlerPtr;
204
        goto initHandler;
205
    } else {
206
        for (handlerPtr = winPtr->handlerList; ;
207
                handlerPtr = handlerPtr->nextPtr) {
208
            if ((handlerPtr->proc == proc)
209
                    && (handlerPtr->clientData == clientData)) {
210
                handlerPtr->mask = mask;
211
                found = 1;
212
            }
213
            if (handlerPtr->nextPtr == NULL) {
214
                break;
215
            }
216
        }
217
    }
218
 
219
    /*
220
     * Create a new handler if no matching old handler was found.
221
     */
222
 
223
    if (!found) {
224
        handlerPtr->nextPtr = (TkEventHandler *)
225
                ckalloc(sizeof(TkEventHandler));
226
        handlerPtr = handlerPtr->nextPtr;
227
        initHandler:
228
        handlerPtr->mask = mask;
229
        handlerPtr->proc = proc;
230
        handlerPtr->clientData = clientData;
231
        handlerPtr->nextPtr = NULL;
232
    }
233
 
234
    /*
235
     * No need to call XSelectInput:  Tk always selects on all events
236
     * for all windows (needed to support bindings on classes and "all").
237
     */
238
}
239
 
240
/*
241
 *--------------------------------------------------------------
242
 *
243
 * Tk_DeleteEventHandler --
244
 *
245
 *      Delete a previously-created handler.
246
 *
247
 * Results:
248
 *      None.
249
 *
250
 * Side effects:
251
 *      If there existed a handler as described by the
252
 *      parameters, the handler is deleted so that proc
253
 *      will not be invoked again.
254
 *
255
 *--------------------------------------------------------------
256
 */
257
 
258
void
259
Tk_DeleteEventHandler(token, mask, proc, clientData)
260
    Tk_Window token;            /* Same as corresponding arguments passed */
261
    unsigned long mask;         /* previously to Tk_CreateEventHandler. */
262
    Tk_EventProc *proc;
263
    ClientData clientData;
264
{
265
    register TkEventHandler *handlerPtr;
266
    register InProgress *ipPtr;
267
    TkEventHandler *prevPtr;
268
    register TkWindow *winPtr = (TkWindow *) token;
269
 
270
    /*
271
     * Find the event handler to be deleted, or return
272
     * immediately if it doesn't exist.
273
     */
274
 
275
    for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
276
            prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
277
        if (handlerPtr == NULL) {
278
            return;
279
        }
280
        if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
281
                && (handlerPtr->clientData == clientData)) {
282
            break;
283
        }
284
    }
285
 
286
    /*
287
     * If Tk_HandleEvent is about to process this handler, tell it to
288
     * process the next one instead.
289
     */
290
 
291
    for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
292
        if (ipPtr->nextHandler == handlerPtr) {
293
            ipPtr->nextHandler = handlerPtr->nextPtr;
294
        }
295
    }
296
 
297
    /*
298
     * Free resources associated with the handler.
299
     */
300
 
301
    if (prevPtr == NULL) {
302
        winPtr->handlerList = handlerPtr->nextPtr;
303
    } else {
304
        prevPtr->nextPtr = handlerPtr->nextPtr;
305
    }
306
    ckfree((char *) handlerPtr);
307
 
308
 
309
    /*
310
     * No need to call XSelectInput:  Tk always selects on all events
311
     * for all windows (needed to support bindings on classes and "all").
312
     */
313
}
314
 
315
/*--------------------------------------------------------------
316
 *
317
 * Tk_CreateGenericHandler --
318
 *
319
 *      Register a procedure to be called on each X event, regardless
320
 *      of display or window.  Generic handlers are useful for capturing
321
 *      events that aren't associated with windows, or events for windows
322
 *      not managed by Tk.
323
 *
324
 * Results:
325
 *      None.
326
 *
327
 * Side Effects:
328
 *      From now on, whenever an X event is given to Tk_HandleEvent,
329
 *      invoke proc, giving it clientData and the event as arguments.
330
 *
331
 *--------------------------------------------------------------
332
 */
333
 
334
void
335
Tk_CreateGenericHandler(proc, clientData)
336
     Tk_GenericProc *proc;      /* Procedure to call on every event. */
337
     ClientData clientData;     /* One-word value to pass to proc. */
338
{
339
    GenericHandler *handlerPtr;
340
 
341
    handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler));
342
 
343
    handlerPtr->proc = proc;
344
    handlerPtr->clientData = clientData;
345
    handlerPtr->deleteFlag = 0;
346
    handlerPtr->nextPtr = NULL;
347
    if (genericList == NULL) {
348
        genericList = handlerPtr;
349
    } else {
350
        lastGenericPtr->nextPtr = handlerPtr;
351
    }
352
    lastGenericPtr = handlerPtr;
353
}
354
 
355
/*
356
 *--------------------------------------------------------------
357
 *
358
 * Tk_DeleteGenericHandler --
359
 *
360
 *      Delete a previously-created generic handler.
361
 *
362
 * Results:
363
 *      None.
364
 *
365
 * Side Effects:
366
 *      If there existed a handler as described by the parameters,
367
 *      that handler is logically deleted so that proc will not be
368
 *      invoked again.  The physical deletion happens in the event
369
 *      loop in Tk_HandleEvent.
370
 *
371
 *--------------------------------------------------------------
372
 */
373
 
374
void
375
Tk_DeleteGenericHandler(proc, clientData)
376
     Tk_GenericProc *proc;
377
     ClientData clientData;
378
{
379
    GenericHandler * handler;
380
 
381
    for (handler = genericList; handler; handler = handler->nextPtr) {
382
        if ((handler->proc == proc) && (handler->clientData == clientData)) {
383
            handler->deleteFlag = 1;
384
        }
385
    }
386
}
387
 
388
/*
389
 *--------------------------------------------------------------
390
 *
391
 * Tk_HandleEvent --
392
 *
393
 *      Given an event, invoke all the handlers that have
394
 *      been registered for the event.
395
 *
396
 * Results:
397
 *      None.
398
 *
399
 * Side effects:
400
 *      Depends on the handlers.
401
 *
402
 *--------------------------------------------------------------
403
 */
404
 
405
void
406
Tk_HandleEvent(eventPtr)
407
    XEvent *eventPtr;           /* Event to dispatch. */
408
{
409
    register TkEventHandler *handlerPtr;
410
    register GenericHandler *genericPtr;
411
    register GenericHandler *genPrevPtr;
412
    TkWindow *winPtr;
413
    unsigned long mask;
414
    InProgress ip;
415
    Window handlerWindow;
416
    TkDisplay *dispPtr;
417
    Tcl_Interp *interp = (Tcl_Interp *) NULL;
418
 
419
    /*
420
     * Next, invoke all the generic event handlers (those that are
421
     * invoked for all events).  If a generic event handler reports that
422
     * an event is fully processed, go no further.
423
     */
424
 
425
    for (genPrevPtr = NULL, genericPtr = genericList;  genericPtr != NULL; ) {
426
        if (genericPtr->deleteFlag) {
427
            if (!genericHandlersActive) {
428
                GenericHandler *tmpPtr;
429
 
430
                /*
431
                 * This handler needs to be deleted and there are no
432
                 * calls pending through the handler, so now is a safe
433
                 * time to delete it.
434
                 */
435
 
436
                tmpPtr = genericPtr->nextPtr;
437
                if (genPrevPtr == NULL) {
438
                    genericList = tmpPtr;
439
                } else {
440
                    genPrevPtr->nextPtr = tmpPtr;
441
                }
442
                if (tmpPtr == NULL) {
443
                    lastGenericPtr = genPrevPtr;
444
                }
445
                (void) ckfree((char *) genericPtr);
446
                genericPtr = tmpPtr;
447
                continue;
448
            }
449
        } else {
450
            int done;
451
 
452
            genericHandlersActive++;
453
            done = (*genericPtr->proc)(genericPtr->clientData, eventPtr);
454
            genericHandlersActive--;
455
            if (done) {
456
                return;
457
            }
458
        }
459
        genPrevPtr = genericPtr;
460
        genericPtr = genPrevPtr->nextPtr;
461
    }
462
 
463
    /*
464
     * If the event is a MappingNotify event, find its display and
465
     * refresh the keyboard mapping information for the display.
466
     * After that there's nothing else to do with the event, so just
467
     * quit.
468
     */
469
 
470
    if (eventPtr->type == MappingNotify) {
471
        dispPtr = TkGetDisplay(eventPtr->xmapping.display);
472
        if (dispPtr != NULL) {
473
            XRefreshKeyboardMapping(&eventPtr->xmapping);
474
            dispPtr->bindInfoStale = 1;
475
        }
476
        return;
477
    }
478
 
479
    /*
480
     * Events selected by StructureNotify require special handling.
481
     * They look the same as those selected by SubstructureNotify.
482
     * The only difference is whether the "event" and "window" fields
483
     * are the same.  Compare the two fields and convert StructureNotify
484
     * to SubstructureNotify if necessary.
485
     */
486
 
487
    handlerWindow = eventPtr->xany.window;
488
    mask = eventMasks[eventPtr->xany.type];
489
    if (mask == StructureNotifyMask) {
490
        if (eventPtr->xmap.event != eventPtr->xmap.window) {
491
            mask = SubstructureNotifyMask;
492
            handlerWindow = eventPtr->xmap.event;
493
        }
494
    }
495
    winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow);
496
    if (winPtr == NULL) {
497
 
498
        /*
499
         * There isn't a TkWindow structure for this window.
500
         * However, if the event is a PropertyNotify event then call
501
         * the selection manager (it deals beneath-the-table with
502
         * certain properties).
503
         */
504
 
505
        if (eventPtr->type == PropertyNotify) {
506
            TkSelPropProc(eventPtr);
507
        }
508
        return;
509
    }
510
 
511
    /*
512
     * Once a window has started getting deleted, don't process any more
513
     * events for it except for the DestroyNotify event.  This check is
514
     * needed because a DestroyNotify handler could re-invoke the event
515
     * loop, causing other pending events to be handled for the window
516
     * (the window doesn't get totally expunged from our tables until
517
     * after the DestroyNotify event has been completely handled).
518
     */
519
 
520
    if ((winPtr->flags & TK_ALREADY_DEAD)
521
            && (eventPtr->type != DestroyNotify)) {
522
        return;
523
    }
524
 
525
    if (winPtr->mainPtr != NULL) {
526
 
527
        /*
528
         * Protect interpreter for this window from possible deletion
529
         * while we are dealing with the event for this window. Thus,
530
         * widget writers do not have to worry about protecting the
531
         * interpreter in their own code.
532
         */
533
 
534
        interp = winPtr->mainPtr->interp;
535
        Tcl_Preserve((ClientData) interp);
536
 
537
        /*
538
         * Call focus-related code to look at FocusIn, FocusOut, Enter,
539
         * and Leave events;  depending on its return value, ignore the
540
         * event.
541
         */
542
 
543
        if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask))
544
                && !TkFocusFilterEvent(winPtr, eventPtr)) {
545
            Tcl_Release((ClientData) interp);
546
            return;
547
        }
548
 
549
        /*
550
         * Redirect KeyPress and KeyRelease events to the focus window,
551
         * or ignore them entirely if there is no focus window.  We also
552
         * route the MouseWheel event to the focus window.  The MouseWheel
553
         * event is an extension to the X event set.  Currently, it is only
554
         * available on the Windows version of Tk.
555
         */
556
 
557
        if (mask & (KeyPressMask|KeyReleaseMask|MouseWheelMask)) {
558
            winPtr->dispPtr->lastEventTime = eventPtr->xkey.time;
559
            winPtr = TkFocusKeyEvent(winPtr, eventPtr);
560
            if (winPtr == NULL) {
561
                Tcl_Release((ClientData) interp);
562
                return;
563
            }
564
        }
565
 
566
        /*
567
         * Call a grab-related procedure to do special processing on
568
         * pointer events.
569
         */
570
 
571
        if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask
572
                |EnterWindowMask|LeaveWindowMask)) {
573
            if (mask & (ButtonPressMask|ButtonReleaseMask)) {
574
                winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time;
575
            } else if (mask & PointerMotionMask) {
576
                winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time;
577
            } else {
578
                winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time;
579
            }
580
            if (TkPointerEvent(eventPtr, winPtr) == 0) {
581
                goto done;
582
            }
583
        }
584
    }
585
 
586
#ifdef TK_USE_INPUT_METHODS
587
    /*
588
     * Pass the event to the input method(s), if there are any, and
589
     * discard the event if the input method(s) insist.  Create the
590
     * input context for the window if it hasn't already been done
591
     * (XFilterEvent needs this context).
592
     */
593
 
594
    if (!(winPtr->flags & TK_CHECKED_IC)) {
595
        if (winPtr->dispPtr->inputMethod != NULL) {
596
            winPtr->inputContext = XCreateIC(
597
                    winPtr->dispPtr->inputMethod, XNInputStyle,
598
                    XIMPreeditNothing|XIMStatusNothing,
599
                    XNClientWindow, winPtr->window,
600
                    XNFocusWindow, winPtr->window, NULL);
601
        }
602
        winPtr->flags |= TK_CHECKED_IC;
603
    }
604
    if (XFilterEvent(eventPtr, None)) {
605
        goto done;
606
    }
607
#endif /* TK_USE_INPUT_METHODS */
608
 
609
    /*
610
     * For events where it hasn't already been done, update the current
611
     * time in the display.
612
     */
613
 
614
    if (eventPtr->type == PropertyNotify) {
615
        winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time;
616
    }
617
 
618
    /*
619
     * There's a potential interaction here with Tk_DeleteEventHandler.
620
     * Read the documentation for pendingPtr.
621
     */
622
 
623
    ip.eventPtr = eventPtr;
624
    ip.winPtr = winPtr;
625
    ip.nextHandler = NULL;
626
    ip.nextPtr = pendingPtr;
627
    pendingPtr = &ip;
628
    if (mask == 0) {
629
        if ((eventPtr->type == SelectionClear)
630
                || (eventPtr->type == SelectionRequest)
631
                || (eventPtr->type == SelectionNotify)) {
632
            TkSelEventProc((Tk_Window) winPtr, eventPtr);
633
        } else if ((eventPtr->type == ClientMessage)
634
                && (eventPtr->xclient.message_type ==
635
                    Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"))) {
636
            TkWmProtocolEventProc(winPtr, eventPtr);
637
        }
638
    } else {
639
        for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
640
            if ((handlerPtr->mask & mask) != 0) {
641
                ip.nextHandler = handlerPtr->nextPtr;
642
                (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
643
                handlerPtr = ip.nextHandler;
644
            } else {
645
                handlerPtr = handlerPtr->nextPtr;
646
            }
647
        }
648
 
649
        /*
650
         * Pass the event to the "bind" command mechanism.  But, don't
651
         * do this for SubstructureNotify events.  The "bind" command
652
         * doesn't support them anyway, and it's easier to filter out
653
         * these events here than in the lower-level procedures.
654
         */
655
 
656
        if ((ip.winPtr != None) && (mask != SubstructureNotifyMask)) {
657
            TkBindEventProc(winPtr, eventPtr);
658
        }
659
    }
660
    pendingPtr = ip.nextPtr;
661
done:
662
 
663
    /*
664
     * Release the interpreter for this window so that it can be potentially
665
     * deleted if requested.
666
     */
667
 
668
    if (interp != (Tcl_Interp *) NULL) {
669
        Tcl_Release((ClientData) interp);
670
    }
671
}
672
 
673
/*
674
 *--------------------------------------------------------------
675
 *
676
 * TkEventDeadWindow --
677
 *
678
 *      This procedure is invoked when it is determined that
679
 *      a window is dead.  It cleans up event-related information
680
 *      about the window.
681
 *
682
 * Results:
683
 *      None.
684
 *
685
 * Side effects:
686
 *      Various things get cleaned up and recycled.
687
 *
688
 *--------------------------------------------------------------
689
 */
690
 
691
void
692
TkEventDeadWindow(winPtr)
693
    TkWindow *winPtr;           /* Information about the window
694
                                 * that is being deleted. */
695
{
696
    register TkEventHandler *handlerPtr;
697
    register InProgress *ipPtr;
698
 
699
    /*
700
     * While deleting all the handlers, be careful to check for
701
     * Tk_HandleEvent being about to process one of the deleted
702
     * handlers.  If it is, tell it to quit (all of the handlers
703
     * are being deleted).
704
     */
705
 
706
    while (winPtr->handlerList != NULL) {
707
        handlerPtr = winPtr->handlerList;
708
        winPtr->handlerList = handlerPtr->nextPtr;
709
        for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
710
            if (ipPtr->nextHandler == handlerPtr) {
711
                ipPtr->nextHandler = NULL;
712
            }
713
            if (ipPtr->winPtr == winPtr) {
714
                ipPtr->winPtr = None;
715
            }
716
        }
717
        ckfree((char *) handlerPtr);
718
    }
719
}
720
 
721
/*
722
 *----------------------------------------------------------------------
723
 *
724
 * TkCurrentTime --
725
 *
726
 *      Try to deduce the current time.  "Current time" means the time
727
 *      of the event that led to the current code being executed, which
728
 *      means the time in the most recently-nested invocation of
729
 *      Tk_HandleEvent.
730
 *
731
 * Results:
732
 *      The return value is the time from the current event, or
733
 *      CurrentTime if there is no current event or if the current
734
 *      event contains no time.
735
 *
736
 * Side effects:
737
 *      None.
738
 *
739
 *----------------------------------------------------------------------
740
 */
741
 
742
Time
743
TkCurrentTime(dispPtr)
744
    TkDisplay *dispPtr;         /* Display for which the time is desired. */
745
{
746
    register XEvent *eventPtr;
747
 
748
    if (pendingPtr == NULL) {
749
        return dispPtr->lastEventTime;
750
    }
751
    eventPtr = pendingPtr->eventPtr;
752
    switch (eventPtr->type) {
753
        case ButtonPress:
754
        case ButtonRelease:
755
            return eventPtr->xbutton.time;
756
        case KeyPress:
757
        case KeyRelease:
758
            return eventPtr->xkey.time;
759
        case MotionNotify:
760
            return eventPtr->xmotion.time;
761
        case EnterNotify:
762
        case LeaveNotify:
763
            return eventPtr->xcrossing.time;
764
        case PropertyNotify:
765
            return eventPtr->xproperty.time;
766
    }
767
    return dispPtr->lastEventTime;
768
}
769
 
770
/*
771
 *----------------------------------------------------------------------
772
 *
773
 * Tk_RestrictEvents --
774
 *
775
 *      This procedure is used to globally restrict the set of events
776
 *      that will be dispatched.  The restriction is done by filtering
777
 *      all incoming X events through a procedure that determines
778
 *      whether they are to be processed immediately, deferred, or
779
 *      discarded.
780
 *
781
 * Results:
782
 *      The return value is the previous restriction procedure in effect,
783
 *      if there was one, or NULL if there wasn't.
784
 *
785
 * Side effects:
786
 *      From now on, proc will be called to determine whether to process,
787
 *      defer or discard each incoming X event.
788
 *
789
 *----------------------------------------------------------------------
790
 */
791
 
792
Tk_RestrictProc *
793
Tk_RestrictEvents(proc, arg, prevArgPtr)
794
    Tk_RestrictProc *proc;      /* Procedure to call for each incoming
795
                                 * event. */
796
    ClientData arg;             /* Arbitrary argument to pass to proc. */
797
    ClientData *prevArgPtr;     /* Place to store information about previous
798
                                 * argument. */
799
{
800
    Tk_RestrictProc *prev;
801
 
802
    prev = restrictProc;
803
    *prevArgPtr = restrictArg;
804
    restrictProc = proc;
805
    restrictArg = arg;
806
    return prev;
807
}
808
 
809
/*
810
 *----------------------------------------------------------------------
811
 *
812
 * Tk_QueueWindowEvent --
813
 *
814
 *      Given an X-style window event, this procedure adds it to the
815
 *      Tcl event queue at the given position.  This procedure also
816
 *      performs mouse motion event collapsing if possible.
817
 *
818
 * Results:
819
 *      None.
820
 *
821
 * Side effects:
822
 *      Adds stuff to the event queue, which will eventually be
823
 *      processed.
824
 *
825
 *----------------------------------------------------------------------
826
 */
827
 
828
void
829
Tk_QueueWindowEvent(eventPtr, position)
830
    XEvent *eventPtr;                   /* Event to add to queue.  This
831
                                         * procedures copies it before adding
832
                                         * it to the queue. */
833
    Tcl_QueuePosition position;         /* Where to put it on the queue:
834
                                         * TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
835
                                         * or TCL_QUEUE_MARK. */
836
{
837
    TkWindowEvent *wevPtr;
838
    TkDisplay *dispPtr;
839
 
840
    /*
841
     * Find our display structure for the event's display.
842
     */
843
 
844
    for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
845
        if (dispPtr == NULL) {
846
            return;
847
        }
848
        if (dispPtr->display == eventPtr->xany.display) {
849
            break;
850
        }
851
    }
852
 
853
    if ((dispPtr->delayedMotionPtr != NULL) && (position == TCL_QUEUE_TAIL)) {
854
        if ((eventPtr->type == MotionNotify) && (eventPtr->xmotion.window
855
                == dispPtr->delayedMotionPtr->event.xmotion.window)) {
856
            /*
857
             * The new event is a motion event in the same window as the
858
             * saved motion event.  Just replace the saved event with the
859
             * new one.
860
             */
861
 
862
            dispPtr->delayedMotionPtr->event = *eventPtr;
863
            return;
864
        } else if ((eventPtr->type != GraphicsExpose)
865
                && (eventPtr->type != NoExpose)
866
                && (eventPtr->type != Expose)) {
867
            /*
868
             * The new event may conflict with the saved motion event.  Queue
869
             * the saved motion event now so that it will be processed before
870
             * the new event.
871
             */
872
 
873
            Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, position);
874
            dispPtr->delayedMotionPtr = NULL;
875
            Tcl_CancelIdleCall(DelayedMotionProc, (ClientData) dispPtr);
876
        }
877
    }
878
 
879
    wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent));
880
    wevPtr->header.proc = WindowEventProc;
881
    wevPtr->event = *eventPtr;
882
    if ((eventPtr->type == MotionNotify) && (position == TCL_QUEUE_TAIL)) {
883
        /*
884
         * The new event is a motion event so don't queue it immediately;
885
         * save it around in case another motion event arrives that it can
886
         * be collapsed with.
887
         */
888
 
889
        if (dispPtr->delayedMotionPtr != NULL) {
890
            panic("Tk_QueueWindowEvent found unexpected delayed motion event");
891
        }
892
        dispPtr->delayedMotionPtr = wevPtr;
893
        Tcl_DoWhenIdle(DelayedMotionProc, (ClientData) dispPtr);
894
    } else {
895
        Tcl_QueueEvent(&wevPtr->header, position);
896
    }
897
}
898
 
899
/*
900
 *---------------------------------------------------------------------------
901
 *
902
 * TkQueueEventForAllChildren --
903
 *
904
 *      Given an XEvent, recursively queue the event for this window and
905
 *      all non-toplevel children of the given window.
906
 *
907
 * Results:
908
 *      None.
909
 *
910
 * Side effects:
911
 *      Events queued.
912
 *
913
 *---------------------------------------------------------------------------
914
 */
915
 
916
void
917
TkQueueEventForAllChildren(winPtr, eventPtr)
918
    TkWindow *winPtr;       /* Window to which event is sent. */
919
    XEvent *eventPtr;       /* The event to be sent. */
920
{
921
    TkWindow *childPtr;
922
 
923
    eventPtr->xany.window = winPtr->window;
924
    Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL);
925
 
926
    childPtr = winPtr->childList;
927
    while (childPtr != NULL) {
928
        if (!Tk_IsTopLevel(childPtr)) {
929
            TkQueueEventForAllChildren(childPtr, eventPtr);
930
        }
931
        childPtr = childPtr->nextPtr;
932
    }
933
}
934
 
935
/*
936
 *----------------------------------------------------------------------
937
 *
938
 * WindowEventProc --
939
 *
940
 *      This procedure is called by Tcl_DoOneEvent when a window event
941
 *      reaches the front of the event queue.  This procedure is responsible
942
 *      for actually handling the event.
943
 *
944
 * Results:
945
 *      Returns 1 if the event was handled, meaning it should be removed
946
 *      from the queue.  Returns 0 if the event was not handled, meaning
947
 *      it should stay on the queue.  The event isn't handled if the
948
 *      TCL_WINDOW_EVENTS bit isn't set in flags, if a restrict proc
949
 *      prevents the event from being handled.
950
 *
951
 * Side effects:
952
 *      Whatever the event handlers for the event do.
953
 *
954
 *----------------------------------------------------------------------
955
 */
956
 
957
static int
958
WindowEventProc(evPtr, flags)
959
    Tcl_Event *evPtr;           /* Event to service. */
960
    int flags;                  /* Flags that indicate what events to
961
                                 * handle, such as TCL_WINDOW_EVENTS. */
962
{
963
    TkWindowEvent *wevPtr = (TkWindowEvent *) evPtr;
964
    Tk_RestrictAction result;
965
 
966
    if (!(flags & TCL_WINDOW_EVENTS)) {
967
        return 0;
968
    }
969
    if (restrictProc != NULL) {
970
        result = (*restrictProc)(restrictArg, &wevPtr->event);
971
        if (result != TK_PROCESS_EVENT) {
972
            if (result == TK_DEFER_EVENT) {
973
                return 0;
974
            } else {
975
                /*
976
                 * TK_DELETE_EVENT: return and say we processed the event,
977
                 * even though we didn't do anything at all.
978
                 */
979
                return 1;
980
            }
981
        }
982
    }
983
    Tk_HandleEvent(&wevPtr->event);
984
    return 1;
985
}
986
 
987
/*
988
 *----------------------------------------------------------------------
989
 *
990
 * DelayedMotionProc --
991
 *
992
 *      This procedure is invoked as an idle handler when a mouse motion
993
 *      event has been delayed.  It queues the delayed event so that it
994
 *      will finally be serviced.
995
 *
996
 * Results:
997
 *      None.
998
 *
999
 * Side effects:
1000
 *      The delayed mouse motion event gets added to the Tcl event
1001
 *      queue for servicing.
1002
 *
1003
 *----------------------------------------------------------------------
1004
 */
1005
 
1006
static void
1007
DelayedMotionProc(clientData)
1008
    ClientData clientData;      /* Pointer to display containing a delayed
1009
                                 * motion event to be serviced. */
1010
{
1011
    TkDisplay *dispPtr = (TkDisplay *) clientData;
1012
 
1013
    if (dispPtr->delayedMotionPtr == NULL) {
1014
        panic("DelayedMotionProc found no delayed mouse motion event");
1015
    }
1016
    Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL);
1017
    dispPtr->delayedMotionPtr = NULL;
1018
}
1019
 
1020
/*
1021
 *--------------------------------------------------------------
1022
 *
1023
 * Tk_MainLoop --
1024
 *
1025
 *      Call Tcl_DoOneEvent over and over again in an infinite
1026
 *      loop as long as there exist any main windows.
1027
 *
1028
 * Results:
1029
 *      None.
1030
 *
1031
 * Side effects:
1032
 *      Arbitrary;  depends on handlers for events.
1033
 *
1034
 *--------------------------------------------------------------
1035
 */
1036
 
1037
void
1038
Tk_MainLoop()
1039
{
1040
    while (Tk_GetNumMainWindows() > 0) {
1041
        Tcl_DoOneEvent(0);
1042
    }
1043
}

powered by: WebSVN 2.1.0

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