4 * This file provides basic event-managing facilities,
5 * whereby procedure callbacks may be attached to
8 * Copyright 1990-1992 Regents of the University of California.
9 * Permission to use, copy, modify, and distribute this
10 * software and its documentation for any purpose and without
11 * fee is hereby granted, provided that the above copyright
12 * notice appear in all copies. The University of California
13 * makes no representations about the suitability of this
14 * software for any purpose. It is provided "as is" without
15 * express or implied warranty.
19 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkEvent.c,v 1.60 92/08/21 16:15:57 ouster Exp $ SPRITE (Berkeley)";
33 * For each timer callback that's pending, there is one record
34 * of the following type, chained together in a list sorted by
35 * time (earliest event first).
38 typedef struct TimerEvent
{
39 struct timeval time
; /* When timer is to fire. */
40 void (*proc
) _ANSI_ARGS_((ClientData clientData
));
41 /* Procedure to call. */
42 ClientData clientData
; /* Argument to pass to proc. */
43 Tk_TimerToken token
; /* Identifies event so it can be
45 struct TimerEvent
*nextPtr
; /* Next event in queue, or NULL for
49 static TimerEvent
*timerQueue
; /* First event in queue. */
52 * The information below is used to provide read, write, and
53 * exception masks to select during calls to Tk_DoOneEvent.
56 static int readCount
; /* Number of files for which we */
57 static int writeCount
; /* care about each event type. */
58 static int exceptCount
;
59 #define MASK_SIZE ((OPEN_MAX+(8*sizeof(int))-1)/(8*sizeof(int)))
60 static int masks
[3*MASK_SIZE
]; /* Integer array containing official
61 * copies of the three sets of
63 static int ready
[3*MASK_SIZE
]; /* Temporary copy of masks, passed
64 * to select and modified by kernel
65 * to indicate which files are
67 static int *readPtr
; /* Pointers to the portions of */
68 static int *writePtr
; /* *readyPtr for reading, writing, */
69 static int *exceptPtr
; /* and excepting. Will be NULL if
70 * corresponding count (e.g. readCount
72 static int numFds
= 0; /* Number of valid bits in mask
73 * arrays (this value is passed
77 * For each file registered in a call to Tk_CreateFileHandler,
78 * and for each display that's currently active, there is one
79 * record of the following type. All of these records are
80 * chained together into a single list.
83 typedef struct FileEvent
{
84 int fd
; /* Descriptor number for this file. */
85 int *readPtr
; /* Pointer to word in ready array
86 * for this file's read mask bit. */
87 int *writePtr
; /* Same for write mask bit. */
88 int *exceptPtr
; /* Same for except mask bit. */
89 int mask
; /* Value to AND with mask word to
90 * select just this file's bit. */
91 void (*proc
) _ANSI_ARGS_((ClientData clientData
, int mask
));
92 /* Procedure to call. NULL means
93 * this is a display. */
94 ClientData clientData
; /* Argument to pass to proc. For
95 * displays, this is a (Display *). */
96 struct FileEvent
*nextPtr
; /* Next in list of all files we
97 * care about (NULL for end of
101 static FileEvent
*fileList
; /* List of all file events. */
104 * There is one of the following structures for each of the
105 * handlers declared in a call to Tk_DoWhenIdle. All of the
106 * currently-active handlers are linked together into a list.
109 typedef struct IdleHandler
{
110 void (*proc
) _ANSI_ARGS_((ClientData clientData
));
111 /* Procedure to call. */
112 ClientData clientData
; /* Value to pass to proc. */
113 struct IdleHandler
*nextPtr
;/* Next in list of active handlers. */
116 static IdleHandler
*idleList
= NULL
;
117 /* First in list of all idle handlers. */
118 static IdleHandler
*lastIdlePtr
= NULL
;
119 /* Last in list (or NULL for empty list). */
122 * There's a potential problem if a handler is deleted while it's
123 * current (i.e. its procedure is executing), since Tk_HandleEvent
124 * will need to read the handler's "nextPtr" field when the procedure
125 * returns. To handle this problem, structures of the type below
126 * indicate the next handler to be processed for any (recursively
127 * nested) dispatches in progress. The nextHandler fields get
128 * updated if the handlers pointed to are deleted. Tk_HandleEvent
129 * also needs to know if the entire window gets deleted; the winPtr
130 * field is set to zero if that particular window gets deleted.
133 typedef struct InProgress
{
134 XEvent
*eventPtr
; /* Event currently being handled. */
135 TkWindow
*winPtr
; /* Window for event. Gets set to None if
136 * window is deleted while event is being
138 TkEventHandler
*nextHandler
; /* Next handler in search. */
139 struct InProgress
*nextPtr
; /* Next higher nested search. */
142 static InProgress
*pendingPtr
= NULL
;
143 /* Topmost search in progress, or
147 * For each call to Tk_CreateGenericHandler, an instance of the following
148 * structure will be created. All of the active handlers are linked into a
152 typedef struct GenericHandler
{
153 Tk_GenericProc
*proc
; /* Procedure to dispatch on all X events. */
154 ClientData clientData
; /* Client data to pass to procedure. */
155 int deleteFlag
; /* Flag to set when this handler is deleted. */
156 struct GenericHandler
*nextPtr
;
157 /* Next handler in list of all generic
158 * handlers, or NULL for end of list. */
161 static GenericHandler
*genericList
= NULL
;
162 /* First handler in the list, or NULL. */
163 static GenericHandler
*lastGenericPtr
= NULL
;
164 /* Last handler in list. */
167 * There's a potential problem if Tk_HandleEvent is entered recursively.
168 * A handler cannot be deleted physically until we have returned from
169 * calling it. Otherwise, we're looking at unallocated memory in advancing to
170 * its `next' entry. We deal with the problem by using the `delete flag' and
171 * deleting handlers only when it's known that there's no handler active.
173 * The following variable has a non-zero value when a handler is active.
176 static int genericHandlersActive
= 0;
179 * Array of event masks corresponding to each X event:
182 static unsigned long eventMasks
[] = {
185 KeyPressMask
, /* KeyPress */
186 KeyReleaseMask
, /* KeyRelease */
187 ButtonPressMask
, /* ButtonPress */
188 ButtonReleaseMask
, /* ButtonRelease */
189 PointerMotionMask
|PointerMotionHintMask
|ButtonMotionMask
190 |Button1MotionMask
|Button2MotionMask
|Button3MotionMask
191 |Button4MotionMask
|Button5MotionMask
,
193 EnterWindowMask
, /* EnterNotify */
194 LeaveWindowMask
, /* LeaveNotify */
195 FocusChangeMask
, /* FocusIn */
196 FocusChangeMask
, /* FocusOut */
197 KeymapStateMask
, /* KeymapNotify */
198 ExposureMask
, /* Expose */
199 ExposureMask
, /* GraphicsExpose */
200 ExposureMask
, /* NoExpose */
201 VisibilityChangeMask
, /* VisibilityNotify */
202 SubstructureNotifyMask
, /* CreateNotify */
203 StructureNotifyMask
, /* DestroyNotify */
204 StructureNotifyMask
, /* UnmapNotify */
205 StructureNotifyMask
, /* MapNotify */
206 SubstructureRedirectMask
, /* MapRequest */
207 StructureNotifyMask
, /* ReparentNotify */
208 StructureNotifyMask
, /* ConfigureNotify */
209 SubstructureRedirectMask
, /* ConfigureRequest */
210 StructureNotifyMask
, /* GravityNotify */
211 ResizeRedirectMask
, /* ResizeRequest */
212 StructureNotifyMask
, /* CirculateNotify */
213 SubstructureRedirectMask
, /* CirculateRequest */
214 PropertyChangeMask
, /* PropertyNotify */
215 0, /* SelectionClear */
216 0, /* SelectionRequest */
217 0, /* SelectionNotify */
218 ColormapChangeMask
, /* ColormapNotify */
219 0, /* ClientMessage */
220 0, /* Mapping Notify */
224 * If someone has called Tk_RestrictEvents, the information below
228 static Bool (*restrictProc
) _ANSI_ARGS_((Display
*display
, XEvent
*eventPtr
,
229 char *arg
)); /* Procedure to call. NULL means no
230 * restrictProc is currently in effect. */
231 static char *restrictArg
; /* Argument to pass to restrictProc. */
234 * The following array keeps track of the last TK_NEVENTS X events, for
235 * memory dump analysis. The tracing is only done if tkEventDebug is set
239 #define TK_NEVENTS 32
240 static XEvent eventTrace
[TK_NEVENTS
];
241 static int traceIndex
= 0;
242 int tkEventDebug
= 0;
244 int tkCollapseMotion
= 1;
248 #define DefPool(type) \
249 type *Unused##type = NULL; \
251 type *New##type() { \
252 if (Unused##type == NULL) { \
253 return (type *)ckalloc(sizeof (type)); \
255 type *ptr = Unused##type; \
256 Unused##type = ptr->nextPtr; \
261 void Free##type(type *ptr) { \
262 ptr->nextPtr = Unused##type; \
263 Unused##type = ptr; \
266 DefPool(TkEventHandler
)
267 DefPool(GenericHandler
)
274 *--------------------------------------------------------------
276 * Tk_CreateEventHandler --
278 * Arrange for a given procedure to be invoked whenever
279 * events from a given class occur in a given window.
285 * From now on, whenever an event of the type given by
286 * mask occurs for token and is processed by Tk_HandleEvent,
287 * proc will be called. See the manual entry for details
288 * of the calling sequence and return value for proc.
290 *--------------------------------------------------------------
294 Tk_CreateEventHandler(
295 Tk_Window token
, /* Token for window in which to
297 unsigned long mask
, /* Events for which proc should
299 Tk_EventProc
*proc
, /* Procedure to call for each
301 ClientData clientData
/* Arbitrary data to pass to proc. */
304 register TkEventHandler
*handlerPtr
;
305 register TkWindow
*winPtr
= (TkWindow
*) token
;
309 * Skim through the list of existing handlers to (a) compute the
310 * overall event mask for the window (so we can pass this new
311 * value to the X system) and (b) see if there's already a handler
312 * declared with the same callback and clientData (if so, just
313 * change the mask). If no existing handler matches, then create
318 if (winPtr
->handlerList
== NULL
) {
319 handlerPtr
= (TkEventHandler
*) NewTkEventHandler();
320 winPtr
->handlerList
= handlerPtr
;
323 for (handlerPtr
= winPtr
->handlerList
; ;
324 handlerPtr
= handlerPtr
->nextPtr
) {
325 if ((handlerPtr
->proc
== proc
)
326 && (handlerPtr
->clientData
== clientData
)) {
327 handlerPtr
->mask
= mask
;
330 if (handlerPtr
->nextPtr
== NULL
) {
337 * Create a new handler if no matching old handler was found.
341 handlerPtr
->nextPtr
= NewTkEventHandler();
342 handlerPtr
= handlerPtr
->nextPtr
;
344 handlerPtr
->mask
= mask
;
345 handlerPtr
->proc
= proc
;
346 handlerPtr
->clientData
= clientData
;
347 handlerPtr
->nextPtr
= NULL
;
351 * No need to call XSelectInput: Tk always selects on all events
352 * for all windows (needed to support bindings on classes and "all").
357 *--------------------------------------------------------------
359 * Tk_DeleteEventHandler --
361 * Delete a previously-created handler.
367 * If there existed a handler as described by the
368 * parameters, the handler is deleted so that proc
369 * will not be invoked again.
371 *--------------------------------------------------------------
375 Tk_DeleteEventHandler (
376 Tk_Window token
, /* Same as corresponding arguments passed */
377 unsigned long mask
, /* previously to Tk_CreateEventHandler. */
379 ClientData clientData
382 register TkEventHandler
*handlerPtr
;
383 register InProgress
*ipPtr
;
384 TkEventHandler
*prevPtr
;
385 register TkWindow
*winPtr
= (TkWindow
*) token
;
388 * Find the event handler to be deleted, or return
389 * immediately if it doesn't exist.
392 for (handlerPtr
= winPtr
->handlerList
, prevPtr
= NULL
; ;
393 prevPtr
= handlerPtr
, handlerPtr
= handlerPtr
->nextPtr
) {
394 if (handlerPtr
== NULL
) {
397 if ((handlerPtr
->mask
== mask
) && (handlerPtr
->proc
== proc
)
398 && (handlerPtr
->clientData
== clientData
)) {
404 * If Tk_HandleEvent is about to process this handler, tell it to
405 * process the next one instead.
408 for (ipPtr
= pendingPtr
; ipPtr
!= NULL
; ipPtr
= ipPtr
->nextPtr
) {
409 if (ipPtr
->nextHandler
== handlerPtr
) {
410 ipPtr
->nextHandler
= handlerPtr
->nextPtr
;
415 * Free resources associated with the handler.
418 if (prevPtr
== NULL
) {
419 winPtr
->handlerList
= handlerPtr
->nextPtr
;
421 prevPtr
->nextPtr
= handlerPtr
->nextPtr
;
423 (void) FreeTkEventHandler(handlerPtr
);
427 * No need to call XSelectInput: Tk always selects on all events
428 * for all windows (needed to support bindings on classes and "all").
432 /*--------------------------------------------------------------
434 * Tk_CreateGenericHandler --
436 * Register a procedure to be called on each X event, regardless
437 * of display or window. Generic handlers are useful for capturing
438 * events that aren't associated with windows, or events for windows
445 * From now on, whenever an X event is given to Tk_HandleEvent,
446 * invoke proc, giving it clientData and the event as arguments.
448 *--------------------------------------------------------------
452 Tk_CreateGenericHandler (
453 Tk_GenericProc
*proc
, /* Procedure to call on every event. */
454 ClientData clientData
/* One-word value to pass to proc. */
457 GenericHandler
*handlerPtr
;
459 handlerPtr
= NewGenericHandler();
461 handlerPtr
->proc
= proc
;
462 handlerPtr
->clientData
= clientData
;
463 handlerPtr
->deleteFlag
= 0;
464 handlerPtr
->nextPtr
= NULL
;
465 if (genericList
== NULL
) {
466 genericList
= handlerPtr
;
468 lastGenericPtr
->nextPtr
= handlerPtr
;
470 lastGenericPtr
= handlerPtr
;
474 *--------------------------------------------------------------
476 * Tk_DeleteGenericHandler --
478 * Delete a previously-created generic handler.
484 * If there existed a handler as described by the parameters,
485 * that handler is logically deleted so that proc will not be
486 * invoked again. The physical deletion happens in the event
487 * loop in Tk_HandleEvent.
489 *--------------------------------------------------------------
493 Tk_DeleteGenericHandler (Tk_GenericProc
*proc
, ClientData clientData
)
495 GenericHandler
* handler
;
497 for (handler
= genericList
; handler
; handler
= handler
->nextPtr
) {
498 if ((handler
->proc
== proc
) && (handler
->clientData
== clientData
)) {
499 handler
->deleteFlag
= 1;
505 *--------------------------------------------------------------
509 * Given an event, invoke all the handlers that have
510 * been registered for the event.
516 * Depends on the handlers.
518 *--------------------------------------------------------------
523 XEvent
*eventPtr
/* Event to dispatch. */
526 register TkEventHandler
*handlerPtr
;
527 register GenericHandler
*genericPtr
;
528 register GenericHandler
*genPrevPtr
;
530 register unsigned long mask
;
532 Window handlerWindow
;
535 * First off, invoke all the generic event handlers (those that are
536 * invoked for all events). If a generic event handler reports that
537 * an event is fully processed, go no further.
540 for (genPrevPtr
= NULL
, genericPtr
= genericList
; genericPtr
!= NULL
; ) {
541 if (genericPtr
->deleteFlag
) {
542 if (!genericHandlersActive
) {
543 GenericHandler
*tmpPtr
;
546 * This handler needs to be deleted and there are no
547 * calls pending through the handler, so now is a safe
551 tmpPtr
= genericPtr
->nextPtr
;
552 if (genPrevPtr
== NULL
) {
553 genericList
= tmpPtr
;
555 genPrevPtr
->nextPtr
= tmpPtr
;
557 (void) FreeGenericHandler(genericPtr
);
564 genericHandlersActive
++;
565 done
= (*genericPtr
->proc
)(genericPtr
->clientData
, eventPtr
);
566 genericHandlersActive
--;
571 genPrevPtr
= genericPtr
;
572 genericPtr
= genPrevPtr
->nextPtr
;
576 * Events selected by StructureNotify look the same as those
577 * selected by SubstructureNotify; the only difference is
578 * whether the "event" and "window" fields are the same.
579 * Check it out and convert StructureNotify to
580 * SubstructureNotify if necessary.
583 handlerWindow
= eventPtr
->xany
.window
;
584 mask
= eventMasks
[eventPtr
->xany
.type
];
585 if (mask
== StructureNotifyMask
) {
586 if (eventPtr
->xmap
.event
!= eventPtr
->xmap
.window
) {
587 mask
= SubstructureNotifyMask
;
588 handlerWindow
= eventPtr
->xmap
.event
;
591 if (XFindContext(eventPtr
->xany
.display
, handlerWindow
,
592 tkWindowContext
, (void *) &winPtr
) != 0) {
595 * There isn't a TkWindow structure for this window.
596 * However, if the event is a PropertyNotify event then call
597 * the selection manager (it deals beneath-the-table with
598 * certain properties).
601 if (eventPtr
->type
== PropertyNotify
) {
602 TkSelPropProc(eventPtr
);
608 * Redirect KeyPress and KeyRelease events if input focussing
609 * is happening. Map the x and y coordinates between the two
610 * windows, if possible (make both -1 if the map-from and map-to
611 * windows don't share the same top-level window).
614 if (mask
& (KeyPressMask
|KeyReleaseMask
)) {
615 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xkey
.time
;
617 if (winPtr
->dispPtr
->focusPtr
!= NULL
) {
619 int winX
, winY
, focusX
, focusY
;
621 focusPtr
= winPtr
->dispPtr
->focusPtr
;
622 if ((focusPtr
->display
!= winPtr
->display
)
623 || (focusPtr
->screenNum
!= winPtr
->screenNum
)) {
624 eventPtr
->xkey
.x
= -1;
625 eventPtr
->xkey
.y
= -1;
627 Tk_GetRootCoords((Tk_Window
) winPtr
, &winX
, &winY
);
628 Tk_GetRootCoords((Tk_Window
) focusPtr
, &focusX
, &focusY
);
629 eventPtr
->xkey
.x
-= focusX
- winX
;
630 eventPtr
->xkey
.y
-= focusY
- winY
;
632 eventPtr
->xkey
.window
= focusPtr
->window
;
638 * Call a grab-related procedure to do special processing on
642 if (mask
& (ButtonPressMask
|ButtonReleaseMask
|PointerMotionMask
643 |EnterWindowMask
|LeaveWindowMask
)) {
644 if (mask
& (ButtonPressMask
|ButtonReleaseMask
)) {
645 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xbutton
.time
;
646 } else if (mask
& PointerMotionMask
) {
647 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xmotion
.time
;
649 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xcrossing
.time
;
651 if (TkPointerEvent(eventPtr
, winPtr
) == 0) {
657 * For events where it hasn't already been done, update the current
658 * time in the display.
661 if (eventPtr
->type
== PropertyNotify
) {
662 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xproperty
.time
;
666 * There's a potential interaction here with Tk_DeleteEventHandler.
667 * Read the documentation for pendingPtr.
670 ip
.eventPtr
= eventPtr
;
672 ip
.nextHandler
= NULL
;
673 ip
.nextPtr
= pendingPtr
;
676 if ((eventPtr
->type
== SelectionClear
)
677 || (eventPtr
->type
== SelectionRequest
)
678 || (eventPtr
->type
== SelectionNotify
)) {
679 TkSelEventProc((Tk_Window
) winPtr
, eventPtr
);
680 } else if ((eventPtr
->type
== ClientMessage
)
681 && (eventPtr
->xclient
.message_type
==
682 Tk_InternAtom((Tk_Window
) winPtr
, "WM_PROTOCOLS"))) {
684 * this is a ICCCM WM_PROTOCOL ClientMessage
686 TkWmProtocolEventProc(winPtr
, eventPtr
);
689 for (handlerPtr
= winPtr
->handlerList
; handlerPtr
!= NULL
; ) {
690 if ((handlerPtr
->mask
& mask
) != 0) {
691 ip
.nextHandler
= handlerPtr
->nextPtr
;
692 (*(handlerPtr
->proc
))(handlerPtr
->clientData
, eventPtr
);
693 handlerPtr
= ip
.nextHandler
;
695 handlerPtr
= handlerPtr
->nextPtr
;
700 * Pass the event to the "bind" command mechanism. But, don't
701 * do this for SubstructureNotify events. The "bind" command
702 * doesn't support them anyway, and it's easier to filter out
703 * these events here than in the lower-level procedures.
706 if ((ip
.winPtr
!= None
) && (mask
!= SubstructureNotifyMask
)) {
707 TkBindEventProc(winPtr
, eventPtr
);
710 pendingPtr
= ip
.nextPtr
;
714 *--------------------------------------------------------------
716 * Tk_CreateFileHandler --
718 * Arrange for a given procedure to be invoked whenever
719 * a given file becomes readable or writable.
725 * From now on, whenever the I/O channel given by fd becomes
726 * ready in the way indicated by mask, proc will be invoked.
727 * See the manual entry for details on the calling sequence
728 * to proc. If fd is already registered then the old mask
729 * and proc and clientData values will be replaced with
732 *--------------------------------------------------------------
736 Tk_CreateFileHandler (
737 int fd
, /* Integer identifier for stream. */
738 int mask
, /* OR'ed combination of TK_READABLE,
739 * TK_WRITABLE, and TK_EXCEPTION:
740 * indicates conditions under which
741 * proc should be called. */
742 Tk_FileProc
*proc
, /* Procedure to call for each
743 * selected event. NULL means that
744 * this is a display, and that
745 * clientData is the (Display *)
746 * for it, and that events should
747 * be handled automatically. */
748 ClientData clientData
/* Arbitrary data to pass to proc. */
751 register FileEvent
*filePtr
;
754 if (fd
>= OPEN_MAX
) {
755 panic("Tk_CreatefileHandler can't handle file id %d", fd
);
759 * Make sure the file isn't already registered. Create a
760 * new record in the normal case where there's no existing
764 for (filePtr
= fileList
; filePtr
!= NULL
;
765 filePtr
= filePtr
->nextPtr
) {
766 if (filePtr
->fd
== fd
) {
770 index
= fd
/(8*sizeof(int));
771 if (filePtr
== NULL
) {
772 filePtr
= NewFileEvent();
774 filePtr
->readPtr
= &ready
[index
];
775 filePtr
->writePtr
= &ready
[index
+MASK_SIZE
];
776 filePtr
->exceptPtr
= &ready
[index
+2*MASK_SIZE
];
777 filePtr
->mask
= 1 << (fd
%(8*sizeof(int)));
778 filePtr
->nextPtr
= fileList
;
781 if (masks
[index
] & filePtr
->mask
) {
783 *filePtr
->readPtr
&= ~filePtr
->mask
;
784 masks
[index
] &= ~filePtr
->mask
;
786 if (masks
[index
+MASK_SIZE
] & filePtr
->mask
) {
788 *filePtr
->writePtr
&= ~filePtr
->mask
;
789 masks
[index
+MASK_SIZE
] &= ~filePtr
->mask
;
791 if (masks
[index
+2*MASK_SIZE
] & filePtr
->mask
) {
793 *filePtr
->exceptPtr
&= ~filePtr
->mask
;
794 masks
[index
+2*MASK_SIZE
] &= ~filePtr
->mask
;
799 * The remainder of the initialization below is done
800 * regardless of whether or not this is a new record
801 * or a modification of an old one.
804 if (mask
& TK_READABLE
) {
805 masks
[index
] |= filePtr
->mask
;
808 readPtr
= (readCount
== 0 ? NULL
: &ready
[0]);
810 if (mask
& TK_WRITABLE
) {
811 masks
[index
+MASK_SIZE
] |= filePtr
->mask
;
814 writePtr
= (writeCount
== 0 ? NULL
: &ready
[MASK_SIZE
]);
816 if (mask
& TK_EXCEPTION
) {
817 masks
[index
+2*MASK_SIZE
] |= filePtr
->mask
;
820 exceptPtr
= (exceptCount
== 0 ? NULL
: &ready
[2*MASK_SIZE
]);
822 filePtr
->proc
= proc
;
823 filePtr
->clientData
= clientData
;
831 *--------------------------------------------------------------
833 * Tk_DeleteFileHandler --
835 * Cancel a previously-arranged callback arrangement for
842 * If a callback was previously registered on fd, remove it.
844 *--------------------------------------------------------------
848 Tk_DeleteFileHandler (
849 int fd
/* Stream id for which to remove
850 * callback procedure. */
853 register FileEvent
*filePtr
;
858 * Find the entry for the given file (and return if there
862 for (prevPtr
= NULL
, filePtr
= fileList
; ;
863 prevPtr
= filePtr
, filePtr
= filePtr
->nextPtr
) {
864 if (filePtr
== NULL
) {
867 if (filePtr
->fd
== fd
) {
873 * Clean up information in the callback record.
876 index
= filePtr
->fd
/(8*sizeof(int));
877 if (masks
[index
] & filePtr
->mask
) {
879 *filePtr
->readPtr
&= ~filePtr
->mask
;
880 masks
[index
] &= ~filePtr
->mask
;
882 if (masks
[index
+MASK_SIZE
] & filePtr
->mask
) {
884 *filePtr
->writePtr
&= ~filePtr
->mask
;
885 masks
[index
+MASK_SIZE
] &= ~filePtr
->mask
;
887 if (masks
[index
+2*MASK_SIZE
] & filePtr
->mask
) {
889 *filePtr
->exceptPtr
&= ~filePtr
->mask
;
890 masks
[index
+2*MASK_SIZE
] &= ~filePtr
->mask
;
892 if (prevPtr
== NULL
) {
893 fileList
= filePtr
->nextPtr
;
895 prevPtr
->nextPtr
= filePtr
->nextPtr
;
897 FreeFileEvent(filePtr
);
904 for (filePtr
= fileList
; filePtr
!= NULL
;
905 filePtr
= filePtr
->nextPtr
) {
906 if (numFds
<= filePtr
->fd
) {
907 numFds
= filePtr
->fd
+1;
913 *--------------------------------------------------------------
915 * Tk_CreateTimerHandler --
917 * Arrange for a given procedure to be invoked at a particular
918 * time in the future.
921 * The return value is a token for the timer event, which
922 * may be used to delete the event before it fires.
925 * When milliseconds have elapsed, proc will be invoked
928 *--------------------------------------------------------------
932 Tk_CreateTimerHandler (
933 int milliseconds
, /* How many milliseconds to wait
934 * before invoking proc. */
935 Tk_TimerProc
*proc
, /* Procedure to invoke. */
936 ClientData clientData
/* Arbitrary data to pass to proc. */
939 register TimerEvent
*timerPtr
, *tPtr2
, *prevPtr
;
942 timerPtr
= NewTimerEvent();
945 * Compute when the event should fire.
948 (void) gettimeofday(&timerPtr
->time
, (struct timezone
*) NULL
);
949 timerPtr
->time
.tv_sec
+= milliseconds
/1000;
950 timerPtr
->time
.tv_usec
+= (milliseconds
%1000)*1000;
951 if (timerPtr
->time
.tv_usec
> 1000000) {
952 timerPtr
->time
.tv_usec
-= 1000000;
953 timerPtr
->time
.tv_sec
+= 1;
957 * Fill in other fields for the event.
960 timerPtr
->proc
= proc
;
961 timerPtr
->clientData
= clientData
;
963 timerPtr
->token
= (Tk_TimerToken
) id
;
966 * Add the event to the queue in the correct position
967 * (ordered by event firing time).
970 for (tPtr2
= timerQueue
, prevPtr
= NULL
; tPtr2
!= NULL
;
971 prevPtr
= tPtr2
, tPtr2
= tPtr2
->nextPtr
) {
972 if ((tPtr2
->time
.tv_sec
> timerPtr
->time
.tv_sec
)
973 || ((tPtr2
->time
.tv_sec
== timerPtr
->time
.tv_sec
)
974 && (tPtr2
->time
.tv_usec
> timerPtr
->time
.tv_usec
))) {
978 if (prevPtr
== NULL
) {
979 timerPtr
->nextPtr
= timerQueue
;
980 timerQueue
= timerPtr
;
982 timerPtr
->nextPtr
= prevPtr
->nextPtr
;
983 prevPtr
->nextPtr
= timerPtr
;
985 return timerPtr
->token
;
988 // Added by Don to support finer timer resolution.
990 *--------------------------------------------------------------
992 * Tk_CreateMicroTimerHandler --
994 * Arrange for a given procedure to be invoked at a particular
995 * time in the future.
998 * The return value is a token for the timer event, which
999 * may be used to delete the event before it fires.
1002 * When seconds and seconds have elapsed, proc will be invoked
1005 *--------------------------------------------------------------
1009 Tk_CreateMicroTimerHandler (
1010 int seconds
, /* How many seconds to wait
1011 * before invoking proc. */
1012 int microseconds
, /* How many microseconds to wait
1013 * before invoking proc. */
1014 Tk_TimerProc
*proc
, /* Procedure to invoke. */
1015 ClientData clientData
/* Arbitrary data to pass to proc. */
1018 register TimerEvent
*timerPtr
, *tPtr2
, *prevPtr
;
1021 timerPtr
= NewTimerEvent();
1024 * Compute when the event should fire.
1027 (void) gettimeofday(&timerPtr
->time
, (struct timezone
*) NULL
);
1028 timerPtr
->time
.tv_sec
+= seconds
;
1029 timerPtr
->time
.tv_usec
+= microseconds
;
1030 while (timerPtr
->time
.tv_usec
> 1000000) {
1031 timerPtr
->time
.tv_usec
-= 1000000;
1032 timerPtr
->time
.tv_sec
+= 1;
1036 * Fill in other fields for the event.
1039 timerPtr
->proc
= proc
;
1040 timerPtr
->clientData
= clientData
;
1042 timerPtr
->token
= (Tk_TimerToken
) id
;
1045 * Add the event to the queue in the correct position
1046 * (ordered by event firing time).
1049 for (tPtr2
= timerQueue
, prevPtr
= NULL
; tPtr2
!= NULL
;
1050 prevPtr
= tPtr2
, tPtr2
= tPtr2
->nextPtr
) {
1051 if ((tPtr2
->time
.tv_sec
> timerPtr
->time
.tv_sec
)
1052 || ((tPtr2
->time
.tv_sec
== timerPtr
->time
.tv_sec
)
1053 && (tPtr2
->time
.tv_usec
> timerPtr
->time
.tv_usec
))) {
1057 if (prevPtr
== NULL
) {
1058 timerPtr
->nextPtr
= timerQueue
;
1059 timerQueue
= timerPtr
;
1061 timerPtr
->nextPtr
= prevPtr
->nextPtr
;
1062 prevPtr
->nextPtr
= timerPtr
;
1064 return timerPtr
->token
;
1069 *--------------------------------------------------------------
1071 * Tk_DeleteTimerHandler --
1073 * Delete a previously-registered timer handler.
1079 * Destroy the timer callback identified by TimerToken,
1080 * so that its associated procedure will not be called.
1081 * If the callback has already fired, or if the given
1082 * token doesn't exist, then nothing happens.
1084 *--------------------------------------------------------------
1088 Tk_DeleteTimerHandler (
1089 Tk_TimerToken token
/* Result previously returned by
1090 * Tk_DeleteTimerHandler. */
1093 register TimerEvent
*timerPtr
, *prevPtr
;
1095 if (token
== 0) return;
1097 for (timerPtr
= timerQueue
, prevPtr
= NULL
; timerPtr
!= NULL
;
1098 prevPtr
= timerPtr
, timerPtr
= timerPtr
->nextPtr
) {
1099 if (timerPtr
->token
!= token
) {
1102 if (prevPtr
== NULL
) {
1103 timerQueue
= timerPtr
->nextPtr
;
1105 prevPtr
->nextPtr
= timerPtr
->nextPtr
;
1107 FreeTimerEvent(timerPtr
);
1111 // fprintf(stderr, "Tk_DeleteTimerHandler called on bogus timer %d\n", token);
1115 *--------------------------------------------------------------
1119 * Arrange for proc to be invoked the next time the
1120 * system is idle (i.e., just before the next time
1121 * that Tk_DoOneEvent would have to wait for something
1128 * Proc will eventually be called, with clientData
1129 * as argument. See the manual entry for details.
1131 *--------------------------------------------------------------
1136 Tk_IdleProc
*proc
, /* Procedure to invoke. */
1137 ClientData clientData
/* Arbitrary value to pass to proc. */
1140 register IdleHandler
*idlePtr
;
1142 idlePtr
= NewIdleHandler();
1143 idlePtr
->proc
= proc
;
1144 idlePtr
->clientData
= clientData
;
1145 idlePtr
->nextPtr
= NULL
;
1146 if (lastIdlePtr
== NULL
) {
1149 lastIdlePtr
->nextPtr
= idlePtr
;
1151 lastIdlePtr
= idlePtr
;
1155 *----------------------------------------------------------------------
1157 * Tk_CancelIdleCall --
1159 * If there are any when-idle calls requested to a given procedure
1160 * with given clientData, cancel all of them.
1166 * If the proc/clientData combination were on the when-idle list,
1167 * they are removed so that they will never be called.
1169 *----------------------------------------------------------------------
1174 Tk_IdleProc
*proc
, /* Procedure that was previously registered. */
1175 ClientData clientData
/* Arbitrary value to pass to proc. */
1178 register IdleHandler
*idlePtr
, *prevPtr
;
1179 IdleHandler
*nextPtr
;
1181 for (prevPtr
= NULL
, idlePtr
= idleList
; idlePtr
!= NULL
;
1182 prevPtr
= idlePtr
, idlePtr
= idlePtr
->nextPtr
) {
1183 while ((idlePtr
->proc
== proc
)
1184 && (idlePtr
->clientData
== clientData
)) {
1185 nextPtr
= idlePtr
->nextPtr
;
1186 FreeIdleHandler(idlePtr
);
1188 if (prevPtr
== NULL
) {
1191 prevPtr
->nextPtr
= idlePtr
;
1193 if (idlePtr
== NULL
) {
1194 lastIdlePtr
= prevPtr
;
1202 *--------------------------------------------------------------
1206 * Process a single event of some sort. If there's no
1207 * work to do, wait for an event to occur, then process
1211 * The return value is 1 if the procedure actually found
1212 * an event to process. If no event was found then 0 is
1216 * May delay execution of process while waiting for an
1217 * X event, X error, file-ready event, or timer event.
1218 * The handling of the event could cause additional
1219 * side effects. Collapses sequences of mouse-motion
1220 * events for the same window into a single event by
1221 * delaying motion event processing.
1223 *--------------------------------------------------------------
1228 int flags
/* Miscellaneous flag values: may be any
1229 * combination of TK_DONT_WAIT, TK_X_EVENTS,
1230 * TK_FILE_EVENTS, TK_TIMER_EVENTS, and
1231 * TK_IDLE_EVENTS. */
1234 register FileEvent
*filePtr
;
1235 struct timeval curTime
, timeout
, *timeoutPtr
;
1237 static XEvent delayedMotionEvent
; /* Used to hold motion events that
1238 * are being saved until later. */
1239 static int eventDelayed
= 0; /* Non-zero means there is an event
1240 * in delayedMotionEvent. */
1242 if ((flags
& TK_ALL_EVENTS
) == 0) {
1243 flags
|= TK_ALL_EVENTS
;
1247 * Phase One: see if there's already something ready
1248 * (either a file or a display) that was left over
1249 * from before (i.e don't do a select, just check the
1250 * bits from the last select).
1254 for (filePtr
= fileList
; filePtr
!= NULL
;
1255 filePtr
= filePtr
->nextPtr
) {
1259 * Displays: flush output, check for queued events,
1260 * and read events from the server if display is ready.
1261 * If there are any events, process one and then
1265 if ((filePtr
->proc
== NULL
) && (flags
& TK_X_EVENTS
)) {
1266 Display
*display
= (Display
*) filePtr
->clientData
;
1270 if ((*filePtr
->readPtr
) & filePtr
->mask
) {
1271 *filePtr
->readPtr
&= ~filePtr
->mask
;
1272 if (XEventsQueued(display
, QueuedAfterReading
) == 0) {
1275 * Things are very tricky if there aren't any events
1276 * readable at this point (after all, there was
1277 * supposedly data available on the connection).
1278 * A couple of things could have occurred:
1280 * One possibility is that there were only error events
1281 * in the input from the server. If this happens,
1282 * we should return (we don't want to go to sleep
1283 * in XNextEvent below, since this would block out
1284 * other sources of input to the process).
1286 * Another possibility is that our connection to the
1287 * server has been closed. This will not necessarily
1288 * be detected in XEventsQueued (!!), so if we just
1289 * return then there will be an infinite loop. To
1290 * detect such an error, generate a NoOp protocol
1291 * request to exercise the connection to the server,
1292 * then return. However, must disable SIGPIPE while
1293 * sending the event, or else the process will die
1294 * from the signal and won't invoke the X error
1295 * function to print a nice message.
1298 void (*oldHandler
)(int);
1300 oldHandler
= (void (*)(int)) signal(SIGPIPE
, SIG_IGN
);
1303 (void) signal(SIGPIPE
, oldHandler
);
1306 if (restrictProc
!= NULL
) {
1307 if (!XCheckIfEvent(display
, &event
, restrictProc
,
1312 XNextEvent(display
, &event
);
1315 if (QLength(display
) == 0) {
1318 if (restrictProc
!= NULL
) {
1319 if (!XCheckIfEvent(display
, &event
, restrictProc
,
1324 XNextEvent(display
, &event
);
1329 * Got an event. Deal with mouse-motion-collapsing and
1330 * event-delaying here. If there's already an event delayed,
1331 * then process that event if it's incompatible with the new
1332 * event (new event not mouse motion, or window changed, or
1333 * state changed). If the new event is mouse motion, then
1334 * don't process it now; delay it until later in the hopes
1335 * that it can be merged with other mouse motion events
1336 * immediately following.
1340 eventTrace
[traceIndex
] = event
;
1341 traceIndex
= (traceIndex
+1) % TK_NEVENTS
;
1345 if (((event
.type
!= MotionNotify
)
1346 && (event
.type
!= GraphicsExpose
)
1347 && (event
.type
!= NoExpose
)
1348 && (event
.type
!= Expose
))
1349 || (event
.xmotion
.display
1350 != delayedMotionEvent
.xmotion
.display
)
1351 || (event
.xmotion
.window
1352 != delayedMotionEvent
.xmotion
.window
)) {
1356 * Must copy the event out of delayedMotionEvent before
1357 * processing it, in order to allow recursive calls to
1358 * Tk_DoOneEvent as part of the handler.
1361 copy
= delayedMotionEvent
;
1363 Tk_HandleEvent(©
);
1366 if (tkCollapseMotion
&& event
.type
== MotionNotify
) {
1367 delayedMotionEvent
= event
;
1370 Tk_HandleEvent(&event
);
1376 * Not a display: if the file is ready, call the
1377 * appropriate handler.
1380 if (((*filePtr
->readPtr
| *filePtr
->writePtr
1381 | *filePtr
->exceptPtr
) & filePtr
->mask
) == 0) {
1384 if (!(flags
& TK_FILE_EVENTS
)) {
1388 if (*filePtr
->readPtr
& filePtr
->mask
) {
1389 mask
|= TK_READABLE
;
1390 *filePtr
->readPtr
&= ~filePtr
->mask
;
1392 if (*filePtr
->writePtr
& filePtr
->mask
) {
1393 mask
|= TK_WRITABLE
;
1394 *filePtr
->writePtr
&= ~filePtr
->mask
;
1396 if (*filePtr
->exceptPtr
& filePtr
->mask
) {
1397 mask
|= TK_EXCEPTION
;
1398 *filePtr
->exceptPtr
&= ~filePtr
->mask
;
1400 (*filePtr
->proc
)(filePtr
->clientData
, mask
);
1405 * Phase Two: get the current time and see if any timer
1406 * events are ready to fire. If so, fire one and return.
1410 if ((timerQueue
!= NULL
) && (flags
& TK_TIMER_EVENTS
)) {
1411 register TimerEvent
*timerPtr
= timerQueue
;
1413 (void) gettimeofday(&curTime
, (struct timezone
*) NULL
);
1414 if ((timerPtr
->time
.tv_sec
< curTime
.tv_sec
)
1415 || ((timerPtr
->time
.tv_sec
== curTime
.tv_sec
)
1416 && (timerPtr
->time
.tv_usec
< curTime
.tv_usec
))) {
1417 timerQueue
= timerPtr
->nextPtr
;
1418 (*timerPtr
->proc
)(timerPtr
->clientData
);
1419 FreeTimerEvent(timerPtr
);
1426 * Phase Three: if there is a delayed motion event, process it
1427 * now, before any DoWhenIdle handlers. Better to process before
1428 * idle handlers than after, because the goal of idle handlers is
1429 * to delay until after all pending events have been processed.
1430 * Must free up delayedMotionEvent *before* calling Tk_HandleEvent,
1431 * so that the event handler can call Tk_DoOneEvent recursively
1432 * without infinite looping.
1435 if ((eventDelayed
) && (flags
& TK_X_EVENTS
)) {
1438 copy
= delayedMotionEvent
;
1440 Tk_HandleEvent(©
);
1445 * Phase Four: if there are DoWhenIdle requests pending (or
1446 * if we're not allowed to block), then do a select with an
1447 * instantaneous timeout. If a ready file is found, then go
1448 * back to process it.
1451 if (((idleList
!= NULL
) && (flags
& TK_IDLE_EVENTS
))
1452 || (flags
& TK_DONT_WAIT
)) {
1453 if (flags
& (TK_X_EVENTS
|TK_FILE_EVENTS
)) {
1454 memcpy((VOID
*) ready
, (VOID
*) masks
, 3*MASK_SIZE
*sizeof(int));
1455 timeout
.tv_sec
= timeout
.tv_usec
= 0;
1457 numFound
= select(numFds
, (SELECT_MASK
*) readPtr
,
1458 (SELECT_MASK
*) writePtr
, (SELECT_MASK
*) exceptPtr
,
1460 } while ((numFound
== -1) && (errno
== EINTR
));
1468 * Phase Five: process all pending DoWhenIdle requests.
1471 if ((idleList
!= NULL
) && (flags
& TK_IDLE_EVENTS
)) {
1472 register IdleHandler
*idlePtr
;
1475 * If you change the code below, be aware that new handlers
1476 * can get added to the list while the current one is being
1479 * NOTE! Must remove the entry from the list before calling
1480 * it, in case the idle handler calls Tk_DoOneEvent: don't
1481 * want to loop infinitely. Must also be careful because
1482 * Tk_CancelIdleCall could change the list during the call.
1485 while (idleList
!= NULL
) {
1487 idleList
= idlePtr
->nextPtr
;
1488 if (idleList
== NULL
) {
1491 (*idlePtr
->proc
)(idlePtr
->clientData
);
1492 FreeIdleHandler(idlePtr
);
1498 * Phase Six: do a select to wait for either one of the
1499 * files to become ready or for the first timer event to
1500 * fire. Then go back to process the event.
1503 if ((flags
& TK_DONT_WAIT
)
1504 || !(flags
& (TK_TIMER_EVENTS
|TK_FILE_EVENTS
|TK_X_EVENTS
))) {
1507 if ((timerQueue
== NULL
) || !(flags
& TK_TIMER_EVENTS
)) {
1510 timeoutPtr
= &timeout
;
1511 timeout
.tv_sec
= timerQueue
->time
.tv_sec
- curTime
.tv_sec
;
1512 timeout
.tv_usec
= timerQueue
->time
.tv_usec
- curTime
.tv_usec
;
1513 if (timeout
.tv_usec
< 0) {
1514 timeout
.tv_sec
-= 1;
1515 timeout
.tv_usec
+= 1000000;
1518 memcpy((VOID
*) ready
, (VOID
*) masks
, 3*MASK_SIZE
*sizeof(int));
1520 numFound
= select(numFds
, (SELECT_MASK
*) readPtr
,
1521 (SELECT_MASK
*) writePtr
, (SELECT_MASK
*) exceptPtr
,
1523 } while ((numFound
== -1) && (errno
== EINTR
));
1524 if (numFound
== 0) {
1531 *--------------------------------------------------------------
1535 * Call Tk_DoOneEvent over and over again in an infinite
1536 * loop as long as there exist any main windows.
1542 * Arbitrary; depends on handlers for events.
1544 *--------------------------------------------------------------
1550 while (!tkMustExit
&&
1551 tk_NumMainWindows
> 0) {
1557 *----------------------------------------------------------------------
1561 * Delay execution for the specified number of milliseconds.
1569 *----------------------------------------------------------------------
1574 int ms
/* Number of milliseconds to sleep. */
1577 static struct timeval delay
;
1579 delay
.tv_sec
= ms
/1000;
1580 delay
.tv_usec
= (ms
%1000)*1000;
1581 (void) select(0, (SELECT_MASK
*) 0, (SELECT_MASK
*) 0,
1582 (SELECT_MASK
*) 0, &delay
);
1586 *----------------------------------------------------------------------
1588 * Tk_RestrictEvents --
1590 * This procedure is used to globally restrict the set of events
1591 * that will be dispatched. The restriction is done by filtering
1592 * all incoming X events through a procedure that determines
1593 * whether they are to be processed immediately or deferred.
1596 * The return value is the previous restriction procedure in effect,
1597 * if there was one, or NULL if there wasn't.
1600 * From now on, proc will be called to determine whether to process
1601 * or defer each incoming X event.
1603 *----------------------------------------------------------------------
1608 Tk_RestrictProc
*proc
, /* X "if" procedure to call for each
1609 * incoming event. See "XIfEvent" doc.
1611 char *arg
, /* Arbitrary argument to pass to proc. */
1612 char **prevArgPtr
/* Place to store information about previous
1616 Bool (*prev
) _ANSI_ARGS_((Display
*display
, XEvent
*eventPtr
, char *arg
));
1618 prev
= restrictProc
;
1619 *prevArgPtr
= restrictArg
;
1620 restrictProc
= proc
;
1626 *--------------------------------------------------------------
1628 * Tk_CreateFocusHandler --
1630 * Arrange for a procedure to be called whenever the focus
1631 * enters or leaves a given window.
1637 * After this procedure has been invoked, whenever tkwin gets
1638 * or loses the input focus, proc will be called. It should have
1639 * the following structure:
1642 * proc(clientData, gotFocus)
1643 * ClientData clientData;
1648 * The clientData argument to "proc" will be the same as the
1649 * clientData argument to this procedure. GotFocus will be
1650 * 1 if tkwin is getting the focus, and 0 if it's losing the
1653 *--------------------------------------------------------------
1657 Tk_CreateFocusHandler (
1658 Tk_Window tkwin
, /* Token for window. */
1659 Tk_FocusProc
*proc
, /* Procedure to call when tkwin gets
1660 * or loses the input focus. */
1661 ClientData clientData
/* Arbitrary value to pass to proc. */
1664 register TkWindow
*winPtr
= (TkWindow
*) tkwin
;
1666 winPtr
->focusProc
= proc
;
1667 winPtr
->focusData
= clientData
;
1671 *--------------------------------------------------------------
1675 * This procedure is invoked to process the "focus" Tcl command.
1676 * See the user documentation for details on what it does.
1679 * A standard Tcl result.
1682 * See the user documentation.
1684 *--------------------------------------------------------------
1689 ClientData clientData
, /* Main window associated with
1691 Tcl_Interp
*interp
, /* Current interpreter. */
1692 int argc
, /* Number of arguments. */
1693 char **argv
/* Argument strings. */
1696 Tk_Window tkwin
= (Tk_Window
) clientData
;
1697 register TkWindow
*winPtr
= (TkWindow
*) clientData
;
1698 register TkWindow
*newPtr
;
1702 Tcl_AppendResult(interp
, "too many args: should be \"",
1703 argv
[0], " ?-query? ?window?\"", (char *) NULL
);
1708 if (winPtr
->dispPtr
->focusPtr
== NULL
) {
1709 interp
->result
= "none";
1711 interp
->result
= winPtr
->dispPtr
->focusPtr
->pathName
;
1716 if (argv
[1][0] == '-') {
1719 switchLength
= strlen(argv
[1]);
1720 if ((switchLength
>= 2)
1721 && (strncmp(argv
[1], "-query", switchLength
) == 0)) {
1727 newPtr
= (TkWindow
*) Tk_NameToWindow(interp
, argv
[2], tkwin
);
1728 if (newPtr
== NULL
) {
1731 if (newPtr
->dispPtr
->focusPtr
== NULL
) {
1732 interp
->result
= "none";
1734 interp
->result
= newPtr
->dispPtr
->focusPtr
->pathName
;
1744 if (strcmp(argv
[1], "none") == 0) {
1747 newPtr
= (TkWindow
*) Tk_NameToWindow(interp
, argv
[1], tkwin
);
1748 if (newPtr
== NULL
) {
1752 /* XXX: mumble frotz */
1753 /* if (newPtr->dispPtr->focusPtr == newPtr) { */
1754 if ((!newPtr
) || (newPtr
->dispPtr
->focusPtr
== newPtr
)) {
1757 if (winPtr
== newPtr
->dispPtr
->mouseMainPtr
) { /* XXX: ??? presumably */
1758 if ((newPtr
->dispPtr
->focusPtr
!= NULL
)
1759 && (newPtr
->dispPtr
->focusPtr
->focusProc
!= NULL
)) {
1760 (*newPtr
->dispPtr
->focusPtr
->focusProc
)(
1761 newPtr
->dispPtr
->focusPtr
->focusData
, 0);
1763 newPtr
->dispPtr
->focusPtr
= newPtr
;
1764 if ((newPtr
!= NULL
) && (newPtr
->focusProc
!= NULL
)) {
1765 (*newPtr
->focusProc
)(newPtr
->focusData
, 1);
1768 newPtr
->dispPtr
->focusPtr
= newPtr
;
1774 *--------------------------------------------------------------
1776 * TkFocusEventProc --
1778 * This procedure is invoked whenever the pointer enters
1779 * or leaves a top-level window. It notifies the current
1780 * owner of the focus, if any.
1788 *--------------------------------------------------------------
1793 register TkWindow
*winPtr
, /* Top-level window just entered or left. */
1794 XEvent
*eventPtr
/* EnterWindow or LeaveWindow event. */
1797 register TkWindow
*focusPtr
;
1798 TkWindow
*newMouseMainPtr
= NULL
;
1800 if (eventPtr
->type
== EnterNotify
) {
1801 newMouseMainPtr
= winPtr
->mainPtr
->winPtr
;
1803 if (winPtr
->dispPtr
->mouseMainPtr
== newMouseMainPtr
) {
1806 if (winPtr
->dispPtr
->mouseMainPtr
!= NULL
) {
1807 focusPtr
= winPtr
->dispPtr
->focusPtr
;
1808 if ((focusPtr
!= NULL
)
1809 && (focusPtr
->focusProc
!= NULL
)) {
1810 (*focusPtr
->focusProc
)(focusPtr
->focusData
, 0);
1813 winPtr
->dispPtr
->mouseMainPtr
= newMouseMainPtr
;
1814 if (newMouseMainPtr
!= NULL
) {
1815 focusPtr
= newMouseMainPtr
->dispPtr
->focusPtr
;
1816 if ((focusPtr
!= NULL
)
1817 && (focusPtr
->focusProc
!= NULL
)) {
1818 (*focusPtr
->focusProc
)(focusPtr
->focusData
, 1);
1824 *--------------------------------------------------------------
1826 * TkEventDeadWindow --
1828 * This procedure is invoked when it is determined that
1829 * a window is dead. It cleans up event-related information
1836 * Various things get cleaned up and recycled.
1838 *--------------------------------------------------------------
1843 TkWindow
*winPtr
/* Information about the window
1844 * that is being deleted. */
1847 register TkEventHandler
*handlerPtr
;
1848 register InProgress
*ipPtr
;
1851 * While deleting all the handlers, be careful to check for
1852 * Tk_HandleEvent being about to process one of the deleted
1853 * handlers. If it is, tell it to quit (all of the handlers
1854 * are being deleted).
1857 while (winPtr
->handlerList
!= NULL
) {
1858 handlerPtr
= winPtr
->handlerList
;
1859 winPtr
->handlerList
= handlerPtr
->nextPtr
;
1860 for (ipPtr
= pendingPtr
; ipPtr
!= NULL
; ipPtr
= ipPtr
->nextPtr
) {
1861 if (ipPtr
->nextHandler
== handlerPtr
) {
1862 ipPtr
->nextHandler
= NULL
;
1864 if (ipPtr
->winPtr
== winPtr
) {
1865 ipPtr
->winPtr
= None
;
1868 ckfree((char *) handlerPtr
);
1870 if ((winPtr
->dispPtr
!= NULL
) && (winPtr
->dispPtr
->focusPtr
== winPtr
)) {
1871 winPtr
->dispPtr
->focusPtr
= NULL
;
1876 *----------------------------------------------------------------------
1880 * Try to deduce the current time. "Current time" means the time
1881 * of the event that led to the current code being executed, which
1882 * means the time in the most recently-nested invocation of
1886 * The return value is the time from the current event, or
1887 * CurrentTime if there is no current event or if the current
1888 * event contains no time.
1893 *----------------------------------------------------------------------
1898 TkDisplay
*dispPtr
/* Display for which the time is desired. */
1901 register XEvent
*eventPtr
;
1903 if (pendingPtr
== NULL
) {
1904 return dispPtr
->lastEventTime
;
1906 eventPtr
= pendingPtr
->eventPtr
;
1907 switch (eventPtr
->type
) {
1910 return eventPtr
->xbutton
.time
;
1913 return eventPtr
->xkey
.time
;
1915 return eventPtr
->xmotion
.time
;
1918 return eventPtr
->xcrossing
.time
;
1919 case PropertyNotify
:
1920 return eventPtr
->xproperty
.time
;
1922 return dispPtr
->lastEventTime
;