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)";
31 * For each timer callback that's pending, there is one record
32 * of the following type, chained together in a list sorted by
33 * time (earliest event first).
36 typedef struct TimerEvent
{
37 struct timeval time
; /* When timer is to fire. */
38 void (*proc
) _ANSI_ARGS_((ClientData clientData
));
39 /* Procedure to call. */
40 ClientData clientData
; /* Argument to pass to proc. */
41 Tk_TimerToken token
; /* Identifies event so it can be
43 struct TimerEvent
*nextPtr
; /* Next event in queue, or NULL for
47 static TimerEvent
*timerQueue
; /* First event in queue. */
50 * The information below is used to provide read, write, and
51 * exception masks to select during calls to Tk_DoOneEvent.
54 static int readCount
; /* Number of files for which we */
55 static int writeCount
; /* care about each event type. */
56 static int exceptCount
;
57 #define MASK_SIZE ((OPEN_MAX+(8*sizeof(int))-1)/(8*sizeof(int)))
58 static int masks
[3*MASK_SIZE
]; /* Integer array containing official
59 * copies of the three sets of
61 static int ready
[3*MASK_SIZE
]; /* Temporary copy of masks, passed
62 * to select and modified by kernel
63 * to indicate which files are
65 static int *readPtr
; /* Pointers to the portions of */
66 static int *writePtr
; /* *readyPtr for reading, writing, */
67 static int *exceptPtr
; /* and excepting. Will be NULL if
68 * corresponding count (e.g. readCount
70 static int numFds
= 0; /* Number of valid bits in mask
71 * arrays (this value is passed
75 * For each file registered in a call to Tk_CreateFileHandler,
76 * and for each display that's currently active, there is one
77 * record of the following type. All of these records are
78 * chained together into a single list.
81 typedef struct FileEvent
{
82 int fd
; /* Descriptor number for this file. */
83 int *readPtr
; /* Pointer to word in ready array
84 * for this file's read mask bit. */
85 int *writePtr
; /* Same for write mask bit. */
86 int *exceptPtr
; /* Same for except mask bit. */
87 int mask
; /* Value to AND with mask word to
88 * select just this file's bit. */
89 void (*proc
) _ANSI_ARGS_((ClientData clientData
, int mask
));
90 /* Procedure to call. NULL means
91 * this is a display. */
92 ClientData clientData
; /* Argument to pass to proc. For
93 * displays, this is a (Display *). */
94 struct FileEvent
*nextPtr
; /* Next in list of all files we
95 * care about (NULL for end of
99 static FileEvent
*fileList
; /* List of all file events. */
102 * There is one of the following structures for each of the
103 * handlers declared in a call to Tk_DoWhenIdle. All of the
104 * currently-active handlers are linked together into a list.
107 typedef struct IdleHandler
{
108 void (*proc
) _ANSI_ARGS_((ClientData clientData
));
109 /* Procedure to call. */
110 ClientData clientData
; /* Value to pass to proc. */
111 struct IdleHandler
*nextPtr
;/* Next in list of active handlers. */
114 static IdleHandler
*idleList
= NULL
;
115 /* First in list of all idle handlers. */
116 static IdleHandler
*lastIdlePtr
= NULL
;
117 /* Last in list (or NULL for empty list). */
120 * There's a potential problem if a handler is deleted while it's
121 * current (i.e. its procedure is executing), since Tk_HandleEvent
122 * will need to read the handler's "nextPtr" field when the procedure
123 * returns. To handle this problem, structures of the type below
124 * indicate the next handler to be processed for any (recursively
125 * nested) dispatches in progress. The nextHandler fields get
126 * updated if the handlers pointed to are deleted. Tk_HandleEvent
127 * also needs to know if the entire window gets deleted; the winPtr
128 * field is set to zero if that particular window gets deleted.
131 typedef struct InProgress
{
132 XEvent
*eventPtr
; /* Event currently being handled. */
133 TkWindow
*winPtr
; /* Window for event. Gets set to None if
134 * window is deleted while event is being
136 TkEventHandler
*nextHandler
; /* Next handler in search. */
137 struct InProgress
*nextPtr
; /* Next higher nested search. */
140 static InProgress
*pendingPtr
= NULL
;
141 /* Topmost search in progress, or
145 * For each call to Tk_CreateGenericHandler, an instance of the following
146 * structure will be created. All of the active handlers are linked into a
150 typedef struct GenericHandler
{
151 Tk_GenericProc
*proc
; /* Procedure to dispatch on all X events. */
152 ClientData clientData
; /* Client data to pass to procedure. */
153 int deleteFlag
; /* Flag to set when this handler is deleted. */
154 struct GenericHandler
*nextPtr
;
155 /* Next handler in list of all generic
156 * handlers, or NULL for end of list. */
159 static GenericHandler
*genericList
= NULL
;
160 /* First handler in the list, or NULL. */
161 static GenericHandler
*lastGenericPtr
= NULL
;
162 /* Last handler in list. */
165 * There's a potential problem if Tk_HandleEvent is entered recursively.
166 * A handler cannot be deleted physically until we have returned from
167 * calling it. Otherwise, we're looking at unallocated memory in advancing to
168 * its `next' entry. We deal with the problem by using the `delete flag' and
169 * deleting handlers only when it's known that there's no handler active.
171 * The following variable has a non-zero value when a handler is active.
174 static int genericHandlersActive
= 0;
177 * Array of event masks corresponding to each X event:
180 static unsigned long eventMasks
[] = {
183 KeyPressMask
, /* KeyPress */
184 KeyReleaseMask
, /* KeyRelease */
185 ButtonPressMask
, /* ButtonPress */
186 ButtonReleaseMask
, /* ButtonRelease */
187 PointerMotionMask
|PointerMotionHintMask
|ButtonMotionMask
188 |Button1MotionMask
|Button2MotionMask
|Button3MotionMask
189 |Button4MotionMask
|Button5MotionMask
,
191 EnterWindowMask
, /* EnterNotify */
192 LeaveWindowMask
, /* LeaveNotify */
193 FocusChangeMask
, /* FocusIn */
194 FocusChangeMask
, /* FocusOut */
195 KeymapStateMask
, /* KeymapNotify */
196 ExposureMask
, /* Expose */
197 ExposureMask
, /* GraphicsExpose */
198 ExposureMask
, /* NoExpose */
199 VisibilityChangeMask
, /* VisibilityNotify */
200 SubstructureNotifyMask
, /* CreateNotify */
201 StructureNotifyMask
, /* DestroyNotify */
202 StructureNotifyMask
, /* UnmapNotify */
203 StructureNotifyMask
, /* MapNotify */
204 SubstructureRedirectMask
, /* MapRequest */
205 StructureNotifyMask
, /* ReparentNotify */
206 StructureNotifyMask
, /* ConfigureNotify */
207 SubstructureRedirectMask
, /* ConfigureRequest */
208 StructureNotifyMask
, /* GravityNotify */
209 ResizeRedirectMask
, /* ResizeRequest */
210 StructureNotifyMask
, /* CirculateNotify */
211 SubstructureRedirectMask
, /* CirculateRequest */
212 PropertyChangeMask
, /* PropertyNotify */
213 0, /* SelectionClear */
214 0, /* SelectionRequest */
215 0, /* SelectionNotify */
216 ColormapChangeMask
, /* ColormapNotify */
217 0, /* ClientMessage */
218 0, /* Mapping Notify */
222 * If someone has called Tk_RestrictEvents, the information below
226 static Bool (*restrictProc
) _ANSI_ARGS_((Display
*display
, XEvent
*eventPtr
,
227 char *arg
)); /* Procedure to call. NULL means no
228 * restrictProc is currently in effect. */
229 static char *restrictArg
; /* Argument to pass to restrictProc. */
232 * The following array keeps track of the last TK_NEVENTS X events, for
233 * memory dump analysis. The tracing is only done if tkEventDebug is set
237 #define TK_NEVENTS 32
238 static XEvent eventTrace
[TK_NEVENTS
];
239 static int traceIndex
= 0;
240 int tkEventDebug
= 0;
242 int tkCollapseMotion
= 1;
246 #define DefPool(type) \
247 type *Unused##type = NULL; \
249 type *New##type() { \
250 if (Unused##type == NULL) { \
251 return (type *)ckalloc(sizeof (type)); \
253 type *ptr = Unused##type; \
254 Unused##type = ptr->nextPtr; \
259 void Free##type(type *ptr) { \
260 ptr->nextPtr = Unused##type; \
261 Unused##type = ptr; \
264 DefPool(TkEventHandler
)
265 DefPool(GenericHandler
)
272 *--------------------------------------------------------------
274 * Tk_CreateEventHandler --
276 * Arrange for a given procedure to be invoked whenever
277 * events from a given class occur in a given window.
283 * From now on, whenever an event of the type given by
284 * mask occurs for token and is processed by Tk_HandleEvent,
285 * proc will be called. See the manual entry for details
286 * of the calling sequence and return value for proc.
288 *--------------------------------------------------------------
292 Tk_CreateEventHandler(token
, mask
, proc
, clientData
)
293 Tk_Window token
; /* Token for window in which to
295 unsigned long mask
; /* Events for which proc should
297 Tk_EventProc
*proc
; /* Procedure to call for each
299 ClientData clientData
; /* Arbitrary data to pass to proc. */
301 register TkEventHandler
*handlerPtr
;
302 register TkWindow
*winPtr
= (TkWindow
*) token
;
306 * Skim through the list of existing handlers to (a) compute the
307 * overall event mask for the window (so we can pass this new
308 * value to the X system) and (b) see if there's already a handler
309 * declared with the same callback and clientData (if so, just
310 * change the mask). If no existing handler matches, then create
315 if (winPtr
->handlerList
== NULL
) {
316 handlerPtr
= (TkEventHandler
*) NewTkEventHandler();
317 winPtr
->handlerList
= handlerPtr
;
320 for (handlerPtr
= winPtr
->handlerList
; ;
321 handlerPtr
= handlerPtr
->nextPtr
) {
322 if ((handlerPtr
->proc
== proc
)
323 && (handlerPtr
->clientData
== clientData
)) {
324 handlerPtr
->mask
= mask
;
327 if (handlerPtr
->nextPtr
== NULL
) {
334 * Create a new handler if no matching old handler was found.
338 handlerPtr
->nextPtr
= NewTkEventHandler();
339 handlerPtr
= handlerPtr
->nextPtr
;
341 handlerPtr
->mask
= mask
;
342 handlerPtr
->proc
= proc
;
343 handlerPtr
->clientData
= clientData
;
344 handlerPtr
->nextPtr
= NULL
;
348 * No need to call XSelectInput: Tk always selects on all events
349 * for all windows (needed to support bindings on classes and "all").
354 *--------------------------------------------------------------
356 * Tk_DeleteEventHandler --
358 * Delete a previously-created handler.
364 * If there existed a handler as described by the
365 * parameters, the handler is deleted so that proc
366 * will not be invoked again.
368 *--------------------------------------------------------------
372 Tk_DeleteEventHandler(token
, mask
, proc
, clientData
)
373 Tk_Window token
; /* Same as corresponding arguments passed */
374 unsigned long mask
; /* previously to Tk_CreateEventHandler. */
376 ClientData clientData
;
378 register TkEventHandler
*handlerPtr
;
379 register InProgress
*ipPtr
;
380 TkEventHandler
*prevPtr
;
381 register TkWindow
*winPtr
= (TkWindow
*) token
;
384 * Find the event handler to be deleted, or return
385 * immediately if it doesn't exist.
388 for (handlerPtr
= winPtr
->handlerList
, prevPtr
= NULL
; ;
389 prevPtr
= handlerPtr
, handlerPtr
= handlerPtr
->nextPtr
) {
390 if (handlerPtr
== NULL
) {
393 if ((handlerPtr
->mask
== mask
) && (handlerPtr
->proc
== proc
)
394 && (handlerPtr
->clientData
== clientData
)) {
400 * If Tk_HandleEvent is about to process this handler, tell it to
401 * process the next one instead.
404 for (ipPtr
= pendingPtr
; ipPtr
!= NULL
; ipPtr
= ipPtr
->nextPtr
) {
405 if (ipPtr
->nextHandler
== handlerPtr
) {
406 ipPtr
->nextHandler
= handlerPtr
->nextPtr
;
411 * Free resources associated with the handler.
414 if (prevPtr
== NULL
) {
415 winPtr
->handlerList
= handlerPtr
->nextPtr
;
417 prevPtr
->nextPtr
= handlerPtr
->nextPtr
;
419 (void) FreeTkEventHandler(handlerPtr
);
423 * No need to call XSelectInput: Tk always selects on all events
424 * for all windows (needed to support bindings on classes and "all").
428 /*--------------------------------------------------------------
430 * Tk_CreateGenericHandler --
432 * Register a procedure to be called on each X event, regardless
433 * of display or window. Generic handlers are useful for capturing
434 * events that aren't associated with windows, or events for windows
441 * From now on, whenever an X event is given to Tk_HandleEvent,
442 * invoke proc, giving it clientData and the event as arguments.
444 *--------------------------------------------------------------
448 Tk_CreateGenericHandler(proc
, clientData
)
449 Tk_GenericProc
*proc
; /* Procedure to call on every event. */
450 ClientData clientData
; /* One-word value to pass to proc. */
452 GenericHandler
*handlerPtr
;
454 handlerPtr
= NewGenericHandler();
456 handlerPtr
->proc
= proc
;
457 handlerPtr
->clientData
= clientData
;
458 handlerPtr
->deleteFlag
= 0;
459 handlerPtr
->nextPtr
= NULL
;
460 if (genericList
== NULL
) {
461 genericList
= handlerPtr
;
463 lastGenericPtr
->nextPtr
= handlerPtr
;
465 lastGenericPtr
= handlerPtr
;
469 *--------------------------------------------------------------
471 * Tk_DeleteGenericHandler --
473 * Delete a previously-created generic handler.
479 * If there existed a handler as described by the parameters,
480 * that handler is logically deleted so that proc will not be
481 * invoked again. The physical deletion happens in the event
482 * loop in Tk_HandleEvent.
484 *--------------------------------------------------------------
488 Tk_DeleteGenericHandler(proc
, clientData
)
489 Tk_GenericProc
*proc
;
490 ClientData clientData
;
492 GenericHandler
* handler
;
494 for (handler
= genericList
; handler
; handler
= handler
->nextPtr
) {
495 if ((handler
->proc
== proc
) && (handler
->clientData
== clientData
)) {
496 handler
->deleteFlag
= 1;
502 *--------------------------------------------------------------
506 * Given an event, invoke all the handlers that have
507 * been registered for the event.
513 * Depends on the handlers.
515 *--------------------------------------------------------------
519 Tk_HandleEvent(eventPtr
)
520 XEvent
*eventPtr
; /* Event to dispatch. */
522 register TkEventHandler
*handlerPtr
;
523 register GenericHandler
*genericPtr
;
524 register GenericHandler
*genPrevPtr
;
526 register unsigned long mask
;
528 Window handlerWindow
;
531 * First off, invoke all the generic event handlers (those that are
532 * invoked for all events). If a generic event handler reports that
533 * an event is fully processed, go no further.
536 for (genPrevPtr
= NULL
, genericPtr
= genericList
; genericPtr
!= NULL
; ) {
537 if (genericPtr
->deleteFlag
) {
538 if (!genericHandlersActive
) {
539 GenericHandler
*tmpPtr
;
542 * This handler needs to be deleted and there are no
543 * calls pending through the handler, so now is a safe
547 tmpPtr
= genericPtr
->nextPtr
;
548 if (genPrevPtr
== NULL
) {
549 genericList
= tmpPtr
;
551 genPrevPtr
->nextPtr
= tmpPtr
;
553 (void) FreeGenericHandler(genericPtr
);
560 genericHandlersActive
++;
561 done
= (*genericPtr
->proc
)(genericPtr
->clientData
, eventPtr
);
562 genericHandlersActive
--;
567 genPrevPtr
= genericPtr
;
568 genericPtr
= genPrevPtr
->nextPtr
;
572 * Events selected by StructureNotify look the same as those
573 * selected by SubstructureNotify; the only difference is
574 * whether the "event" and "window" fields are the same.
575 * Check it out and convert StructureNotify to
576 * SubstructureNotify if necessary.
579 handlerWindow
= eventPtr
->xany
.window
;
580 mask
= eventMasks
[eventPtr
->xany
.type
];
581 if (mask
== StructureNotifyMask
) {
582 if (eventPtr
->xmap
.event
!= eventPtr
->xmap
.window
) {
583 mask
= SubstructureNotifyMask
;
584 handlerWindow
= eventPtr
->xmap
.event
;
587 if (XFindContext(eventPtr
->xany
.display
, handlerWindow
,
588 tkWindowContext
, (void *) &winPtr
) != 0) {
591 * There isn't a TkWindow structure for this window.
592 * However, if the event is a PropertyNotify event then call
593 * the selection manager (it deals beneath-the-table with
594 * certain properties).
597 if (eventPtr
->type
== PropertyNotify
) {
598 TkSelPropProc(eventPtr
);
604 * Redirect KeyPress and KeyRelease events if input focussing
605 * is happening. Map the x and y coordinates between the two
606 * windows, if possible (make both -1 if the map-from and map-to
607 * windows don't share the same top-level window).
610 if (mask
& (KeyPressMask
|KeyReleaseMask
)) {
611 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xkey
.time
;
613 if (winPtr
->dispPtr
->focusPtr
!= NULL
) {
615 int winX
, winY
, focusX
, focusY
;
617 focusPtr
= winPtr
->dispPtr
->focusPtr
;
618 if ((focusPtr
->display
!= winPtr
->display
)
619 || (focusPtr
->screenNum
!= winPtr
->screenNum
)) {
620 eventPtr
->xkey
.x
= -1;
621 eventPtr
->xkey
.y
= -1;
623 Tk_GetRootCoords((Tk_Window
) winPtr
, &winX
, &winY
);
624 Tk_GetRootCoords((Tk_Window
) focusPtr
, &focusX
, &focusY
);
625 eventPtr
->xkey
.x
-= focusX
- winX
;
626 eventPtr
->xkey
.y
-= focusY
- winY
;
628 eventPtr
->xkey
.window
= focusPtr
->window
;
634 * Call a grab-related procedure to do special processing on
638 if (mask
& (ButtonPressMask
|ButtonReleaseMask
|PointerMotionMask
639 |EnterWindowMask
|LeaveWindowMask
)) {
640 if (mask
& (ButtonPressMask
|ButtonReleaseMask
)) {
641 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xbutton
.time
;
642 } else if (mask
& PointerMotionMask
) {
643 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xmotion
.time
;
645 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xcrossing
.time
;
647 if (TkPointerEvent(eventPtr
, winPtr
) == 0) {
653 * For events where it hasn't already been done, update the current
654 * time in the display.
657 if (eventPtr
->type
== PropertyNotify
) {
658 winPtr
->dispPtr
->lastEventTime
= eventPtr
->xproperty
.time
;
662 * There's a potential interaction here with Tk_DeleteEventHandler.
663 * Read the documentation for pendingPtr.
666 ip
.eventPtr
= eventPtr
;
668 ip
.nextHandler
= NULL
;
669 ip
.nextPtr
= pendingPtr
;
672 if ((eventPtr
->type
== SelectionClear
)
673 || (eventPtr
->type
== SelectionRequest
)
674 || (eventPtr
->type
== SelectionNotify
)) {
675 TkSelEventProc((Tk_Window
) winPtr
, eventPtr
);
676 } else if ((eventPtr
->type
== ClientMessage
)
677 && (eventPtr
->xclient
.message_type
==
678 Tk_InternAtom((Tk_Window
) winPtr
, "WM_PROTOCOLS"))) {
680 * this is a ICCCM WM_PROTOCOL ClientMessage
682 TkWmProtocolEventProc(winPtr
, eventPtr
);
685 for (handlerPtr
= winPtr
->handlerList
; handlerPtr
!= NULL
; ) {
686 if ((handlerPtr
->mask
& mask
) != 0) {
687 ip
.nextHandler
= handlerPtr
->nextPtr
;
688 (*(handlerPtr
->proc
))(handlerPtr
->clientData
, eventPtr
);
689 handlerPtr
= ip
.nextHandler
;
691 handlerPtr
= handlerPtr
->nextPtr
;
696 * Pass the event to the "bind" command mechanism. But, don't
697 * do this for SubstructureNotify events. The "bind" command
698 * doesn't support them anyway, and it's easier to filter out
699 * these events here than in the lower-level procedures.
702 if ((ip
.winPtr
!= None
) && (mask
!= SubstructureNotifyMask
)) {
703 TkBindEventProc(winPtr
, eventPtr
);
706 pendingPtr
= ip
.nextPtr
;
710 *--------------------------------------------------------------
712 * Tk_CreateFileHandler --
714 * Arrange for a given procedure to be invoked whenever
715 * a given file becomes readable or writable.
721 * From now on, whenever the I/O channel given by fd becomes
722 * ready in the way indicated by mask, proc will be invoked.
723 * See the manual entry for details on the calling sequence
724 * to proc. If fd is already registered then the old mask
725 * and proc and clientData values will be replaced with
728 *--------------------------------------------------------------
732 Tk_CreateFileHandler(fd
, mask
, proc
, clientData
)
733 int fd
; /* Integer identifier for stream. */
734 int mask
; /* OR'ed combination of TK_READABLE,
735 * TK_WRITABLE, and TK_EXCEPTION:
736 * indicates conditions under which
737 * proc should be called. */
738 Tk_FileProc
*proc
; /* Procedure to call for each
739 * selected event. NULL means that
740 * this is a display, and that
741 * clientData is the (Display *)
742 * for it, and that events should
743 * be handled automatically. */
744 ClientData clientData
; /* Arbitrary data to pass to proc. */
746 register FileEvent
*filePtr
;
749 if (fd
>= OPEN_MAX
) {
750 panic("Tk_CreatefileHandler can't handle file id %d", fd
);
754 * Make sure the file isn't already registered. Create a
755 * new record in the normal case where there's no existing
759 for (filePtr
= fileList
; filePtr
!= NULL
;
760 filePtr
= filePtr
->nextPtr
) {
761 if (filePtr
->fd
== fd
) {
765 index
= fd
/(8*sizeof(int));
766 if (filePtr
== NULL
) {
767 filePtr
= NewFileEvent();
769 filePtr
->readPtr
= &ready
[index
];
770 filePtr
->writePtr
= &ready
[index
+MASK_SIZE
];
771 filePtr
->exceptPtr
= &ready
[index
+2*MASK_SIZE
];
772 filePtr
->mask
= 1 << (fd
%(8*sizeof(int)));
773 filePtr
->nextPtr
= fileList
;
776 if (masks
[index
] & filePtr
->mask
) {
778 *filePtr
->readPtr
&= ~filePtr
->mask
;
779 masks
[index
] &= ~filePtr
->mask
;
781 if (masks
[index
+MASK_SIZE
] & filePtr
->mask
) {
783 *filePtr
->writePtr
&= ~filePtr
->mask
;
784 masks
[index
+MASK_SIZE
] &= ~filePtr
->mask
;
786 if (masks
[index
+2*MASK_SIZE
] & filePtr
->mask
) {
788 *filePtr
->exceptPtr
&= ~filePtr
->mask
;
789 masks
[index
+2*MASK_SIZE
] &= ~filePtr
->mask
;
794 * The remainder of the initialization below is done
795 * regardless of whether or not this is a new record
796 * or a modification of an old one.
799 if (mask
& TK_READABLE
) {
800 masks
[index
] |= filePtr
->mask
;
803 readPtr
= (readCount
== 0 ? NULL
: &ready
[0]);
805 if (mask
& TK_WRITABLE
) {
806 masks
[index
+MASK_SIZE
] |= filePtr
->mask
;
809 writePtr
= (writeCount
== 0 ? NULL
: &ready
[MASK_SIZE
]);
811 if (mask
& TK_EXCEPTION
) {
812 masks
[index
+2*MASK_SIZE
] |= filePtr
->mask
;
815 exceptPtr
= (exceptCount
== 0 ? NULL
: &ready
[2*MASK_SIZE
]);
817 filePtr
->proc
= proc
;
818 filePtr
->clientData
= clientData
;
826 *--------------------------------------------------------------
828 * Tk_DeleteFileHandler --
830 * Cancel a previously-arranged callback arrangement for
837 * If a callback was previously registered on fd, remove it.
839 *--------------------------------------------------------------
843 Tk_DeleteFileHandler(fd
)
844 int fd
; /* Stream id for which to remove
845 * callback procedure. */
847 register FileEvent
*filePtr
;
852 * Find the entry for the given file (and return if there
856 for (prevPtr
= NULL
, filePtr
= fileList
; ;
857 prevPtr
= filePtr
, filePtr
= filePtr
->nextPtr
) {
858 if (filePtr
== NULL
) {
861 if (filePtr
->fd
== fd
) {
867 * Clean up information in the callback record.
870 index
= filePtr
->fd
/(8*sizeof(int));
871 if (masks
[index
] & filePtr
->mask
) {
873 *filePtr
->readPtr
&= ~filePtr
->mask
;
874 masks
[index
] &= ~filePtr
->mask
;
876 if (masks
[index
+MASK_SIZE
] & filePtr
->mask
) {
878 *filePtr
->writePtr
&= ~filePtr
->mask
;
879 masks
[index
+MASK_SIZE
] &= ~filePtr
->mask
;
881 if (masks
[index
+2*MASK_SIZE
] & filePtr
->mask
) {
883 *filePtr
->exceptPtr
&= ~filePtr
->mask
;
884 masks
[index
+2*MASK_SIZE
] &= ~filePtr
->mask
;
886 if (prevPtr
== NULL
) {
887 fileList
= filePtr
->nextPtr
;
889 prevPtr
->nextPtr
= filePtr
->nextPtr
;
891 FreeFileEvent(filePtr
);
898 for (filePtr
= fileList
; filePtr
!= NULL
;
899 filePtr
= filePtr
->nextPtr
) {
900 if (numFds
<= filePtr
->fd
) {
901 numFds
= filePtr
->fd
+1;
907 *--------------------------------------------------------------
909 * Tk_CreateTimerHandler --
911 * Arrange for a given procedure to be invoked at a particular
912 * time in the future.
915 * The return value is a token for the timer event, which
916 * may be used to delete the event before it fires.
919 * When milliseconds have elapsed, proc will be invoked
922 *--------------------------------------------------------------
926 Tk_CreateTimerHandler(milliseconds
, proc
, clientData
)
927 int milliseconds
; /* How many milliseconds to wait
928 * before invoking proc. */
929 Tk_TimerProc
*proc
; /* Procedure to invoke. */
930 ClientData clientData
; /* Arbitrary data to pass to proc. */
932 register TimerEvent
*timerPtr
, *tPtr2
, *prevPtr
;
935 timerPtr
= NewTimerEvent();
938 * Compute when the event should fire.
941 (void) gettimeofday(&timerPtr
->time
, (struct timezone
*) NULL
);
942 timerPtr
->time
.tv_sec
+= milliseconds
/1000;
943 timerPtr
->time
.tv_usec
+= (milliseconds
%1000)*1000;
944 if (timerPtr
->time
.tv_usec
> 1000000) {
945 timerPtr
->time
.tv_usec
-= 1000000;
946 timerPtr
->time
.tv_sec
+= 1;
950 * Fill in other fields for the event.
953 timerPtr
->proc
= proc
;
954 timerPtr
->clientData
= clientData
;
956 timerPtr
->token
= (Tk_TimerToken
) id
;
959 * Add the event to the queue in the correct position
960 * (ordered by event firing time).
963 for (tPtr2
= timerQueue
, prevPtr
= NULL
; tPtr2
!= NULL
;
964 prevPtr
= tPtr2
, tPtr2
= tPtr2
->nextPtr
) {
965 if ((tPtr2
->time
.tv_sec
> timerPtr
->time
.tv_sec
)
966 || ((tPtr2
->time
.tv_sec
== timerPtr
->time
.tv_sec
)
967 && (tPtr2
->time
.tv_usec
> timerPtr
->time
.tv_usec
))) {
971 if (prevPtr
== NULL
) {
972 timerPtr
->nextPtr
= timerQueue
;
973 timerQueue
= timerPtr
;
975 timerPtr
->nextPtr
= prevPtr
->nextPtr
;
976 prevPtr
->nextPtr
= timerPtr
;
978 return timerPtr
->token
;
981 // Added by Don to support finer timer resolution.
983 *--------------------------------------------------------------
985 * Tk_CreateMicroTimerHandler --
987 * Arrange for a given procedure to be invoked at a particular
988 * time in the future.
991 * The return value is a token for the timer event, which
992 * may be used to delete the event before it fires.
995 * When seconds and seconds have elapsed, proc will be invoked
998 *--------------------------------------------------------------
1002 Tk_CreateMicroTimerHandler(seconds
, microseconds
, proc
, clientData
)
1003 int seconds
; /* How many seconds to wait
1004 * before invoking proc. */
1005 int microseconds
; /* How many microseconds to wait
1006 * before invoking proc. */
1007 Tk_TimerProc
*proc
; /* Procedure to invoke. */
1008 ClientData clientData
; /* Arbitrary data to pass to proc. */
1010 register TimerEvent
*timerPtr
, *tPtr2
, *prevPtr
;
1013 timerPtr
= NewTimerEvent();
1016 * Compute when the event should fire.
1019 (void) gettimeofday(&timerPtr
->time
, (struct timezone
*) NULL
);
1020 timerPtr
->time
.tv_sec
+= seconds
;
1021 timerPtr
->time
.tv_usec
+= microseconds
;
1022 while (timerPtr
->time
.tv_usec
> 1000000) {
1023 timerPtr
->time
.tv_usec
-= 1000000;
1024 timerPtr
->time
.tv_sec
+= 1;
1028 * Fill in other fields for the event.
1031 timerPtr
->proc
= proc
;
1032 timerPtr
->clientData
= clientData
;
1034 timerPtr
->token
= (Tk_TimerToken
) id
;
1037 * Add the event to the queue in the correct position
1038 * (ordered by event firing time).
1041 for (tPtr2
= timerQueue
, prevPtr
= NULL
; tPtr2
!= NULL
;
1042 prevPtr
= tPtr2
, tPtr2
= tPtr2
->nextPtr
) {
1043 if ((tPtr2
->time
.tv_sec
> timerPtr
->time
.tv_sec
)
1044 || ((tPtr2
->time
.tv_sec
== timerPtr
->time
.tv_sec
)
1045 && (tPtr2
->time
.tv_usec
> timerPtr
->time
.tv_usec
))) {
1049 if (prevPtr
== NULL
) {
1050 timerPtr
->nextPtr
= timerQueue
;
1051 timerQueue
= timerPtr
;
1053 timerPtr
->nextPtr
= prevPtr
->nextPtr
;
1054 prevPtr
->nextPtr
= timerPtr
;
1056 return timerPtr
->token
;
1061 *--------------------------------------------------------------
1063 * Tk_DeleteTimerHandler --
1065 * Delete a previously-registered timer handler.
1071 * Destroy the timer callback identified by TimerToken,
1072 * so that its associated procedure will not be called.
1073 * If the callback has already fired, or if the given
1074 * token doesn't exist, then nothing happens.
1076 *--------------------------------------------------------------
1080 Tk_DeleteTimerHandler(token
)
1081 Tk_TimerToken token
; /* Result previously returned by
1082 * Tk_DeleteTimerHandler. */
1084 register TimerEvent
*timerPtr
, *prevPtr
;
1086 if (token
== 0) return;
1088 for (timerPtr
= timerQueue
, prevPtr
= NULL
; timerPtr
!= NULL
;
1089 prevPtr
= timerPtr
, timerPtr
= timerPtr
->nextPtr
) {
1090 if (timerPtr
->token
!= token
) {
1093 if (prevPtr
== NULL
) {
1094 timerQueue
= timerPtr
->nextPtr
;
1096 prevPtr
->nextPtr
= timerPtr
->nextPtr
;
1098 FreeTimerEvent(timerPtr
);
1102 // fprintf(stderr, "Tk_DeleteTimerHandler called on bogus timer %d\n", token);
1106 *--------------------------------------------------------------
1110 * Arrange for proc to be invoked the next time the
1111 * system is idle (i.e., just before the next time
1112 * that Tk_DoOneEvent would have to wait for something
1119 * Proc will eventually be called, with clientData
1120 * as argument. See the manual entry for details.
1122 *--------------------------------------------------------------
1126 Tk_DoWhenIdle(proc
, clientData
)
1127 Tk_IdleProc
*proc
; /* Procedure to invoke. */
1128 ClientData clientData
; /* Arbitrary value to pass to proc. */
1130 register IdleHandler
*idlePtr
;
1132 idlePtr
= NewIdleHandler();
1133 idlePtr
->proc
= proc
;
1134 idlePtr
->clientData
= clientData
;
1135 idlePtr
->nextPtr
= NULL
;
1136 if (lastIdlePtr
== NULL
) {
1139 lastIdlePtr
->nextPtr
= idlePtr
;
1141 lastIdlePtr
= idlePtr
;
1145 *----------------------------------------------------------------------
1147 * Tk_CancelIdleCall --
1149 * If there are any when-idle calls requested to a given procedure
1150 * with given clientData, cancel all of them.
1156 * If the proc/clientData combination were on the when-idle list,
1157 * they are removed so that they will never be called.
1159 *----------------------------------------------------------------------
1163 Tk_CancelIdleCall(proc
, clientData
)
1164 Tk_IdleProc
*proc
; /* Procedure that was previously registered. */
1165 ClientData clientData
; /* Arbitrary value to pass to proc. */
1167 register IdleHandler
*idlePtr
, *prevPtr
;
1168 IdleHandler
*nextPtr
;
1170 for (prevPtr
= NULL
, idlePtr
= idleList
; idlePtr
!= NULL
;
1171 prevPtr
= idlePtr
, idlePtr
= idlePtr
->nextPtr
) {
1172 while ((idlePtr
->proc
== proc
)
1173 && (idlePtr
->clientData
== clientData
)) {
1174 nextPtr
= idlePtr
->nextPtr
;
1175 FreeIdleHandler(idlePtr
);
1177 if (prevPtr
== NULL
) {
1180 prevPtr
->nextPtr
= idlePtr
;
1182 if (idlePtr
== NULL
) {
1183 lastIdlePtr
= prevPtr
;
1191 *--------------------------------------------------------------
1195 * Process a single event of some sort. If there's no
1196 * work to do, wait for an event to occur, then process
1200 * The return value is 1 if the procedure actually found
1201 * an event to process. If no event was found then 0 is
1205 * May delay execution of process while waiting for an
1206 * X event, X error, file-ready event, or timer event.
1207 * The handling of the event could cause additional
1208 * side effects. Collapses sequences of mouse-motion
1209 * events for the same window into a single event by
1210 * delaying motion event processing.
1212 *--------------------------------------------------------------
1216 Tk_DoOneEvent(flags
)
1217 int flags
; /* Miscellaneous flag values: may be any
1218 * combination of TK_DONT_WAIT, TK_X_EVENTS,
1219 * TK_FILE_EVENTS, TK_TIMER_EVENTS, and
1220 * TK_IDLE_EVENTS. */
1222 register FileEvent
*filePtr
;
1223 struct timeval curTime
, timeout
, *timeoutPtr
;
1225 static XEvent delayedMotionEvent
; /* Used to hold motion events that
1226 * are being saved until later. */
1227 static int eventDelayed
= 0; /* Non-zero means there is an event
1228 * in delayedMotionEvent. */
1230 if ((flags
& TK_ALL_EVENTS
) == 0) {
1231 flags
|= TK_ALL_EVENTS
;
1235 * Phase One: see if there's already something ready
1236 * (either a file or a display) that was left over
1237 * from before (i.e don't do a select, just check the
1238 * bits from the last select).
1242 for (filePtr
= fileList
; filePtr
!= NULL
;
1243 filePtr
= filePtr
->nextPtr
) {
1247 * Displays: flush output, check for queued events,
1248 * and read events from the server if display is ready.
1249 * If there are any events, process one and then
1253 if ((filePtr
->proc
== NULL
) && (flags
& TK_X_EVENTS
)) {
1254 Display
*display
= (Display
*) filePtr
->clientData
;
1258 if ((*filePtr
->readPtr
) & filePtr
->mask
) {
1259 *filePtr
->readPtr
&= ~filePtr
->mask
;
1260 if (XEventsQueued(display
, QueuedAfterReading
) == 0) {
1263 * Things are very tricky if there aren't any events
1264 * readable at this point (after all, there was
1265 * supposedly data available on the connection).
1266 * A couple of things could have occurred:
1268 * One possibility is that there were only error events
1269 * in the input from the server. If this happens,
1270 * we should return (we don't want to go to sleep
1271 * in XNextEvent below, since this would block out
1272 * other sources of input to the process).
1274 * Another possibility is that our connection to the
1275 * server has been closed. This will not necessarily
1276 * be detected in XEventsQueued (!!), so if we just
1277 * return then there will be an infinite loop. To
1278 * detect such an error, generate a NoOp protocol
1279 * request to exercise the connection to the server,
1280 * then return. However, must disable SIGPIPE while
1281 * sending the event, or else the process will die
1282 * from the signal and won't invoke the X error
1283 * function to print a nice message.
1286 void (*oldHandler
)();
1288 oldHandler
= (void (*)()) signal(SIGPIPE
, SIG_IGN
);
1291 (void) signal(SIGPIPE
, oldHandler
);
1294 if (restrictProc
!= NULL
) {
1295 if (!XCheckIfEvent(display
, &event
, restrictProc
,
1300 XNextEvent(display
, &event
);
1303 if (QLength(display
) == 0) {
1306 if (restrictProc
!= NULL
) {
1307 if (!XCheckIfEvent(display
, &event
, restrictProc
,
1312 XNextEvent(display
, &event
);
1317 * Got an event. Deal with mouse-motion-collapsing and
1318 * event-delaying here. If there's already an event delayed,
1319 * then process that event if it's incompatible with the new
1320 * event (new event not mouse motion, or window changed, or
1321 * state changed). If the new event is mouse motion, then
1322 * don't process it now; delay it until later in the hopes
1323 * that it can be merged with other mouse motion events
1324 * immediately following.
1328 eventTrace
[traceIndex
] = event
;
1329 traceIndex
= (traceIndex
+1) % TK_NEVENTS
;
1333 if (((event
.type
!= MotionNotify
)
1334 && (event
.type
!= GraphicsExpose
)
1335 && (event
.type
!= NoExpose
)
1336 && (event
.type
!= Expose
))
1337 || (event
.xmotion
.display
1338 != delayedMotionEvent
.xmotion
.display
)
1339 || (event
.xmotion
.window
1340 != delayedMotionEvent
.xmotion
.window
)) {
1344 * Must copy the event out of delayedMotionEvent before
1345 * processing it, in order to allow recursive calls to
1346 * Tk_DoOneEvent as part of the handler.
1349 copy
= delayedMotionEvent
;
1351 Tk_HandleEvent(©
);
1354 if (tkCollapseMotion
&& event
.type
== MotionNotify
) {
1355 delayedMotionEvent
= event
;
1358 Tk_HandleEvent(&event
);
1364 * Not a display: if the file is ready, call the
1365 * appropriate handler.
1368 if (((*filePtr
->readPtr
| *filePtr
->writePtr
1369 | *filePtr
->exceptPtr
) & filePtr
->mask
) == 0) {
1372 if (!(flags
& TK_FILE_EVENTS
)) {
1376 if (*filePtr
->readPtr
& filePtr
->mask
) {
1377 mask
|= TK_READABLE
;
1378 *filePtr
->readPtr
&= ~filePtr
->mask
;
1380 if (*filePtr
->writePtr
& filePtr
->mask
) {
1381 mask
|= TK_WRITABLE
;
1382 *filePtr
->writePtr
&= ~filePtr
->mask
;
1384 if (*filePtr
->exceptPtr
& filePtr
->mask
) {
1385 mask
|= TK_EXCEPTION
;
1386 *filePtr
->exceptPtr
&= ~filePtr
->mask
;
1388 (*filePtr
->proc
)(filePtr
->clientData
, mask
);
1393 * Phase Two: get the current time and see if any timer
1394 * events are ready to fire. If so, fire one and return.
1398 if ((timerQueue
!= NULL
) && (flags
& TK_TIMER_EVENTS
)) {
1399 register TimerEvent
*timerPtr
= timerQueue
;
1401 (void) gettimeofday(&curTime
, (struct timezone
*) NULL
);
1402 if ((timerPtr
->time
.tv_sec
< curTime
.tv_sec
)
1403 || ((timerPtr
->time
.tv_sec
== curTime
.tv_sec
)
1404 && (timerPtr
->time
.tv_usec
< curTime
.tv_usec
))) {
1405 timerQueue
= timerPtr
->nextPtr
;
1406 (*timerPtr
->proc
)(timerPtr
->clientData
);
1407 FreeTimerEvent(timerPtr
);
1414 * Phase Three: if there is a delayed motion event, process it
1415 * now, before any DoWhenIdle handlers. Better to process before
1416 * idle handlers than after, because the goal of idle handlers is
1417 * to delay until after all pending events have been processed.
1418 * Must free up delayedMotionEvent *before* calling Tk_HandleEvent,
1419 * so that the event handler can call Tk_DoOneEvent recursively
1420 * without infinite looping.
1423 if ((eventDelayed
) && (flags
& TK_X_EVENTS
)) {
1426 copy
= delayedMotionEvent
;
1428 Tk_HandleEvent(©
);
1433 * Phase Four: if there are DoWhenIdle requests pending (or
1434 * if we're not allowed to block), then do a select with an
1435 * instantaneous timeout. If a ready file is found, then go
1436 * back to process it.
1439 if (((idleList
!= NULL
) && (flags
& TK_IDLE_EVENTS
))
1440 || (flags
& TK_DONT_WAIT
)) {
1441 if (flags
& (TK_X_EVENTS
|TK_FILE_EVENTS
)) {
1442 memcpy((VOID
*) ready
, (VOID
*) masks
, 3*MASK_SIZE
*sizeof(int));
1443 timeout
.tv_sec
= timeout
.tv_usec
= 0;
1445 numFound
= select(numFds
, (SELECT_MASK
*) readPtr
,
1446 (SELECT_MASK
*) writePtr
, (SELECT_MASK
*) exceptPtr
,
1448 } while ((numFound
== -1) && (errno
== EINTR
));
1456 * Phase Five: process all pending DoWhenIdle requests.
1459 if ((idleList
!= NULL
) && (flags
& TK_IDLE_EVENTS
)) {
1460 register IdleHandler
*idlePtr
;
1463 * If you change the code below, be aware that new handlers
1464 * can get added to the list while the current one is being
1467 * NOTE! Must remove the entry from the list before calling
1468 * it, in case the idle handler calls Tk_DoOneEvent: don't
1469 * want to loop infinitely. Must also be careful because
1470 * Tk_CancelIdleCall could change the list during the call.
1473 while (idleList
!= NULL
) {
1475 idleList
= idlePtr
->nextPtr
;
1476 if (idleList
== NULL
) {
1479 (*idlePtr
->proc
)(idlePtr
->clientData
);
1480 FreeIdleHandler(idlePtr
);
1486 * Phase Six: do a select to wait for either one of the
1487 * files to become ready or for the first timer event to
1488 * fire. Then go back to process the event.
1491 if ((flags
& TK_DONT_WAIT
)
1492 || !(flags
& (TK_TIMER_EVENTS
|TK_FILE_EVENTS
|TK_X_EVENTS
))) {
1495 if ((timerQueue
== NULL
) || !(flags
& TK_TIMER_EVENTS
)) {
1498 timeoutPtr
= &timeout
;
1499 timeout
.tv_sec
= timerQueue
->time
.tv_sec
- curTime
.tv_sec
;
1500 timeout
.tv_usec
= timerQueue
->time
.tv_usec
- curTime
.tv_usec
;
1501 if (timeout
.tv_usec
< 0) {
1502 timeout
.tv_sec
-= 1;
1503 timeout
.tv_usec
+= 1000000;
1506 memcpy((VOID
*) ready
, (VOID
*) masks
, 3*MASK_SIZE
*sizeof(int));
1508 numFound
= select(numFds
, (SELECT_MASK
*) readPtr
,
1509 (SELECT_MASK
*) writePtr
, (SELECT_MASK
*) exceptPtr
,
1511 } while ((numFound
== -1) && (errno
== EINTR
));
1512 if (numFound
== 0) {
1519 *--------------------------------------------------------------
1523 * Call Tk_DoOneEvent over and over again in an infinite
1524 * loop as long as there exist any main windows.
1530 * Arbitrary; depends on handlers for events.
1532 *--------------------------------------------------------------
1538 while (!tkMustExit
&&
1539 tk_NumMainWindows
> 0) {
1545 *----------------------------------------------------------------------
1549 * Delay execution for the specified number of milliseconds.
1557 *----------------------------------------------------------------------
1562 int ms
; /* Number of milliseconds to sleep. */
1564 static struct timeval delay
;
1566 delay
.tv_sec
= ms
/1000;
1567 delay
.tv_usec
= (ms
%1000)*1000;
1568 (void) select(0, (SELECT_MASK
*) 0, (SELECT_MASK
*) 0,
1569 (SELECT_MASK
*) 0, &delay
);
1573 *----------------------------------------------------------------------
1575 * Tk_RestrictEvents --
1577 * This procedure is used to globally restrict the set of events
1578 * that will be dispatched. The restriction is done by filtering
1579 * all incoming X events through a procedure that determines
1580 * whether they are to be processed immediately or deferred.
1583 * The return value is the previous restriction procedure in effect,
1584 * if there was one, or NULL if there wasn't.
1587 * From now on, proc will be called to determine whether to process
1588 * or defer each incoming X event.
1590 *----------------------------------------------------------------------
1594 Tk_RestrictEvents(proc
, arg
, prevArgPtr
)
1595 Tk_RestrictProc
*proc
; /* X "if" procedure to call for each
1596 * incoming event. See "XIfEvent" doc.
1598 char *arg
; /* Arbitrary argument to pass to proc. */
1599 char **prevArgPtr
; /* Place to store information about previous
1602 Bool (*prev
) _ANSI_ARGS_((Display
*display
, XEvent
*eventPtr
, char *arg
));
1604 prev
= restrictProc
;
1605 *prevArgPtr
= restrictArg
;
1606 restrictProc
= proc
;
1612 *--------------------------------------------------------------
1614 * Tk_CreateFocusHandler --
1616 * Arrange for a procedure to be called whenever the focus
1617 * enters or leaves a given window.
1623 * After this procedure has been invoked, whenever tkwin gets
1624 * or loses the input focus, proc will be called. It should have
1625 * the following structure:
1628 * proc(clientData, gotFocus)
1629 * ClientData clientData;
1634 * The clientData argument to "proc" will be the same as the
1635 * clientData argument to this procedure. GotFocus will be
1636 * 1 if tkwin is getting the focus, and 0 if it's losing the
1639 *--------------------------------------------------------------
1643 Tk_CreateFocusHandler(tkwin
, proc
, clientData
)
1644 Tk_Window tkwin
; /* Token for window. */
1645 Tk_FocusProc
*proc
; /* Procedure to call when tkwin gets
1646 * or loses the input focus. */
1647 ClientData clientData
; /* Arbitrary value to pass to proc. */
1649 register TkWindow
*winPtr
= (TkWindow
*) tkwin
;
1651 winPtr
->focusProc
= proc
;
1652 winPtr
->focusData
= clientData
;
1656 *--------------------------------------------------------------
1660 * This procedure is invoked to process the "focus" Tcl command.
1661 * See the user documentation for details on what it does.
1664 * A standard Tcl result.
1667 * See the user documentation.
1669 *--------------------------------------------------------------
1673 Tk_FocusCmd(clientData
, interp
, argc
, argv
)
1674 ClientData clientData
; /* Main window associated with
1676 Tcl_Interp
*interp
; /* Current interpreter. */
1677 int argc
; /* Number of arguments. */
1678 char **argv
; /* Argument strings. */
1680 Tk_Window tkwin
= (Tk_Window
) clientData
;
1681 register TkWindow
*winPtr
= (TkWindow
*) clientData
;
1682 register TkWindow
*newPtr
;
1686 Tcl_AppendResult(interp
, "too many args: should be \"",
1687 argv
[0], " ?-query? ?window?\"", (char *) NULL
);
1692 if (winPtr
->dispPtr
->focusPtr
== NULL
) {
1693 interp
->result
= "none";
1695 interp
->result
= winPtr
->dispPtr
->focusPtr
->pathName
;
1700 if (argv
[1][0] == '-') {
1703 switchLength
= strlen(argv
[1]);
1704 if ((switchLength
>= 2)
1705 && (strncmp(argv
[1], "-query", switchLength
) == 0)) {
1711 newPtr
= (TkWindow
*) Tk_NameToWindow(interp
, argv
[2], tkwin
);
1712 if (newPtr
== NULL
) {
1715 if (newPtr
->dispPtr
->focusPtr
== NULL
) {
1716 interp
->result
= "none";
1718 interp
->result
= newPtr
->dispPtr
->focusPtr
->pathName
;
1728 if (strcmp(argv
[1], "none") == 0) {
1731 newPtr
= (TkWindow
*) Tk_NameToWindow(interp
, argv
[1], tkwin
);
1732 if (newPtr
== NULL
) {
1736 /* XXX: mumble frotz */
1737 /* if (newPtr->dispPtr->focusPtr == newPtr) { */
1738 if ((!newPtr
) || (newPtr
->dispPtr
->focusPtr
== newPtr
)) {
1741 if (winPtr
== newPtr
->dispPtr
->mouseMainPtr
) { /* XXX: ??? presumably */
1742 if ((newPtr
->dispPtr
->focusPtr
!= NULL
)
1743 && (newPtr
->dispPtr
->focusPtr
->focusProc
!= NULL
)) {
1744 (*newPtr
->dispPtr
->focusPtr
->focusProc
)(
1745 newPtr
->dispPtr
->focusPtr
->focusData
, 0);
1747 newPtr
->dispPtr
->focusPtr
= newPtr
;
1748 if ((newPtr
!= NULL
) && (newPtr
->focusProc
!= NULL
)) {
1749 (*newPtr
->focusProc
)(newPtr
->focusData
, 1);
1752 newPtr
->dispPtr
->focusPtr
= newPtr
;
1758 *--------------------------------------------------------------
1760 * TkFocusEventProc --
1762 * This procedure is invoked whenever the pointer enters
1763 * or leaves a top-level window. It notifies the current
1764 * owner of the focus, if any.
1772 *--------------------------------------------------------------
1776 TkFocusEventProc(winPtr
, eventPtr
)
1777 register TkWindow
*winPtr
; /* Top-level window just entered or left. */
1778 XEvent
*eventPtr
; /* EnterWindow or LeaveWindow event. */
1780 register TkWindow
*focusPtr
;
1781 TkWindow
*newMouseMainPtr
= NULL
;
1783 if (eventPtr
->type
== EnterNotify
) {
1784 newMouseMainPtr
= winPtr
->mainPtr
->winPtr
;
1786 if (winPtr
->dispPtr
->mouseMainPtr
== newMouseMainPtr
) {
1789 if (winPtr
->dispPtr
->mouseMainPtr
!= NULL
) {
1790 focusPtr
= winPtr
->dispPtr
->focusPtr
;
1791 if ((focusPtr
!= NULL
)
1792 && (focusPtr
->focusProc
!= NULL
)) {
1793 (*focusPtr
->focusProc
)(focusPtr
->focusData
, 0);
1796 winPtr
->dispPtr
->mouseMainPtr
= newMouseMainPtr
;
1797 if (newMouseMainPtr
!= NULL
) {
1798 focusPtr
= newMouseMainPtr
->dispPtr
->focusPtr
;
1799 if ((focusPtr
!= NULL
)
1800 && (focusPtr
->focusProc
!= NULL
)) {
1801 (*focusPtr
->focusProc
)(focusPtr
->focusData
, 1);
1807 *--------------------------------------------------------------
1809 * TkEventDeadWindow --
1811 * This procedure is invoked when it is determined that
1812 * a window is dead. It cleans up event-related information
1819 * Various things get cleaned up and recycled.
1821 *--------------------------------------------------------------
1825 TkEventDeadWindow(winPtr
)
1826 TkWindow
*winPtr
; /* Information about the window
1827 * that is being deleted. */
1829 register TkEventHandler
*handlerPtr
;
1830 register InProgress
*ipPtr
;
1833 * While deleting all the handlers, be careful to check for
1834 * Tk_HandleEvent being about to process one of the deleted
1835 * handlers. If it is, tell it to quit (all of the handlers
1836 * are being deleted).
1839 while (winPtr
->handlerList
!= NULL
) {
1840 handlerPtr
= winPtr
->handlerList
;
1841 winPtr
->handlerList
= handlerPtr
->nextPtr
;
1842 for (ipPtr
= pendingPtr
; ipPtr
!= NULL
; ipPtr
= ipPtr
->nextPtr
) {
1843 if (ipPtr
->nextHandler
== handlerPtr
) {
1844 ipPtr
->nextHandler
= NULL
;
1846 if (ipPtr
->winPtr
== winPtr
) {
1847 ipPtr
->winPtr
= None
;
1850 ckfree((char *) handlerPtr
);
1852 if ((winPtr
->dispPtr
!= NULL
) && (winPtr
->dispPtr
->focusPtr
== winPtr
)) {
1853 winPtr
->dispPtr
->focusPtr
= NULL
;
1858 *----------------------------------------------------------------------
1862 * Try to deduce the current time. "Current time" means the time
1863 * of the event that led to the current code being executed, which
1864 * means the time in the most recently-nested invocation of
1868 * The return value is the time from the current event, or
1869 * CurrentTime if there is no current event or if the current
1870 * event contains no time.
1875 *----------------------------------------------------------------------
1879 TkCurrentTime(dispPtr
)
1880 TkDisplay
*dispPtr
; /* Display for which the time is desired. */
1882 register XEvent
*eventPtr
;
1884 if (pendingPtr
== NULL
) {
1885 return dispPtr
->lastEventTime
;
1887 eventPtr
= pendingPtr
->eventPtr
;
1888 switch (eventPtr
->type
) {
1891 return eventPtr
->xbutton
.time
;
1894 return eventPtr
->xkey
.time
;
1896 return eventPtr
->xmotion
.time
;
1899 return eventPtr
->xcrossing
.time
;
1900 case PropertyNotify
:
1901 return eventPtr
->xproperty
.time
;
1903 return dispPtr
->lastEventTime
;