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(token
, mask
, proc
, clientData
)
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. */
303 register TkEventHandler
*handlerPtr
;
304 register TkWindow
*winPtr
= (TkWindow
*) token
;
308 * Skim through the list of existing handlers to (a) compute the
309 * overall event mask for the window (so we can pass this new
310 * value to the X system) and (b) see if there's already a handler
311 * declared with the same callback and clientData (if so, just
312 * change the mask). If no existing handler matches, then create
317 if (winPtr
->handlerList
== NULL
) {
318 handlerPtr
= (TkEventHandler
*) NewTkEventHandler();
319 winPtr
->handlerList
= handlerPtr
;
322 for (handlerPtr
= winPtr
->handlerList
; ;
323 handlerPtr
= handlerPtr
->nextPtr
) {
324 if ((handlerPtr
->proc
== proc
)
325 && (handlerPtr
->clientData
== clientData
)) {
326 handlerPtr
->mask
= mask
;
329 if (handlerPtr
->nextPtr
== NULL
) {
336 * Create a new handler if no matching old handler was found.
340 handlerPtr
->nextPtr
= NewTkEventHandler();
341 handlerPtr
= handlerPtr
->nextPtr
;
343 handlerPtr
->mask
= mask
;
344 handlerPtr
->proc
= proc
;
345 handlerPtr
->clientData
= clientData
;
346 handlerPtr
->nextPtr
= NULL
;
350 * No need to call XSelectInput: Tk always selects on all events
351 * for all windows (needed to support bindings on classes and "all").
356 *--------------------------------------------------------------
358 * Tk_DeleteEventHandler --
360 * Delete a previously-created handler.
366 * If there existed a handler as described by the
367 * parameters, the handler is deleted so that proc
368 * will not be invoked again.
370 *--------------------------------------------------------------
374 Tk_DeleteEventHandler(token
, mask
, proc
, clientData
)
375 Tk_Window token
; /* Same as corresponding arguments passed */
376 unsigned long mask
; /* previously to Tk_CreateEventHandler. */
378 ClientData clientData
;
380 register TkEventHandler
*handlerPtr
;
381 register InProgress
*ipPtr
;
382 TkEventHandler
*prevPtr
;
383 register TkWindow
*winPtr
= (TkWindow
*) token
;
386 * Find the event handler to be deleted, or return
387 * immediately if it doesn't exist.
390 for (handlerPtr
= winPtr
->handlerList
, prevPtr
= NULL
; ;
391 prevPtr
= handlerPtr
, handlerPtr
= handlerPtr
->nextPtr
) {
392 if (handlerPtr
== NULL
) {
395 if ((handlerPtr
->mask
== mask
) && (handlerPtr
->proc
== proc
)
396 && (handlerPtr
->clientData
== clientData
)) {
402 * If Tk_HandleEvent is about to process this handler, tell it to
403 * process the next one instead.
406 for (ipPtr
= pendingPtr
; ipPtr
!= NULL
; ipPtr
= ipPtr
->nextPtr
) {
407 if (ipPtr
->nextHandler
== handlerPtr
) {
408 ipPtr
->nextHandler
= handlerPtr
->nextPtr
;
413 * Free resources associated with the handler.
416 if (prevPtr
== NULL
) {
417 winPtr
->handlerList
= handlerPtr
->nextPtr
;
419 prevPtr
->nextPtr
= handlerPtr
->nextPtr
;
421 (void) FreeTkEventHandler(handlerPtr
);
425 * No need to call XSelectInput: Tk always selects on all events
426 * for all windows (needed to support bindings on classes and "all").
430 /*--------------------------------------------------------------
432 * Tk_CreateGenericHandler --
434 * Register a procedure to be called on each X event, regardless
435 * of display or window. Generic handlers are useful for capturing
436 * events that aren't associated with windows, or events for windows
443 * From now on, whenever an X event is given to Tk_HandleEvent,
444 * invoke proc, giving it clientData and the event as arguments.
446 *--------------------------------------------------------------
450 Tk_CreateGenericHandler(proc
, clientData
)
451 Tk_GenericProc
*proc
; /* Procedure to call on every event. */
452 ClientData clientData
; /* One-word value to pass to proc. */
454 GenericHandler
*handlerPtr
;
456 handlerPtr
= NewGenericHandler();
458 handlerPtr
->proc
= proc
;
459 handlerPtr
->clientData
= clientData
;
460 handlerPtr
->deleteFlag
= 0;
461 handlerPtr
->nextPtr
= NULL
;
462 if (genericList
== NULL
) {
463 genericList
= handlerPtr
;
465 lastGenericPtr
->nextPtr
= handlerPtr
;
467 lastGenericPtr
= handlerPtr
;
471 *--------------------------------------------------------------
473 * Tk_DeleteGenericHandler --
475 * Delete a previously-created generic handler.
481 * If there existed a handler as described by the parameters,
482 * that handler is logically deleted so that proc will not be
483 * invoked again. The physical deletion happens in the event
484 * loop in Tk_HandleEvent.
486 *--------------------------------------------------------------
490 Tk_DeleteGenericHandler(proc
, clientData
)
491 Tk_GenericProc
*proc
;
492 ClientData clientData
;
494 GenericHandler
* handler
;
496 for (handler
= genericList
; handler
; handler
= handler
->nextPtr
) {
497 if ((handler
->proc
== proc
) && (handler
->clientData
== clientData
)) {
498 handler
->deleteFlag
= 1;
504 *--------------------------------------------------------------
508 * Given an event, invoke all the handlers that have
509 * been registered for the event.
515 * Depends on the handlers.
517 *--------------------------------------------------------------
521 Tk_HandleEvent(eventPtr
)
522 XEvent
*eventPtr
; /* Event to dispatch. */
524 register TkEventHandler
*handlerPtr
;
525 register GenericHandler
*genericPtr
;
526 register GenericHandler
*genPrevPtr
;
528 register unsigned long mask
;
530 Window handlerWindow
;
533 * First off, invoke all the generic event handlers (those that are
534 * invoked for all events). If a generic event handler reports that
535 * an event is fully processed, go no further.
538 for (genPrevPtr
= NULL
, genericPtr
= genericList
; genericPtr
!= NULL
; ) {
539 if (genericPtr
->deleteFlag
) {
540 if (!genericHandlersActive
) {
541 GenericHandler
*tmpPtr
;
544 * This handler needs to be deleted and there are no
545 * calls pending through the handler, so now is a safe
549 tmpPtr
= genericPtr
->nextPtr
;
550 if (genPrevPtr
== NULL
) {
551 genericList
= tmpPtr
;
553 genPrevPtr
->nextPtr
= tmpPtr
;
555 (void) FreeGenericHandler(genericPtr
);
562 genericHandlersActive
++;
563 done
= (*genericPtr
->proc
)(genericPtr
->clientData
, eventPtr
);
564 genericHandlersActive
--;
569 genPrevPtr
= genericPtr
;
570 genericPtr
= genPrevPtr
->nextPtr
;
574 * Events selected by StructureNotify look the same as those
575 * selected by SubstructureNotify; the only difference is
576 * whether the "event" and "window" fields are the same.
577 * Check it out and convert StructureNotify to
578 * SubstructureNotify if necessary.
581 handlerWindow
= eventPtr
->xany
.window
;
582 mask
= eventMasks
[eventPtr
->xany
.type
];
583 if (mask
== StructureNotifyMask
) {
584 if (eventPtr
->xmap
.event
!= eventPtr
->xmap
.window
) {
585 mask
= SubstructureNotifyMask
;
586 handlerWindow
= eventPtr
->xmap
.event
;
589 if (XFindContext(eventPtr
->xany
.display
, handlerWindow
,
590 tkWindowContext
, (void *) &winPtr
) != 0) {
593 * There isn't a TkWindow structure for this window.
594 * However, if the event is a PropertyNotify event then call
595 * the selection manager (it deals beneath-the-table with
596 * certain properties).
599 if (eventPtr
->type
== PropertyNotify
) {
600 TkSelPropProc(eventPtr
);
606 * Redirect KeyPress and KeyRelease events if input focussing
607 * is happening. Map the x and y coordinates between the two
608 * windows, if possible (make both -1 if the map-from and map-to
609 * windows don't share the same top-level window).
612 if (mask
& (KeyPressMask
|KeyReleaseMask
)) {
613 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xkey
.time
;
615 if (winPtr
->dispPtr
->focusPtr
!= NULL
) {
617 int winX
, winY
, focusX
, focusY
;
619 focusPtr
= winPtr
->dispPtr
->focusPtr
;
620 if ((focusPtr
->display
!= winPtr
->display
)
621 || (focusPtr
->screenNum
!= winPtr
->screenNum
)) {
622 eventPtr
->xkey
.x
= -1;
623 eventPtr
->xkey
.y
= -1;
625 Tk_GetRootCoords((Tk_Window
) winPtr
, &winX
, &winY
);
626 Tk_GetRootCoords((Tk_Window
) focusPtr
, &focusX
, &focusY
);
627 eventPtr
->xkey
.x
-= focusX
- winX
;
628 eventPtr
->xkey
.y
-= focusY
- winY
;
630 eventPtr
->xkey
.window
= focusPtr
->window
;
636 * Call a grab-related procedure to do special processing on
640 if (mask
& (ButtonPressMask
|ButtonReleaseMask
|PointerMotionMask
641 |EnterWindowMask
|LeaveWindowMask
)) {
642 if (mask
& (ButtonPressMask
|ButtonReleaseMask
)) {
643 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xbutton
.time
;
644 } else if (mask
& PointerMotionMask
) {
645 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xmotion
.time
;
647 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xcrossing
.time
;
649 if (TkPointerEvent(eventPtr
, winPtr
) == 0) {
655 * For events where it hasn't already been done, update the current
656 * time in the display.
659 if (eventPtr
->type
== PropertyNotify
) {
660 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xproperty
.time
;
664 * There's a potential interaction here with Tk_DeleteEventHandler.
665 * Read the documentation for pendingPtr.
668 ip
.eventPtr
= eventPtr
;
670 ip
.nextHandler
= NULL
;
671 ip
.nextPtr
= pendingPtr
;
674 if ((eventPtr
->type
== SelectionClear
)
675 || (eventPtr
->type
== SelectionRequest
)
676 || (eventPtr
->type
== SelectionNotify
)) {
677 TkSelEventProc((Tk_Window
) winPtr
, eventPtr
);
678 } else if ((eventPtr
->type
== ClientMessage
)
679 && (eventPtr
->xclient
.message_type
==
680 Tk_InternAtom((Tk_Window
) winPtr
, "WM_PROTOCOLS"))) {
682 * this is a ICCCM WM_PROTOCOL ClientMessage
684 TkWmProtocolEventProc(winPtr
, eventPtr
);
687 for (handlerPtr
= winPtr
->handlerList
; handlerPtr
!= NULL
; ) {
688 if ((handlerPtr
->mask
& mask
) != 0) {
689 ip
.nextHandler
= handlerPtr
->nextPtr
;
690 (*(handlerPtr
->proc
))(handlerPtr
->clientData
, eventPtr
);
691 handlerPtr
= ip
.nextHandler
;
693 handlerPtr
= handlerPtr
->nextPtr
;
698 * Pass the event to the "bind" command mechanism. But, don't
699 * do this for SubstructureNotify events. The "bind" command
700 * doesn't support them anyway, and it's easier to filter out
701 * these events here than in the lower-level procedures.
704 if ((ip
.winPtr
!= None
) && (mask
!= SubstructureNotifyMask
)) {
705 TkBindEventProc(winPtr
, eventPtr
);
708 pendingPtr
= ip
.nextPtr
;
712 *--------------------------------------------------------------
714 * Tk_CreateFileHandler --
716 * Arrange for a given procedure to be invoked whenever
717 * a given file becomes readable or writable.
723 * From now on, whenever the I/O channel given by fd becomes
724 * ready in the way indicated by mask, proc will be invoked.
725 * See the manual entry for details on the calling sequence
726 * to proc. If fd is already registered then the old mask
727 * and proc and clientData values will be replaced with
730 *--------------------------------------------------------------
734 Tk_CreateFileHandler(fd
, mask
, proc
, clientData
)
735 int fd
; /* Integer identifier for stream. */
736 int mask
; /* OR'ed combination of TK_READABLE,
737 * TK_WRITABLE, and TK_EXCEPTION:
738 * indicates conditions under which
739 * proc should be called. */
740 Tk_FileProc
*proc
; /* Procedure to call for each
741 * selected event. NULL means that
742 * this is a display, and that
743 * clientData is the (Display *)
744 * for it, and that events should
745 * be handled automatically. */
746 ClientData clientData
; /* Arbitrary data to pass to proc. */
748 register FileEvent
*filePtr
;
751 if (fd
>= OPEN_MAX
) {
752 panic("Tk_CreatefileHandler can't handle file id %d", fd
);
756 * Make sure the file isn't already registered. Create a
757 * new record in the normal case where there's no existing
761 for (filePtr
= fileList
; filePtr
!= NULL
;
762 filePtr
= filePtr
->nextPtr
) {
763 if (filePtr
->fd
== fd
) {
767 index
= fd
/(8*sizeof(int));
768 if (filePtr
== NULL
) {
769 filePtr
= NewFileEvent();
771 filePtr
->readPtr
= &ready
[index
];
772 filePtr
->writePtr
= &ready
[index
+MASK_SIZE
];
773 filePtr
->exceptPtr
= &ready
[index
+2*MASK_SIZE
];
774 filePtr
->mask
= 1 << (fd
%(8*sizeof(int)));
775 filePtr
->nextPtr
= fileList
;
778 if (masks
[index
] & filePtr
->mask
) {
780 *filePtr
->readPtr
&= ~filePtr
->mask
;
781 masks
[index
] &= ~filePtr
->mask
;
783 if (masks
[index
+MASK_SIZE
] & filePtr
->mask
) {
785 *filePtr
->writePtr
&= ~filePtr
->mask
;
786 masks
[index
+MASK_SIZE
] &= ~filePtr
->mask
;
788 if (masks
[index
+2*MASK_SIZE
] & filePtr
->mask
) {
790 *filePtr
->exceptPtr
&= ~filePtr
->mask
;
791 masks
[index
+2*MASK_SIZE
] &= ~filePtr
->mask
;
796 * The remainder of the initialization below is done
797 * regardless of whether or not this is a new record
798 * or a modification of an old one.
801 if (mask
& TK_READABLE
) {
802 masks
[index
] |= filePtr
->mask
;
805 readPtr
= (readCount
== 0 ? NULL
: &ready
[0]);
807 if (mask
& TK_WRITABLE
) {
808 masks
[index
+MASK_SIZE
] |= filePtr
->mask
;
811 writePtr
= (writeCount
== 0 ? NULL
: &ready
[MASK_SIZE
]);
813 if (mask
& TK_EXCEPTION
) {
814 masks
[index
+2*MASK_SIZE
] |= filePtr
->mask
;
817 exceptPtr
= (exceptCount
== 0 ? NULL
: &ready
[2*MASK_SIZE
]);
819 filePtr
->proc
= proc
;
820 filePtr
->clientData
= clientData
;
828 *--------------------------------------------------------------
830 * Tk_DeleteFileHandler --
832 * Cancel a previously-arranged callback arrangement for
839 * If a callback was previously registered on fd, remove it.
841 *--------------------------------------------------------------
845 Tk_DeleteFileHandler(fd
)
846 int fd
; /* Stream id for which to remove
847 * callback procedure. */
849 register FileEvent
*filePtr
;
854 * Find the entry for the given file (and return if there
858 for (prevPtr
= NULL
, filePtr
= fileList
; ;
859 prevPtr
= filePtr
, filePtr
= filePtr
->nextPtr
) {
860 if (filePtr
== NULL
) {
863 if (filePtr
->fd
== fd
) {
869 * Clean up information in the callback record.
872 index
= filePtr
->fd
/(8*sizeof(int));
873 if (masks
[index
] & filePtr
->mask
) {
875 *filePtr
->readPtr
&= ~filePtr
->mask
;
876 masks
[index
] &= ~filePtr
->mask
;
878 if (masks
[index
+MASK_SIZE
] & filePtr
->mask
) {
880 *filePtr
->writePtr
&= ~filePtr
->mask
;
881 masks
[index
+MASK_SIZE
] &= ~filePtr
->mask
;
883 if (masks
[index
+2*MASK_SIZE
] & filePtr
->mask
) {
885 *filePtr
->exceptPtr
&= ~filePtr
->mask
;
886 masks
[index
+2*MASK_SIZE
] &= ~filePtr
->mask
;
888 if (prevPtr
== NULL
) {
889 fileList
= filePtr
->nextPtr
;
891 prevPtr
->nextPtr
= filePtr
->nextPtr
;
893 FreeFileEvent(filePtr
);
900 for (filePtr
= fileList
; filePtr
!= NULL
;
901 filePtr
= filePtr
->nextPtr
) {
902 if (numFds
<= filePtr
->fd
) {
903 numFds
= filePtr
->fd
+1;
909 *--------------------------------------------------------------
911 * Tk_CreateTimerHandler --
913 * Arrange for a given procedure to be invoked at a particular
914 * time in the future.
917 * The return value is a token for the timer event, which
918 * may be used to delete the event before it fires.
921 * When milliseconds have elapsed, proc will be invoked
924 *--------------------------------------------------------------
928 Tk_CreateTimerHandler(milliseconds
, proc
, clientData
)
929 int milliseconds
; /* How many milliseconds to wait
930 * before invoking proc. */
931 Tk_TimerProc
*proc
; /* Procedure to invoke. */
932 ClientData clientData
; /* Arbitrary data to pass to proc. */
934 register TimerEvent
*timerPtr
, *tPtr2
, *prevPtr
;
937 timerPtr
= NewTimerEvent();
940 * Compute when the event should fire.
943 (void) gettimeofday(&timerPtr
->time
, (struct timezone
*) NULL
);
944 timerPtr
->time
.tv_sec
+= milliseconds
/1000;
945 timerPtr
->time
.tv_usec
+= (milliseconds
%1000)*1000;
946 if (timerPtr
->time
.tv_usec
> 1000000) {
947 timerPtr
->time
.tv_usec
-= 1000000;
948 timerPtr
->time
.tv_sec
+= 1;
952 * Fill in other fields for the event.
955 timerPtr
->proc
= proc
;
956 timerPtr
->clientData
= clientData
;
958 timerPtr
->token
= (Tk_TimerToken
) id
;
961 * Add the event to the queue in the correct position
962 * (ordered by event firing time).
965 for (tPtr2
= timerQueue
, prevPtr
= NULL
; tPtr2
!= NULL
;
966 prevPtr
= tPtr2
, tPtr2
= tPtr2
->nextPtr
) {
967 if ((tPtr2
->time
.tv_sec
> timerPtr
->time
.tv_sec
)
968 || ((tPtr2
->time
.tv_sec
== timerPtr
->time
.tv_sec
)
969 && (tPtr2
->time
.tv_usec
> timerPtr
->time
.tv_usec
))) {
973 if (prevPtr
== NULL
) {
974 timerPtr
->nextPtr
= timerQueue
;
975 timerQueue
= timerPtr
;
977 timerPtr
->nextPtr
= prevPtr
->nextPtr
;
978 prevPtr
->nextPtr
= timerPtr
;
980 return timerPtr
->token
;
983 // Added by Don to support finer timer resolution.
985 *--------------------------------------------------------------
987 * Tk_CreateMicroTimerHandler --
989 * Arrange for a given procedure to be invoked at a particular
990 * time in the future.
993 * The return value is a token for the timer event, which
994 * may be used to delete the event before it fires.
997 * When seconds and seconds have elapsed, proc will be invoked
1000 *--------------------------------------------------------------
1004 Tk_CreateMicroTimerHandler(seconds
, microseconds
, proc
, clientData
)
1005 int seconds
; /* How many seconds to wait
1006 * before invoking proc. */
1007 int microseconds
; /* How many microseconds to wait
1008 * before invoking proc. */
1009 Tk_TimerProc
*proc
; /* Procedure to invoke. */
1010 ClientData clientData
; /* Arbitrary data to pass to proc. */
1012 register TimerEvent
*timerPtr
, *tPtr2
, *prevPtr
;
1015 timerPtr
= NewTimerEvent();
1018 * Compute when the event should fire.
1021 (void) gettimeofday(&timerPtr
->time
, (struct timezone
*) NULL
);
1022 timerPtr
->time
.tv_sec
+= seconds
;
1023 timerPtr
->time
.tv_usec
+= microseconds
;
1024 while (timerPtr
->time
.tv_usec
> 1000000) {
1025 timerPtr
->time
.tv_usec
-= 1000000;
1026 timerPtr
->time
.tv_sec
+= 1;
1030 * Fill in other fields for the event.
1033 timerPtr
->proc
= proc
;
1034 timerPtr
->clientData
= clientData
;
1036 timerPtr
->token
= (Tk_TimerToken
) id
;
1039 * Add the event to the queue in the correct position
1040 * (ordered by event firing time).
1043 for (tPtr2
= timerQueue
, prevPtr
= NULL
; tPtr2
!= NULL
;
1044 prevPtr
= tPtr2
, tPtr2
= tPtr2
->nextPtr
) {
1045 if ((tPtr2
->time
.tv_sec
> timerPtr
->time
.tv_sec
)
1046 || ((tPtr2
->time
.tv_sec
== timerPtr
->time
.tv_sec
)
1047 && (tPtr2
->time
.tv_usec
> timerPtr
->time
.tv_usec
))) {
1051 if (prevPtr
== NULL
) {
1052 timerPtr
->nextPtr
= timerQueue
;
1053 timerQueue
= timerPtr
;
1055 timerPtr
->nextPtr
= prevPtr
->nextPtr
;
1056 prevPtr
->nextPtr
= timerPtr
;
1058 return timerPtr
->token
;
1063 *--------------------------------------------------------------
1065 * Tk_DeleteTimerHandler --
1067 * Delete a previously-registered timer handler.
1073 * Destroy the timer callback identified by TimerToken,
1074 * so that its associated procedure will not be called.
1075 * If the callback has already fired, or if the given
1076 * token doesn't exist, then nothing happens.
1078 *--------------------------------------------------------------
1082 Tk_DeleteTimerHandler(token
)
1083 Tk_TimerToken token
; /* Result previously returned by
1084 * Tk_DeleteTimerHandler. */
1086 register TimerEvent
*timerPtr
, *prevPtr
;
1088 if (token
== 0) return;
1090 for (timerPtr
= timerQueue
, prevPtr
= NULL
; timerPtr
!= NULL
;
1091 prevPtr
= timerPtr
, timerPtr
= timerPtr
->nextPtr
) {
1092 if (timerPtr
->token
!= token
) {
1095 if (prevPtr
== NULL
) {
1096 timerQueue
= timerPtr
->nextPtr
;
1098 prevPtr
->nextPtr
= timerPtr
->nextPtr
;
1100 FreeTimerEvent(timerPtr
);
1104 // fprintf(stderr, "Tk_DeleteTimerHandler called on bogus timer %d\n", token);
1108 *--------------------------------------------------------------
1112 * Arrange for proc to be invoked the next time the
1113 * system is idle (i.e., just before the next time
1114 * that Tk_DoOneEvent would have to wait for something
1121 * Proc will eventually be called, with clientData
1122 * as argument. See the manual entry for details.
1124 *--------------------------------------------------------------
1128 Tk_DoWhenIdle(proc
, clientData
)
1129 Tk_IdleProc
*proc
; /* Procedure to invoke. */
1130 ClientData clientData
; /* Arbitrary value to pass to proc. */
1132 register IdleHandler
*idlePtr
;
1134 idlePtr
= NewIdleHandler();
1135 idlePtr
->proc
= proc
;
1136 idlePtr
->clientData
= clientData
;
1137 idlePtr
->nextPtr
= NULL
;
1138 if (lastIdlePtr
== NULL
) {
1141 lastIdlePtr
->nextPtr
= idlePtr
;
1143 lastIdlePtr
= idlePtr
;
1147 *----------------------------------------------------------------------
1149 * Tk_CancelIdleCall --
1151 * If there are any when-idle calls requested to a given procedure
1152 * with given clientData, cancel all of them.
1158 * If the proc/clientData combination were on the when-idle list,
1159 * they are removed so that they will never be called.
1161 *----------------------------------------------------------------------
1165 Tk_CancelIdleCall(proc
, clientData
)
1166 Tk_IdleProc
*proc
; /* Procedure that was previously registered. */
1167 ClientData clientData
; /* Arbitrary value to pass to proc. */
1169 register IdleHandler
*idlePtr
, *prevPtr
;
1170 IdleHandler
*nextPtr
;
1172 for (prevPtr
= NULL
, idlePtr
= idleList
; idlePtr
!= NULL
;
1173 prevPtr
= idlePtr
, idlePtr
= idlePtr
->nextPtr
) {
1174 while ((idlePtr
->proc
== proc
)
1175 && (idlePtr
->clientData
== clientData
)) {
1176 nextPtr
= idlePtr
->nextPtr
;
1177 FreeIdleHandler(idlePtr
);
1179 if (prevPtr
== NULL
) {
1182 prevPtr
->nextPtr
= idlePtr
;
1184 if (idlePtr
== NULL
) {
1185 lastIdlePtr
= prevPtr
;
1193 *--------------------------------------------------------------
1197 * Process a single event of some sort. If there's no
1198 * work to do, wait for an event to occur, then process
1202 * The return value is 1 if the procedure actually found
1203 * an event to process. If no event was found then 0 is
1207 * May delay execution of process while waiting for an
1208 * X event, X error, file-ready event, or timer event.
1209 * The handling of the event could cause additional
1210 * side effects. Collapses sequences of mouse-motion
1211 * events for the same window into a single event by
1212 * delaying motion event processing.
1214 *--------------------------------------------------------------
1218 Tk_DoOneEvent(flags
)
1219 int flags
; /* Miscellaneous flag values: may be any
1220 * combination of TK_DONT_WAIT, TK_X_EVENTS,
1221 * TK_FILE_EVENTS, TK_TIMER_EVENTS, and
1222 * TK_IDLE_EVENTS. */
1224 register FileEvent
*filePtr
;
1225 struct timeval curTime
, timeout
, *timeoutPtr
;
1227 static XEvent delayedMotionEvent
; /* Used to hold motion events that
1228 * are being saved until later. */
1229 static int eventDelayed
= 0; /* Non-zero means there is an event
1230 * in delayedMotionEvent. */
1232 if ((flags
& TK_ALL_EVENTS
) == 0) {
1233 flags
|= TK_ALL_EVENTS
;
1237 * Phase One: see if there's already something ready
1238 * (either a file or a display) that was left over
1239 * from before (i.e don't do a select, just check the
1240 * bits from the last select).
1244 for (filePtr
= fileList
; filePtr
!= NULL
;
1245 filePtr
= filePtr
->nextPtr
) {
1249 * Displays: flush output, check for queued events,
1250 * and read events from the server if display is ready.
1251 * If there are any events, process one and then
1255 if ((filePtr
->proc
== NULL
) && (flags
& TK_X_EVENTS
)) {
1256 Display
*display
= (Display
*) filePtr
->clientData
;
1260 if ((*filePtr
->readPtr
) & filePtr
->mask
) {
1261 *filePtr
->readPtr
&= ~filePtr
->mask
;
1262 if (XEventsQueued(display
, QueuedAfterReading
) == 0) {
1265 * Things are very tricky if there aren't any events
1266 * readable at this point (after all, there was
1267 * supposedly data available on the connection).
1268 * A couple of things could have occurred:
1270 * One possibility is that there were only error events
1271 * in the input from the server. If this happens,
1272 * we should return (we don't want to go to sleep
1273 * in XNextEvent below, since this would block out
1274 * other sources of input to the process).
1276 * Another possibility is that our connection to the
1277 * server has been closed. This will not necessarily
1278 * be detected in XEventsQueued (!!), so if we just
1279 * return then there will be an infinite loop. To
1280 * detect such an error, generate a NoOp protocol
1281 * request to exercise the connection to the server,
1282 * then return. However, must disable SIGPIPE while
1283 * sending the event, or else the process will die
1284 * from the signal and won't invoke the X error
1285 * function to print a nice message.
1288 void (*oldHandler
)();
1290 oldHandler
= (void (*)()) signal(SIGPIPE
, SIG_IGN
);
1293 (void) signal(SIGPIPE
, oldHandler
);
1296 if (restrictProc
!= NULL
) {
1297 if (!XCheckIfEvent(display
, &event
, restrictProc
,
1302 XNextEvent(display
, &event
);
1305 if (QLength(display
) == 0) {
1308 if (restrictProc
!= NULL
) {
1309 if (!XCheckIfEvent(display
, &event
, restrictProc
,
1314 XNextEvent(display
, &event
);
1319 * Got an event. Deal with mouse-motion-collapsing and
1320 * event-delaying here. If there's already an event delayed,
1321 * then process that event if it's incompatible with the new
1322 * event (new event not mouse motion, or window changed, or
1323 * state changed). If the new event is mouse motion, then
1324 * don't process it now; delay it until later in the hopes
1325 * that it can be merged with other mouse motion events
1326 * immediately following.
1330 eventTrace
[traceIndex
] = event
;
1331 traceIndex
= (traceIndex
+1) % TK_NEVENTS
;
1335 if (((event
.type
!= MotionNotify
)
1336 && (event
.type
!= GraphicsExpose
)
1337 && (event
.type
!= NoExpose
)
1338 && (event
.type
!= Expose
))
1339 || (event
.xmotion
.display
1340 != delayedMotionEvent
.xmotion
.display
)
1341 || (event
.xmotion
.window
1342 != delayedMotionEvent
.xmotion
.window
)) {
1346 * Must copy the event out of delayedMotionEvent before
1347 * processing it, in order to allow recursive calls to
1348 * Tk_DoOneEvent as part of the handler.
1351 copy
= delayedMotionEvent
;
1353 Tk_HandleEvent(©
);
1356 if (tkCollapseMotion
&& event
.type
== MotionNotify
) {
1357 delayedMotionEvent
= event
;
1360 Tk_HandleEvent(&event
);
1366 * Not a display: if the file is ready, call the
1367 * appropriate handler.
1370 if (((*filePtr
->readPtr
| *filePtr
->writePtr
1371 | *filePtr
->exceptPtr
) & filePtr
->mask
) == 0) {
1374 if (!(flags
& TK_FILE_EVENTS
)) {
1378 if (*filePtr
->readPtr
& filePtr
->mask
) {
1379 mask
|= TK_READABLE
;
1380 *filePtr
->readPtr
&= ~filePtr
->mask
;
1382 if (*filePtr
->writePtr
& filePtr
->mask
) {
1383 mask
|= TK_WRITABLE
;
1384 *filePtr
->writePtr
&= ~filePtr
->mask
;
1386 if (*filePtr
->exceptPtr
& filePtr
->mask
) {
1387 mask
|= TK_EXCEPTION
;
1388 *filePtr
->exceptPtr
&= ~filePtr
->mask
;
1390 (*filePtr
->proc
)(filePtr
->clientData
, mask
);
1395 * Phase Two: get the current time and see if any timer
1396 * events are ready to fire. If so, fire one and return.
1400 if ((timerQueue
!= NULL
) && (flags
& TK_TIMER_EVENTS
)) {
1401 register TimerEvent
*timerPtr
= timerQueue
;
1403 (void) gettimeofday(&curTime
, (struct timezone
*) NULL
);
1404 if ((timerPtr
->time
.tv_sec
< curTime
.tv_sec
)
1405 || ((timerPtr
->time
.tv_sec
== curTime
.tv_sec
)
1406 && (timerPtr
->time
.tv_usec
< curTime
.tv_usec
))) {
1407 timerQueue
= timerPtr
->nextPtr
;
1408 (*timerPtr
->proc
)(timerPtr
->clientData
);
1409 FreeTimerEvent(timerPtr
);
1416 * Phase Three: if there is a delayed motion event, process it
1417 * now, before any DoWhenIdle handlers. Better to process before
1418 * idle handlers than after, because the goal of idle handlers is
1419 * to delay until after all pending events have been processed.
1420 * Must free up delayedMotionEvent *before* calling Tk_HandleEvent,
1421 * so that the event handler can call Tk_DoOneEvent recursively
1422 * without infinite looping.
1425 if ((eventDelayed
) && (flags
& TK_X_EVENTS
)) {
1428 copy
= delayedMotionEvent
;
1430 Tk_HandleEvent(©
);
1435 * Phase Four: if there are DoWhenIdle requests pending (or
1436 * if we're not allowed to block), then do a select with an
1437 * instantaneous timeout. If a ready file is found, then go
1438 * back to process it.
1441 if (((idleList
!= NULL
) && (flags
& TK_IDLE_EVENTS
))
1442 || (flags
& TK_DONT_WAIT
)) {
1443 if (flags
& (TK_X_EVENTS
|TK_FILE_EVENTS
)) {
1444 memcpy((VOID
*) ready
, (VOID
*) masks
, 3*MASK_SIZE
*sizeof(int));
1445 timeout
.tv_sec
= timeout
.tv_usec
= 0;
1447 numFound
= select(numFds
, (SELECT_MASK
*) readPtr
,
1448 (SELECT_MASK
*) writePtr
, (SELECT_MASK
*) exceptPtr
,
1450 } while ((numFound
== -1) && (errno
== EINTR
));
1458 * Phase Five: process all pending DoWhenIdle requests.
1461 if ((idleList
!= NULL
) && (flags
& TK_IDLE_EVENTS
)) {
1462 register IdleHandler
*idlePtr
;
1465 * If you change the code below, be aware that new handlers
1466 * can get added to the list while the current one is being
1469 * NOTE! Must remove the entry from the list before calling
1470 * it, in case the idle handler calls Tk_DoOneEvent: don't
1471 * want to loop infinitely. Must also be careful because
1472 * Tk_CancelIdleCall could change the list during the call.
1475 while (idleList
!= NULL
) {
1477 idleList
= idlePtr
->nextPtr
;
1478 if (idleList
== NULL
) {
1481 (*idlePtr
->proc
)(idlePtr
->clientData
);
1482 FreeIdleHandler(idlePtr
);
1488 * Phase Six: do a select to wait for either one of the
1489 * files to become ready or for the first timer event to
1490 * fire. Then go back to process the event.
1493 if ((flags
& TK_DONT_WAIT
)
1494 || !(flags
& (TK_TIMER_EVENTS
|TK_FILE_EVENTS
|TK_X_EVENTS
))) {
1497 if ((timerQueue
== NULL
) || !(flags
& TK_TIMER_EVENTS
)) {
1500 timeoutPtr
= &timeout
;
1501 timeout
.tv_sec
= timerQueue
->time
.tv_sec
- curTime
.tv_sec
;
1502 timeout
.tv_usec
= timerQueue
->time
.tv_usec
- curTime
.tv_usec
;
1503 if (timeout
.tv_usec
< 0) {
1504 timeout
.tv_sec
-= 1;
1505 timeout
.tv_usec
+= 1000000;
1508 memcpy((VOID
*) ready
, (VOID
*) masks
, 3*MASK_SIZE
*sizeof(int));
1510 numFound
= select(numFds
, (SELECT_MASK
*) readPtr
,
1511 (SELECT_MASK
*) writePtr
, (SELECT_MASK
*) exceptPtr
,
1513 } while ((numFound
== -1) && (errno
== EINTR
));
1514 if (numFound
== 0) {
1521 *--------------------------------------------------------------
1525 * Call Tk_DoOneEvent over and over again in an infinite
1526 * loop as long as there exist any main windows.
1532 * Arbitrary; depends on handlers for events.
1534 *--------------------------------------------------------------
1540 while (!tkMustExit
&&
1541 tk_NumMainWindows
> 0) {
1547 *----------------------------------------------------------------------
1551 * Delay execution for the specified number of milliseconds.
1559 *----------------------------------------------------------------------
1564 int ms
; /* Number of milliseconds to sleep. */
1566 static struct timeval delay
;
1568 delay
.tv_sec
= ms
/1000;
1569 delay
.tv_usec
= (ms
%1000)*1000;
1570 (void) select(0, (SELECT_MASK
*) 0, (SELECT_MASK
*) 0,
1571 (SELECT_MASK
*) 0, &delay
);
1575 *----------------------------------------------------------------------
1577 * Tk_RestrictEvents --
1579 * This procedure is used to globally restrict the set of events
1580 * that will be dispatched. The restriction is done by filtering
1581 * all incoming X events through a procedure that determines
1582 * whether they are to be processed immediately or deferred.
1585 * The return value is the previous restriction procedure in effect,
1586 * if there was one, or NULL if there wasn't.
1589 * From now on, proc will be called to determine whether to process
1590 * or defer each incoming X event.
1592 *----------------------------------------------------------------------
1596 Tk_RestrictEvents(proc
, arg
, prevArgPtr
)
1597 Tk_RestrictProc
*proc
; /* X "if" procedure to call for each
1598 * incoming event. See "XIfEvent" doc.
1600 char *arg
; /* Arbitrary argument to pass to proc. */
1601 char **prevArgPtr
; /* Place to store information about previous
1604 Bool (*prev
) _ANSI_ARGS_((Display
*display
, XEvent
*eventPtr
, char *arg
));
1606 prev
= restrictProc
;
1607 *prevArgPtr
= restrictArg
;
1608 restrictProc
= proc
;
1614 *--------------------------------------------------------------
1616 * Tk_CreateFocusHandler --
1618 * Arrange for a procedure to be called whenever the focus
1619 * enters or leaves a given window.
1625 * After this procedure has been invoked, whenever tkwin gets
1626 * or loses the input focus, proc will be called. It should have
1627 * the following structure:
1630 * proc(clientData, gotFocus)
1631 * ClientData clientData;
1636 * The clientData argument to "proc" will be the same as the
1637 * clientData argument to this procedure. GotFocus will be
1638 * 1 if tkwin is getting the focus, and 0 if it's losing the
1641 *--------------------------------------------------------------
1645 Tk_CreateFocusHandler(tkwin
, proc
, clientData
)
1646 Tk_Window tkwin
; /* Token for window. */
1647 Tk_FocusProc
*proc
; /* Procedure to call when tkwin gets
1648 * or loses the input focus. */
1649 ClientData clientData
; /* Arbitrary value to pass to proc. */
1651 register TkWindow
*winPtr
= (TkWindow
*) tkwin
;
1653 winPtr
->focusProc
= proc
;
1654 winPtr
->focusData
= clientData
;
1658 *--------------------------------------------------------------
1662 * This procedure is invoked to process the "focus" Tcl command.
1663 * See the user documentation for details on what it does.
1666 * A standard Tcl result.
1669 * See the user documentation.
1671 *--------------------------------------------------------------
1675 Tk_FocusCmd(clientData
, interp
, argc
, argv
)
1676 ClientData clientData
; /* Main window associated with
1678 Tcl_Interp
*interp
; /* Current interpreter. */
1679 int argc
; /* Number of arguments. */
1680 char **argv
; /* Argument strings. */
1682 Tk_Window tkwin
= (Tk_Window
) clientData
;
1683 register TkWindow
*winPtr
= (TkWindow
*) clientData
;
1684 register TkWindow
*newPtr
;
1688 Tcl_AppendResult(interp
, "too many args: should be \"",
1689 argv
[0], " ?-query? ?window?\"", (char *) NULL
);
1694 if (winPtr
->dispPtr
->focusPtr
== NULL
) {
1695 interp
->result
= "none";
1697 interp
->result
= winPtr
->dispPtr
->focusPtr
->pathName
;
1702 if (argv
[1][0] == '-') {
1705 switchLength
= strlen(argv
[1]);
1706 if ((switchLength
>= 2)
1707 && (strncmp(argv
[1], "-query", switchLength
) == 0)) {
1713 newPtr
= (TkWindow
*) Tk_NameToWindow(interp
, argv
[2], tkwin
);
1714 if (newPtr
== NULL
) {
1717 if (newPtr
->dispPtr
->focusPtr
== NULL
) {
1718 interp
->result
= "none";
1720 interp
->result
= newPtr
->dispPtr
->focusPtr
->pathName
;
1730 if (strcmp(argv
[1], "none") == 0) {
1733 newPtr
= (TkWindow
*) Tk_NameToWindow(interp
, argv
[1], tkwin
);
1734 if (newPtr
== NULL
) {
1738 /* XXX: mumble frotz */
1739 /* if (newPtr->dispPtr->focusPtr == newPtr) { */
1740 if ((!newPtr
) || (newPtr
->dispPtr
->focusPtr
== newPtr
)) {
1743 if (winPtr
== newPtr
->dispPtr
->mouseMainPtr
) { /* XXX: ??? presumably */
1744 if ((newPtr
->dispPtr
->focusPtr
!= NULL
)
1745 && (newPtr
->dispPtr
->focusPtr
->focusProc
!= NULL
)) {
1746 (*newPtr
->dispPtr
->focusPtr
->focusProc
)(
1747 newPtr
->dispPtr
->focusPtr
->focusData
, 0);
1749 newPtr
->dispPtr
->focusPtr
= newPtr
;
1750 if ((newPtr
!= NULL
) && (newPtr
->focusProc
!= NULL
)) {
1751 (*newPtr
->focusProc
)(newPtr
->focusData
, 1);
1754 newPtr
->dispPtr
->focusPtr
= newPtr
;
1760 *--------------------------------------------------------------
1762 * TkFocusEventProc --
1764 * This procedure is invoked whenever the pointer enters
1765 * or leaves a top-level window. It notifies the current
1766 * owner of the focus, if any.
1774 *--------------------------------------------------------------
1778 TkFocusEventProc(winPtr
, eventPtr
)
1779 register TkWindow
*winPtr
; /* Top-level window just entered or left. */
1780 XEvent
*eventPtr
; /* EnterWindow or LeaveWindow event. */
1782 register TkWindow
*focusPtr
;
1783 TkWindow
*newMouseMainPtr
= NULL
;
1785 if (eventPtr
->type
== EnterNotify
) {
1786 newMouseMainPtr
= winPtr
->mainPtr
->winPtr
;
1788 if (winPtr
->dispPtr
->mouseMainPtr
== newMouseMainPtr
) {
1791 if (winPtr
->dispPtr
->mouseMainPtr
!= NULL
) {
1792 focusPtr
= winPtr
->dispPtr
->focusPtr
;
1793 if ((focusPtr
!= NULL
)
1794 && (focusPtr
->focusProc
!= NULL
)) {
1795 (*focusPtr
->focusProc
)(focusPtr
->focusData
, 0);
1798 winPtr
->dispPtr
->mouseMainPtr
= newMouseMainPtr
;
1799 if (newMouseMainPtr
!= NULL
) {
1800 focusPtr
= newMouseMainPtr
->dispPtr
->focusPtr
;
1801 if ((focusPtr
!= NULL
)
1802 && (focusPtr
->focusProc
!= NULL
)) {
1803 (*focusPtr
->focusProc
)(focusPtr
->focusData
, 1);
1809 *--------------------------------------------------------------
1811 * TkEventDeadWindow --
1813 * This procedure is invoked when it is determined that
1814 * a window is dead. It cleans up event-related information
1821 * Various things get cleaned up and recycled.
1823 *--------------------------------------------------------------
1827 TkEventDeadWindow(winPtr
)
1828 TkWindow
*winPtr
; /* Information about the window
1829 * that is being deleted. */
1831 register TkEventHandler
*handlerPtr
;
1832 register InProgress
*ipPtr
;
1835 * While deleting all the handlers, be careful to check for
1836 * Tk_HandleEvent being about to process one of the deleted
1837 * handlers. If it is, tell it to quit (all of the handlers
1838 * are being deleted).
1841 while (winPtr
->handlerList
!= NULL
) {
1842 handlerPtr
= winPtr
->handlerList
;
1843 winPtr
->handlerList
= handlerPtr
->nextPtr
;
1844 for (ipPtr
= pendingPtr
; ipPtr
!= NULL
; ipPtr
= ipPtr
->nextPtr
) {
1845 if (ipPtr
->nextHandler
== handlerPtr
) {
1846 ipPtr
->nextHandler
= NULL
;
1848 if (ipPtr
->winPtr
== winPtr
) {
1849 ipPtr
->winPtr
= None
;
1852 ckfree((char *) handlerPtr
);
1854 if ((winPtr
->dispPtr
!= NULL
) && (winPtr
->dispPtr
->focusPtr
== winPtr
)) {
1855 winPtr
->dispPtr
->focusPtr
= NULL
;
1860 *----------------------------------------------------------------------
1864 * Try to deduce the current time. "Current time" means the time
1865 * of the event that led to the current code being executed, which
1866 * means the time in the most recently-nested invocation of
1870 * The return value is the time from the current event, or
1871 * CurrentTime if there is no current event or if the current
1872 * event contains no time.
1877 *----------------------------------------------------------------------
1881 TkCurrentTime(dispPtr
)
1882 TkDisplay
*dispPtr
; /* Display for which the time is desired. */
1884 register XEvent
*eventPtr
;
1886 if (pendingPtr
== NULL
) {
1887 return dispPtr
->lastEventTime
;
1889 eventPtr
= pendingPtr
->eventPtr
;
1890 switch (eventPtr
->type
) {
1893 return eventPtr
->xbutton
.time
;
1896 return eventPtr
->xkey
.time
;
1898 return eventPtr
->xmotion
.time
;
1901 return eventPtr
->xcrossing
.time
;
1902 case PropertyNotify
:
1903 return eventPtr
->xproperty
.time
;
1905 return dispPtr
->lastEventTime
;