1/* 2 * tkEvent.c -- 3 * 4 * This file provides basic low-level facilities for managing 5 * X events in Tk. 6 * 7 * Copyright (c) 1990-1994 The Regents of the University of California. 8 * Copyright (c) 1994-1995 Sun Microsystems, Inc. 9 * Copyright (c) 1998-2000 Ajuba Solutions. 10 * 11 * See the file "license.terms" for information on usage and redistribution 12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 * 14 * RCS: @(#) $Id: tkEvent.c,v 1.17.2.8 2006/01/20 18:42:04 jenglish Exp $ 15 */ 16 17#include "tkPort.h" 18#include "tkInt.h" 19#include <signal.h> 20 21/* 22 * There's a potential problem if a handler is deleted while it's 23 * current (i.e. its procedure is executing), since Tk_HandleEvent 24 * will need to read the handler's "nextPtr" field when the procedure 25 * returns. To handle this problem, structures of the type below 26 * indicate the next handler to be processed for any (recursively 27 * nested) dispatches in progress. The nextHandler fields get 28 * updated if the handlers pointed to are deleted. Tk_HandleEvent 29 * also needs to know if the entire window gets deleted; the winPtr 30 * field is set to zero if that particular window gets deleted. 31 */ 32 33typedef struct InProgress { 34 XEvent *eventPtr; /* Event currently being handled. */ 35 TkWindow *winPtr; /* Window for event. Gets set to None if 36 * window is deleted while event is being 37 * handled. */ 38 TkEventHandler *nextHandler; /* Next handler in search. */ 39 struct InProgress *nextPtr; /* Next higher nested search. */ 40} InProgress; 41 42/* 43 * For each call to Tk_CreateGenericHandler, an instance of the following 44 * structure will be created. All of the active handlers are linked into a 45 * list. 46 */ 47 48typedef struct GenericHandler { 49 Tk_GenericProc *proc; /* Procedure to dispatch on all X events. */ 50 ClientData clientData; /* Client data to pass to procedure. */ 51 int deleteFlag; /* Flag to set when this handler is deleted. */ 52 struct GenericHandler *nextPtr; 53 /* Next handler in list of all generic 54 * handlers, or NULL for end of list. */ 55} GenericHandler; 56 57/* 58 * There's a potential problem if Tk_HandleEvent is entered recursively. 59 * A handler cannot be deleted physically until we have returned from 60 * calling it. Otherwise, we're looking at unallocated memory in advancing to 61 * its `next' entry. We deal with the problem by using the `delete flag' and 62 * deleting handlers only when it's known that there's no handler active. 63 * 64 */ 65 66/* 67 * The following structure is used for queueing X-style events on the 68 * Tcl event queue. 69 */ 70 71typedef struct TkWindowEvent { 72 Tcl_Event header; /* Standard information for all events. */ 73 XEvent event; /* The X event. */ 74} TkWindowEvent; 75 76/* 77 * Array of event masks corresponding to each X event: 78 */ 79 80static unsigned long eventMasks[TK_LASTEVENT] = { 81 0, 82 0, 83 KeyPressMask, /* KeyPress */ 84 KeyReleaseMask, /* KeyRelease */ 85 ButtonPressMask, /* ButtonPress */ 86 ButtonReleaseMask, /* ButtonRelease */ 87 PointerMotionMask|PointerMotionHintMask|ButtonMotionMask 88 |Button1MotionMask|Button2MotionMask|Button3MotionMask 89 |Button4MotionMask|Button5MotionMask, 90 /* MotionNotify */ 91 EnterWindowMask, /* EnterNotify */ 92 LeaveWindowMask, /* LeaveNotify */ 93 FocusChangeMask, /* FocusIn */ 94 FocusChangeMask, /* FocusOut */ 95 KeymapStateMask, /* KeymapNotify */ 96 ExposureMask, /* Expose */ 97 ExposureMask, /* GraphicsExpose */ 98 ExposureMask, /* NoExpose */ 99 VisibilityChangeMask, /* VisibilityNotify */ 100 SubstructureNotifyMask, /* CreateNotify */ 101 StructureNotifyMask, /* DestroyNotify */ 102 StructureNotifyMask, /* UnmapNotify */ 103 StructureNotifyMask, /* MapNotify */ 104 SubstructureRedirectMask, /* MapRequest */ 105 StructureNotifyMask, /* ReparentNotify */ 106 StructureNotifyMask, /* ConfigureNotify */ 107 SubstructureRedirectMask, /* ConfigureRequest */ 108 StructureNotifyMask, /* GravityNotify */ 109 ResizeRedirectMask, /* ResizeRequest */ 110 StructureNotifyMask, /* CirculateNotify */ 111 SubstructureRedirectMask, /* CirculateRequest */ 112 PropertyChangeMask, /* PropertyNotify */ 113 0, /* SelectionClear */ 114 0, /* SelectionRequest */ 115 0, /* SelectionNotify */ 116 ColormapChangeMask, /* ColormapNotify */ 117 0, /* ClientMessage */ 118 0, /* Mapping Notify */ 119 VirtualEventMask, /* VirtualEvents */ 120 ActivateMask, /* ActivateNotify */ 121 ActivateMask, /* DeactivateNotify */ 122 MouseWheelMask /* MouseWheelEvent */ 123}; 124 125 126/* 127 * The structure below is used to store Data for the Event module that 128 * must be kept thread-local. The "dataKey" is used to fetch the 129 * thread-specific storage for the current thread. 130 */ 131 132typedef struct ThreadSpecificData { 133 int handlersActive; /* The following variable has a non-zero 134 * value when a handler is active. */ 135 InProgress *pendingPtr; /* Topmost search in progress, or 136 * NULL if none. */ 137 138 GenericHandler *genericList; /* First handler in the list, or NULL. */ 139 GenericHandler *lastGenericPtr; /* Last handler in list. */ 140 141 GenericHandler *cmList; /* First handler in the list, or NULL. */ 142 GenericHandler *lastCmPtr; /* Last handler in list. */ 143 144 /* 145 * If someone has called Tk_RestrictEvents, the information below 146 * keeps track of it. 147 */ 148 149 Tk_RestrictProc *restrictProc; 150 /* Procedure to call. NULL means no 151 * restrictProc is currently in effect. */ 152 ClientData restrictArg; /* Argument to pass to restrictProc. */ 153} ThreadSpecificData; 154static Tcl_ThreadDataKey dataKey; 155 156/* 157 * Prototypes for procedures that are only referenced locally within 158 * this file. 159 */ 160 161static void DelayedMotionProc _ANSI_ARGS_((ClientData clientData)); 162static int WindowEventProc _ANSI_ARGS_((Tcl_Event *evPtr, 163 int flags)); 164static int TkXErrorHandler _ANSI_ARGS_((ClientData clientData, 165 XErrorEvent *errEventPtr)); 166 167 168/* 169 *-------------------------------------------------------------- 170 * 171 * Tk_CreateEventHandler -- 172 * 173 * Arrange for a given procedure to be invoked whenever 174 * events from a given class occur in a given window. 175 * 176 * Results: 177 * None. 178 * 179 * Side effects: 180 * From now on, whenever an event of the type given by 181 * mask occurs for token and is processed by Tk_HandleEvent, 182 * proc will be called. See the manual entry for details 183 * of the calling sequence and return value for proc. 184 * 185 *-------------------------------------------------------------- 186 */ 187 188void 189Tk_CreateEventHandler(token, mask, proc, clientData) 190 Tk_Window token; /* Token for window in which to 191 * create handler. */ 192 unsigned long mask; /* Events for which proc should 193 * be called. */ 194 Tk_EventProc *proc; /* Procedure to call for each 195 * selected event */ 196 ClientData clientData; /* Arbitrary data to pass to proc. */ 197{ 198 register TkEventHandler *handlerPtr; 199 register TkWindow *winPtr = (TkWindow *) token; 200 int found; 201 202 /* 203 * Skim through the list of existing handlers to (a) compute the 204 * overall event mask for the window (so we can pass this new 205 * value to the X system) and (b) see if there's already a handler 206 * declared with the same callback and clientData (if so, just 207 * change the mask). If no existing handler matches, then create 208 * a new handler. 209 */ 210 211 found = 0; 212 if (winPtr->handlerList == NULL) { 213 handlerPtr = (TkEventHandler *) ckalloc( 214 (unsigned) sizeof(TkEventHandler)); 215 winPtr->handlerList = handlerPtr; 216 goto initHandler; 217 } else { 218 for (handlerPtr = winPtr->handlerList; ; 219 handlerPtr = handlerPtr->nextPtr) { 220 if ((handlerPtr->proc == proc) 221 && (handlerPtr->clientData == clientData)) { 222 handlerPtr->mask = mask; 223 found = 1; 224 } 225 if (handlerPtr->nextPtr == NULL) { 226 break; 227 } 228 } 229 } 230 231 /* 232 * Create a new handler if no matching old handler was found. 233 */ 234 235 if (!found) { 236 handlerPtr->nextPtr = (TkEventHandler *) 237 ckalloc(sizeof(TkEventHandler)); 238 handlerPtr = handlerPtr->nextPtr; 239 initHandler: 240 handlerPtr->mask = mask; 241 handlerPtr->proc = proc; 242 handlerPtr->clientData = clientData; 243 handlerPtr->nextPtr = NULL; 244 } 245 246 /* 247 * No need to call XSelectInput: Tk always selects on all events 248 * for all windows (needed to support bindings on classes and "all"). 249 */ 250} 251 252/* 253 *-------------------------------------------------------------- 254 * 255 * Tk_DeleteEventHandler -- 256 * 257 * Delete a previously-created handler. 258 * 259 * Results: 260 * None. 261 * 262 * Side effects: 263 * If there existed a handler as described by the 264 * parameters, the handler is deleted so that proc 265 * will not be invoked again. 266 * 267 *-------------------------------------------------------------- 268 */ 269 270void 271Tk_DeleteEventHandler(token, mask, proc, clientData) 272 Tk_Window token; /* Same as corresponding arguments passed */ 273 unsigned long mask; /* previously to Tk_CreateEventHandler. */ 274 Tk_EventProc *proc; 275 ClientData clientData; 276{ 277 register TkEventHandler *handlerPtr; 278 register InProgress *ipPtr; 279 TkEventHandler *prevPtr; 280 register TkWindow *winPtr = (TkWindow *) token; 281 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 282 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 283 284 /* 285 * Find the event handler to be deleted, or return 286 * immediately if it doesn't exist. 287 */ 288 289 for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ; 290 prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) { 291 if (handlerPtr == NULL) { 292 return; 293 } 294 if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc) 295 && (handlerPtr->clientData == clientData)) { 296 break; 297 } 298 } 299 300 /* 301 * If Tk_HandleEvent is about to process this handler, tell it to 302 * process the next one instead. 303 */ 304 305 for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { 306 if (ipPtr->nextHandler == handlerPtr) { 307 ipPtr->nextHandler = handlerPtr->nextPtr; 308 } 309 } 310 311 /* 312 * Free resources associated with the handler. 313 */ 314 315 if (prevPtr == NULL) { 316 winPtr->handlerList = handlerPtr->nextPtr; 317 } else { 318 prevPtr->nextPtr = handlerPtr->nextPtr; 319 } 320 ckfree((char *) handlerPtr); 321 322 323 /* 324 * No need to call XSelectInput: Tk always selects on all events 325 * for all windows (needed to support bindings on classes and "all"). 326 */ 327} 328 329/*-------------------------------------------------------------- 330 * 331 * Tk_CreateGenericHandler -- 332 * 333 * Register a procedure to be called on each X event, regardless 334 * of display or window. Generic handlers are useful for capturing 335 * events that aren't associated with windows, or events for windows 336 * not managed by Tk. 337 * 338 * Results: 339 * None. 340 * 341 * Side Effects: 342 * From now on, whenever an X event is given to Tk_HandleEvent, 343 * invoke proc, giving it clientData and the event as arguments. 344 * 345 *-------------------------------------------------------------- 346 */ 347 348void 349Tk_CreateGenericHandler(proc, clientData) 350 Tk_GenericProc *proc; /* Procedure to call on every event. */ 351 ClientData clientData; /* One-word value to pass to proc. */ 352{ 353 GenericHandler *handlerPtr; 354 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 355 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 356 357 handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler)); 358 359 handlerPtr->proc = proc; 360 handlerPtr->clientData = clientData; 361 handlerPtr->deleteFlag = 0; 362 handlerPtr->nextPtr = NULL; 363 if (tsdPtr->genericList == NULL) { 364 tsdPtr->genericList = handlerPtr; 365 } else { 366 tsdPtr->lastGenericPtr->nextPtr = handlerPtr; 367 } 368 tsdPtr->lastGenericPtr = handlerPtr; 369} 370 371/* 372 *-------------------------------------------------------------- 373 * 374 * Tk_DeleteGenericHandler -- 375 * 376 * Delete a previously-created generic handler. 377 * 378 * Results: 379 * None. 380 * 381 * Side Effects: 382 * If there existed a handler as described by the parameters, 383 * that handler is logically deleted so that proc will not be 384 * invoked again. The physical deletion happens in the event 385 * loop in Tk_HandleEvent. 386 * 387 *-------------------------------------------------------------- 388 */ 389 390void 391Tk_DeleteGenericHandler(proc, clientData) 392 Tk_GenericProc *proc; 393 ClientData clientData; 394{ 395 GenericHandler * handler; 396 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 397 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 398 399 for (handler = tsdPtr->genericList; handler; handler = handler->nextPtr) { 400 if ((handler->proc == proc) && (handler->clientData == clientData)) { 401 handler->deleteFlag = 1; 402 } 403 } 404} 405 406/*-------------------------------------------------------------- 407 * 408 * Tk_CreateClientMessageHandler -- 409 * 410 * Register a procedure to be called on each ClientMessage event. 411 * ClientMessage handlers are useful for Drag&Drop extensions. 412 * 413 * Results: 414 * None. 415 * 416 * Side Effects: 417 * From now on, whenever a ClientMessage event is received that isn't 418 * a WM_PROTOCOL event or SelectionEvent, invoke proc, giving it 419 * tkwin and the event as arguments. 420 * 421 *-------------------------------------------------------------- 422 */ 423 424void 425Tk_CreateClientMessageHandler(proc) 426 Tk_ClientMessageProc *proc; /* Procedure to call on event. */ 427{ 428 GenericHandler *handlerPtr; 429 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 430 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 431 432 /* 433 * We use a GenericHandler struct, because it's basically the same, 434 * except with an extra clientData field we'll never use. 435 */ 436 handlerPtr = (GenericHandler *) 437 ckalloc (sizeof (GenericHandler)); 438 439 handlerPtr->proc = (Tk_GenericProc *) proc; 440 handlerPtr->clientData = NULL; /* never used */ 441 handlerPtr->deleteFlag = 0; 442 handlerPtr->nextPtr = NULL; 443 if (tsdPtr->cmList == NULL) { 444 tsdPtr->cmList = handlerPtr; 445 } else { 446 tsdPtr->lastCmPtr->nextPtr = handlerPtr; 447 } 448 tsdPtr->lastCmPtr = handlerPtr; 449} 450 451/* 452 *-------------------------------------------------------------- 453 * 454 * Tk_DeleteClientMessageHandler -- 455 * 456 * Delete a previously-created ClientMessage handler. 457 * 458 * Results: 459 * None. 460 * 461 * Side Effects: 462 * If there existed a handler as described by the parameters, 463 * that handler is logically deleted so that proc will not be 464 * invoked again. The physical deletion happens in the event 465 * loop in TkClientMessageEventProc. 466 * 467 *-------------------------------------------------------------- 468 */ 469 470void 471Tk_DeleteClientMessageHandler(proc) 472 Tk_ClientMessageProc *proc; 473{ 474 GenericHandler * handler; 475 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 476 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 477 478 for (handler = tsdPtr->cmList; handler != NULL; 479 handler = handler->nextPtr) { 480 if (handler->proc == (Tk_GenericProc *) proc) { 481 handler->deleteFlag = 1; 482 } 483 } 484} 485 486/* 487 *-------------------------------------------------------------- 488 * 489 * TkEventInit -- 490 * 491 * This procedures initializes all the event module 492 * structures used by the current thread. It must be 493 * called before any other procedure in this file is 494 * called. 495 * 496 * Results: 497 * None. 498 * 499 * Side Effects: 500 * None. 501 * 502 *-------------------------------------------------------------- 503 */ 504 505void 506TkEventInit _ANSI_ARGS_((void)) 507{ 508 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 509 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 510 511 tsdPtr->handlersActive = 0; 512 tsdPtr->pendingPtr = NULL; 513 tsdPtr->genericList = NULL; 514 tsdPtr->lastGenericPtr = NULL; 515 tsdPtr->cmList = NULL; 516 tsdPtr->lastCmPtr = NULL; 517 tsdPtr->restrictProc = NULL; 518 tsdPtr->restrictArg = NULL; 519} 520 521/* 522 *-------------------------------------------------------------- 523 * 524 * TkXErrorHandler -- 525 * 526 * TkXErrorHandler is an error handler, to be installed 527 * via Tk_CreateErrorHandler, that will set a flag if an 528 * X error occurred. 529 * 530 * Results: 531 * Always returns 0, indicating that the X error was 532 * handled. 533 * 534 * Side effects: 535 * None. 536 * 537 *-------------------------------------------------------------- 538 */ 539 540static int 541TkXErrorHandler (clientData, errEventPtr) 542 ClientData clientData; /* Pointer to flag we set */ 543 XErrorEvent *errEventPtr; /* X error info */ 544{ 545 int *error; 546 547 error = (int *) clientData; 548 *error = 1; 549 return 0; 550} 551 552/* 553 *-------------------------------------------------------------- 554 * 555 * ParentXId -- 556 * 557 * Returns the parent of the given window, or "None" 558 * if the window doesn't exist. 559 * 560 * Results: 561 * Returns an X window ID. 562 * 563 * Side effects: 564 * None. 565 * 566 *-------------------------------------------------------------- 567 */ 568 569static Window 570ParentXId(display, w) 571 Display *display; 572 Window w; 573{ 574 Tk_ErrorHandler handler; 575 int gotXError; 576 Status status; 577 Window parent; 578 Window root; 579 Window *childList; 580 unsigned int nChildren; 581 582 /* Handle errors ourselves. */ 583 584 gotXError = 0; 585 handler = Tk_CreateErrorHandler(display, -1, -1, -1, 586 TkXErrorHandler, (ClientData) (&gotXError)); 587 588 /* Get the parent window. */ 589 590 status = XQueryTree(display, w, &root, &parent, &childList, &nChildren); 591 592 /* Do some cleanup; gotta return "None" if we got an error. */ 593 594 Tk_DeleteErrorHandler(handler); 595 XSync(display, False); 596 if (status != 0 && childList != NULL) { 597 XFree(childList); 598 } 599 if (status == 0) { 600 parent = None; 601 } 602 603 return parent; 604} 605 606/* 607 *-------------------------------------------------------------- 608 * 609 * Tk_HandleEvent -- 610 * 611 * Given an event, invoke all the handlers that have 612 * been registered for the event. 613 * 614 * Results: 615 * None. 616 * 617 * Side effects: 618 * Depends on the handlers. 619 * 620 *-------------------------------------------------------------- 621 */ 622 623void 624Tk_HandleEvent(eventPtr) 625 XEvent *eventPtr; /* Event to dispatch. */ 626{ 627 register TkEventHandler *handlerPtr; 628 register GenericHandler *genericPtr; 629 register GenericHandler *genPrevPtr; 630 TkWindow *winPtr; 631 unsigned long mask; 632 InProgress ip; 633 Window handlerWindow; 634 Window parentXId; 635 TkDisplay *dispPtr; 636 Tcl_Interp *interp = (Tcl_Interp *) NULL; 637 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 638 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 639 640 /* 641 * Hack for simulated X-events: Correct the state field 642 * of the event record to match with the ButtonPress 643 * and ButtonRelease events. 644 */ 645 646 if (eventPtr->type==ButtonPress) { 647 dispPtr = TkGetDisplay(eventPtr->xbutton.display); 648 dispPtr->mouseButtonWindow = eventPtr->xbutton.window; 649 eventPtr->xbutton.state |= dispPtr->mouseButtonState; 650 switch (eventPtr->xbutton.button) { 651 case 1: dispPtr->mouseButtonState |= Button1Mask; break; 652 case 2: dispPtr->mouseButtonState |= Button2Mask; break; 653 case 3: dispPtr->mouseButtonState |= Button3Mask; break; 654 } 655 } else if (eventPtr->type==ButtonRelease) { 656 dispPtr = TkGetDisplay(eventPtr->xbutton.display); 657 dispPtr->mouseButtonWindow = 0; 658 switch (eventPtr->xbutton.button) { 659 case 1: dispPtr->mouseButtonState &= ~Button1Mask; break; 660 case 2: dispPtr->mouseButtonState &= ~Button2Mask; break; 661 case 3: dispPtr->mouseButtonState &= ~Button3Mask; break; 662 } 663 eventPtr->xbutton.state |= dispPtr->mouseButtonState; 664 } else if (eventPtr->type==MotionNotify) { 665 dispPtr = TkGetDisplay(eventPtr->xmotion.display); 666 if (dispPtr->mouseButtonState & (Button1Mask|Button2Mask|Button3Mask)) { 667 if (eventPtr->xbutton.window != dispPtr->mouseButtonWindow) { 668 /* 669 * This motion event should not be interpreted as a button 670 * press + motion event since this is not the same window 671 * the button was pressed down in. 672 */ 673 dispPtr->mouseButtonState &= 674 ~(Button1Mask|Button2Mask|Button3Mask); 675 dispPtr->mouseButtonWindow = 0; 676 } else { 677 eventPtr->xmotion.state |= dispPtr->mouseButtonState; 678 } 679 } 680 } 681 682 /* 683 * Next, invoke all the generic event handlers (those that are 684 * invoked for all events). If a generic event handler reports that 685 * an event is fully processed, go no further. 686 */ 687 688 for (genPrevPtr = NULL, genericPtr = tsdPtr->genericList; 689 genericPtr != NULL; ) { 690 if (genericPtr->deleteFlag) { 691 if (!tsdPtr->handlersActive) { 692 GenericHandler *tmpPtr; 693 694 /* 695 * This handler needs to be deleted and there are no 696 * calls pending through the handler, so now is a safe 697 * time to delete it. 698 */ 699 700 tmpPtr = genericPtr->nextPtr; 701 if (genPrevPtr == NULL) { 702 tsdPtr->genericList = tmpPtr; 703 } else { 704 genPrevPtr->nextPtr = tmpPtr; 705 } 706 if (tmpPtr == NULL) { 707 tsdPtr->lastGenericPtr = genPrevPtr; 708 } 709 (void) ckfree((char *) genericPtr); 710 genericPtr = tmpPtr; 711 continue; 712 } 713 } else { 714 int done; 715 716 tsdPtr->handlersActive++; 717 done = (*genericPtr->proc)(genericPtr->clientData, eventPtr); 718 tsdPtr->handlersActive--; 719 if (done) { 720 return; 721 } 722 } 723 genPrevPtr = genericPtr; 724 genericPtr = genPrevPtr->nextPtr; 725 } 726 727 /* 728 * If the event is a MappingNotify event, find its display and 729 * refresh the keyboard mapping information for the display. 730 * After that there's nothing else to do with the event, so just 731 * quit. 732 */ 733 734 if (eventPtr->type == MappingNotify) { 735 dispPtr = TkGetDisplay(eventPtr->xmapping.display); 736 if (dispPtr != NULL) { 737 XRefreshKeyboardMapping(&eventPtr->xmapping); 738 dispPtr->bindInfoStale = 1; 739 } 740 return; 741 } 742 743 /* 744 * Events selected by StructureNotify require special handling. 745 * They look the same as those selected by SubstructureNotify. 746 * The only difference is whether the "event" and "window" fields 747 * are the same. Compare the two fields and convert StructureNotify 748 * to SubstructureNotify if necessary. 749 */ 750 751 handlerWindow = eventPtr->xany.window; 752 mask = eventMasks[eventPtr->xany.type]; 753 if (mask == StructureNotifyMask) { 754 if (eventPtr->xmap.event != eventPtr->xmap.window) { 755 mask = SubstructureNotifyMask; 756 handlerWindow = eventPtr->xmap.event; 757 } 758 } 759 winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, handlerWindow); 760 if (winPtr == NULL) { 761 /* 762 * There isn't a TkWindow structure for this window. 763 * However, if the event is a PropertyNotify event then call 764 * the selection manager (it deals beneath-the-table with 765 * certain properties). Also, if the window's parent is a 766 * Tk window that has the TK_PROP_PROPCHANGE flag set, then 767 * we must propagate the PropertyNotify event up to the parent. 768 */ 769 770 if (eventPtr->type != PropertyNotify) { 771 return; 772 } 773 774 TkSelPropProc(eventPtr); 775 776 /* Get handlerWindow's parent. */ 777 778 parentXId = ParentXId(eventPtr->xany.display, handlerWindow); 779 if (parentXId == None) { 780 return; 781 } 782 783 winPtr = (TkWindow *) Tk_IdToWindow(eventPtr->xany.display, parentXId); 784 if (winPtr == NULL) { 785 return; 786 } 787 788 if (!(winPtr->flags & TK_PROP_PROPCHANGE)) { 789 return; 790 } 791 792 handlerWindow = parentXId; 793 } 794 795 /* 796 * Once a window has started getting deleted, don't process any more 797 * events for it except for the DestroyNotify event. This check is 798 * needed because a DestroyNotify handler could re-invoke the event 799 * loop, causing other pending events to be handled for the window 800 * (the window doesn't get totally expunged from our tables until 801 * after the DestroyNotify event has been completely handled). 802 */ 803 804 if ((winPtr->flags & TK_ALREADY_DEAD) 805 && (eventPtr->type != DestroyNotify)) { 806 return; 807 } 808 809 if (winPtr->mainPtr != NULL) { 810 811 /* 812 * Protect interpreter for this window from possible deletion 813 * while we are dealing with the event for this window. Thus, 814 * widget writers do not have to worry about protecting the 815 * interpreter in their own code. 816 */ 817 818 interp = winPtr->mainPtr->interp; 819 Tcl_Preserve((ClientData) interp); 820 821 /* 822 * Call focus-related code to look at FocusIn, FocusOut, Enter, 823 * and Leave events; depending on its return value, ignore the 824 * event. 825 */ 826 827 if ((mask & (FocusChangeMask|EnterWindowMask|LeaveWindowMask)) 828 && !TkFocusFilterEvent(winPtr, eventPtr)) { 829 Tcl_Release((ClientData) interp); 830 return; 831 } 832 833 /* 834 * Redirect KeyPress and KeyRelease events to the focus window, 835 * or ignore them entirely if there is no focus window. We also 836 * route the MouseWheel event to the focus window. The MouseWheel 837 * event is an extension to the X event set. Currently, it is only 838 * available on the Windows version of Tk. 839 */ 840 841#ifdef MAC_OSX_TK 842 /* MouseWheel events are not focus specific on Mac OS X */ 843 if (mask & (KeyPressMask|KeyReleaseMask)) { 844#else 845 if (mask & (KeyPressMask|KeyReleaseMask|MouseWheelMask)) { 846#endif 847 winPtr->dispPtr->lastEventTime = eventPtr->xkey.time; 848 winPtr = TkFocusKeyEvent(winPtr, eventPtr); 849 if (winPtr == NULL) { 850 Tcl_Release((ClientData) interp); 851 return; 852 } 853 } 854 855 /* 856 * Call a grab-related procedure to do special processing on 857 * pointer events. 858 */ 859 860 if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask 861 |EnterWindowMask|LeaveWindowMask)) { 862 if (mask & (ButtonPressMask|ButtonReleaseMask)) { 863 winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time; 864 } else if (mask & PointerMotionMask) { 865 winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time; 866 } else { 867 winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time; 868 } 869 if (TkPointerEvent(eventPtr, winPtr) == 0) { 870 goto done; 871 } 872 } 873 } 874 875#ifdef TK_USE_INPUT_METHODS 876 /* 877 * Pass the event to the input method(s), if there are any, and 878 * discard the event if the input method(s) insist. Create the 879 * input context for the window if it hasn't already been done 880 * (XFilterEvent needs this context). XIM is only ever enabled on 881 * Unix, but this hasn't been factored out of the generic code yet. 882 */ 883 dispPtr = winPtr->dispPtr; 884 if ((dispPtr->flags & TK_DISPLAY_USE_IM)) { 885 long im_event_mask = 0L; 886 if (!(winPtr->flags & (TK_CHECKED_IC|TK_ALREADY_DEAD))) { 887 winPtr->flags |= TK_CHECKED_IC; 888 if (dispPtr->inputMethod != NULL) { 889#if TK_XIM_SPOT 890 if (dispPtr->flags & TK_DISPLAY_XIM_SPOT) { 891 XVaNestedList preedit_attr; 892 XPoint spot = {0, 0}; 893 894 if (dispPtr->inputXfs == NULL) { 895 /* 896 * We only need to create one XFontSet 897 */ 898 char **missing_list; 899 int missing_count; 900 char *def_string; 901 902 dispPtr->inputXfs = XCreateFontSet(dispPtr->display, 903 "-*-*-*-R-Normal--14-130-75-75-*-*", 904 &missing_list, &missing_count, &def_string); 905 if (missing_count > 0) { 906 XFreeStringList(missing_list); 907 } 908 } 909 910 preedit_attr = XVaCreateNestedList(0, XNSpotLocation, 911 &spot, XNFontSet, dispPtr->inputXfs, NULL); 912 if (winPtr->inputContext != NULL) 913 panic("inputContext not NULL"); 914 winPtr->inputContext = XCreateIC(dispPtr->inputMethod, 915 XNInputStyle, XIMPreeditPosition|XIMStatusNothing, 916 XNClientWindow, winPtr->window, 917 XNFocusWindow, winPtr->window, 918 XNPreeditAttributes, preedit_attr, 919 NULL); 920 XFree(preedit_attr); 921 } else { 922 if (winPtr->inputContext != NULL) 923 panic("inputContext not NULL"); 924 winPtr->inputContext = XCreateIC(dispPtr->inputMethod, 925 XNInputStyle, XIMPreeditNothing|XIMStatusNothing, 926 XNClientWindow, winPtr->window, 927 XNFocusWindow, winPtr->window, 928 NULL); 929 } 930#else 931 if (winPtr->inputContext != NULL) 932 panic("inputContext not NULL"); 933 winPtr->inputContext = XCreateIC(dispPtr->inputMethod, 934 XNInputStyle, XIMPreeditNothing|XIMStatusNothing, 935 XNClientWindow, winPtr->window, 936 XNFocusWindow, winPtr->window, 937 NULL); 938#endif 939 } 940 } 941 if (winPtr->inputContext != NULL && 942 (eventPtr->xany.type == FocusIn)) { 943 XGetICValues(winPtr->inputContext, 944 XNFilterEvents, &im_event_mask, NULL); 945 if (im_event_mask != 0L) { 946 XSelectInput(winPtr->display, winPtr->window, 947 winPtr->atts.event_mask | im_event_mask); 948 XSetICFocus(winPtr->inputContext); 949 } 950 } 951 if (eventPtr->type == KeyPress || eventPtr->type == KeyRelease) { 952 if (XFilterEvent(eventPtr, None)) { 953 goto done; 954 } 955 } 956 } 957#endif /* TK_USE_INPUT_METHODS */ 958 959 /* 960 * For events where it hasn't already been done, update the current 961 * time in the display. 962 */ 963 964 if (eventPtr->type == PropertyNotify) { 965 winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time; 966 } 967 968 /* 969 * There's a potential interaction here with Tk_DeleteEventHandler. 970 * Read the documentation for pendingPtr. 971 */ 972 973 ip.eventPtr = eventPtr; 974 ip.winPtr = winPtr; 975 ip.nextHandler = NULL; 976 ip.nextPtr = tsdPtr->pendingPtr; 977 tsdPtr->pendingPtr = &ip; 978 if (mask == 0) { 979 if ((eventPtr->type == SelectionClear) 980 || (eventPtr->type == SelectionRequest) 981 || (eventPtr->type == SelectionNotify)) { 982 TkSelEventProc((Tk_Window) winPtr, eventPtr); 983 } else if (eventPtr->type == ClientMessage) { 984 if (eventPtr->xclient.message_type == 985 Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS")) { 986 TkWmProtocolEventProc(winPtr, eventPtr); 987 } else { 988 /* 989 * Finally, invoke any ClientMessage event handlers. 990 */ 991 992 for (genPrevPtr = NULL, genericPtr = tsdPtr->cmList; 993 genericPtr != NULL; ) { 994 if (genericPtr->deleteFlag) { 995 if (!tsdPtr->handlersActive) { 996 GenericHandler *tmpPtr; 997 998 /* 999 * This handler needs to be deleted and there are 1000 * no calls pending through any handlers, so now 1001 * is a safe time to delete it. 1002 */ 1003 1004 tmpPtr = genericPtr->nextPtr; 1005 if (genPrevPtr == NULL) { 1006 tsdPtr->cmList = tmpPtr; 1007 } else { 1008 genPrevPtr->nextPtr = tmpPtr; 1009 } 1010 if (tmpPtr == NULL) { 1011 tsdPtr->lastCmPtr = genPrevPtr; 1012 } 1013 (void) ckfree((char *) genericPtr); 1014 genericPtr = tmpPtr; 1015 continue; 1016 } 1017 } else { 1018 int done; 1019 1020 tsdPtr->handlersActive++; 1021 done = (*(Tk_ClientMessageProc *)genericPtr->proc) 1022 ((Tk_Window) winPtr, eventPtr); 1023 tsdPtr->handlersActive--; 1024 if (done) { 1025 break; 1026 } 1027 } 1028 genPrevPtr = genericPtr; 1029 genericPtr = genPrevPtr->nextPtr; 1030 } 1031 } 1032 } 1033 } else { 1034 for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) { 1035 if ((handlerPtr->mask & mask) != 0) { 1036 ip.nextHandler = handlerPtr->nextPtr; 1037 (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr); 1038 handlerPtr = ip.nextHandler; 1039 } else { 1040 handlerPtr = handlerPtr->nextPtr; 1041 } 1042 } 1043 1044 /* 1045 * Pass the event to the "bind" command mechanism. But, don't 1046 * do this for SubstructureNotify events. The "bind" command 1047 * doesn't support them anyway, and it's easier to filter out 1048 * these events here than in the lower-level procedures. 1049 */ 1050 1051 /* 1052 * ...well, except when we use the tkwm patches, in which case 1053 * we DO handle CreateNotify events, so we gotta pass 'em through. 1054 */ 1055 1056 if ((ip.winPtr != None) 1057 && ((mask != SubstructureNotifyMask) 1058 || (eventPtr->type == CreateNotify))) { 1059 TkBindEventProc(winPtr, eventPtr); 1060 } 1061 } 1062 tsdPtr->pendingPtr = ip.nextPtr; 1063done: 1064 1065 /* 1066 * Release the interpreter for this window so that it can be potentially 1067 * deleted if requested. 1068 */ 1069 1070 if (interp != (Tcl_Interp *) NULL) { 1071 Tcl_Release((ClientData) interp); 1072 } 1073} 1074 1075/* 1076 *-------------------------------------------------------------- 1077 * 1078 * TkEventDeadWindow -- 1079 * 1080 * This procedure is invoked when it is determined that 1081 * a window is dead. It cleans up event-related information 1082 * about the window. 1083 * 1084 * Results: 1085 * None. 1086 * 1087 * Side effects: 1088 * Various things get cleaned up and recycled. 1089 * 1090 *-------------------------------------------------------------- 1091 */ 1092 1093void 1094TkEventDeadWindow(winPtr) 1095 TkWindow *winPtr; /* Information about the window 1096 * that is being deleted. */ 1097{ 1098 register TkEventHandler *handlerPtr; 1099 register InProgress *ipPtr; 1100 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1101 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1102 1103 /* 1104 * While deleting all the handlers, be careful to check for 1105 * Tk_HandleEvent being about to process one of the deleted 1106 * handlers. If it is, tell it to quit (all of the handlers 1107 * are being deleted). 1108 */ 1109 1110 while (winPtr->handlerList != NULL) { 1111 handlerPtr = winPtr->handlerList; 1112 winPtr->handlerList = handlerPtr->nextPtr; 1113 for (ipPtr = tsdPtr->pendingPtr; ipPtr != NULL; 1114 ipPtr = ipPtr->nextPtr) { 1115 if (ipPtr->nextHandler == handlerPtr) { 1116 ipPtr->nextHandler = NULL; 1117 } 1118 if (ipPtr->winPtr == winPtr) { 1119 ipPtr->winPtr = None; 1120 } 1121 } 1122 ckfree((char *) handlerPtr); 1123 } 1124} 1125 1126/* 1127 *---------------------------------------------------------------------- 1128 * 1129 * TkCurrentTime -- 1130 * 1131 * Try to deduce the current time. "Current time" means the time 1132 * of the event that led to the current code being executed, which 1133 * means the time in the most recently-nested invocation of 1134 * Tk_HandleEvent. 1135 * 1136 * Results: 1137 * The return value is the time from the current event, or 1138 * CurrentTime if there is no current event or if the current 1139 * event contains no time. 1140 * 1141 * Side effects: 1142 * None. 1143 * 1144 *---------------------------------------------------------------------- 1145 */ 1146 1147Time 1148TkCurrentTime(dispPtr) 1149 TkDisplay *dispPtr; /* Display for which the time is desired. */ 1150{ 1151 register XEvent *eventPtr; 1152 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1153 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1154 1155 if (tsdPtr->pendingPtr == NULL) { 1156 return dispPtr->lastEventTime; 1157 } 1158 eventPtr = tsdPtr->pendingPtr->eventPtr; 1159 switch (eventPtr->type) { 1160 case ButtonPress: 1161 case ButtonRelease: 1162 return eventPtr->xbutton.time; 1163 case KeyPress: 1164 case KeyRelease: 1165 return eventPtr->xkey.time; 1166 case MotionNotify: 1167 return eventPtr->xmotion.time; 1168 case EnterNotify: 1169 case LeaveNotify: 1170 return eventPtr->xcrossing.time; 1171 case PropertyNotify: 1172 return eventPtr->xproperty.time; 1173 } 1174 return dispPtr->lastEventTime; 1175} 1176 1177/* 1178 *---------------------------------------------------------------------- 1179 * 1180 * Tk_RestrictEvents -- 1181 * 1182 * This procedure is used to globally restrict the set of events 1183 * that will be dispatched. The restriction is done by filtering 1184 * all incoming X events through a procedure that determines 1185 * whether they are to be processed immediately, deferred, or 1186 * discarded. 1187 * 1188 * Results: 1189 * The return value is the previous restriction procedure in effect, 1190 * if there was one, or NULL if there wasn't. 1191 * 1192 * Side effects: 1193 * From now on, proc will be called to determine whether to process, 1194 * defer or discard each incoming X event. 1195 * 1196 *---------------------------------------------------------------------- 1197 */ 1198 1199Tk_RestrictProc * 1200Tk_RestrictEvents(proc, arg, prevArgPtr) 1201 Tk_RestrictProc *proc; /* Procedure to call for each incoming 1202 * event. */ 1203 ClientData arg; /* Arbitrary argument to pass to proc. */ 1204 ClientData *prevArgPtr; /* Place to store information about previous 1205 * argument. */ 1206{ 1207 Tk_RestrictProc *prev; 1208 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1209 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1210 1211 prev = tsdPtr->restrictProc; 1212 *prevArgPtr = tsdPtr->restrictArg; 1213 tsdPtr->restrictProc = proc; 1214 tsdPtr->restrictArg = arg; 1215 return prev; 1216} 1217 1218/* 1219 *---------------------------------------------------------------------- 1220 * 1221 * Tk_CollapseMotionEvents -- 1222 * 1223 * This procedure controls whether we collapse motion events in a 1224 * particular display or not. 1225 * 1226 * Results: 1227 * The return value is the previous collapse value in effect. 1228 * 1229 * Side effects: 1230 * Filtering of motion events may be changed after calling this. 1231 * 1232 *---------------------------------------------------------------------- 1233 */ 1234 1235int 1236Tk_CollapseMotionEvents(display, collapse) 1237 Display *display; /* Display handling these events. */ 1238 int collapse; /* boolean value that specifies whether 1239 * motion events should be collapsed. */ 1240{ 1241 TkDisplay *dispPtr = (TkDisplay *) display; 1242 int prev = (dispPtr->flags & TK_DISPLAY_COLLAPSE_MOTION_EVENTS); 1243 1244 if (collapse) { 1245 dispPtr->flags |= TK_DISPLAY_COLLAPSE_MOTION_EVENTS; 1246 } else { 1247 dispPtr->flags &= ~TK_DISPLAY_COLLAPSE_MOTION_EVENTS; 1248 } 1249 return prev; 1250} 1251 1252/* 1253 *---------------------------------------------------------------------- 1254 * 1255 * Tk_QueueWindowEvent -- 1256 * 1257 * Given an X-style window event, this procedure adds it to the 1258 * Tcl event queue at the given position. This procedure also 1259 * performs mouse motion event collapsing if possible. 1260 * 1261 * Results: 1262 * None. 1263 * 1264 * Side effects: 1265 * Adds stuff to the event queue, which will eventually be 1266 * processed. 1267 * 1268 *---------------------------------------------------------------------- 1269 */ 1270 1271void 1272Tk_QueueWindowEvent(eventPtr, position) 1273 XEvent *eventPtr; /* Event to add to queue. This 1274 * procedures copies it before adding 1275 * it to the queue. */ 1276 Tcl_QueuePosition position; /* Where to put it on the queue: 1277 * TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, 1278 * or TCL_QUEUE_MARK. */ 1279{ 1280 TkWindowEvent *wevPtr; 1281 TkDisplay *dispPtr; 1282 1283 /* 1284 * Find our display structure for the event's display. 1285 */ 1286 1287 for (dispPtr = TkGetDisplayList(); ; dispPtr = dispPtr->nextPtr) { 1288 if (dispPtr == NULL) { 1289 return; 1290 } 1291 if (dispPtr->display == eventPtr->xany.display) { 1292 break; 1293 } 1294 } 1295 1296 /* 1297 * Don't filter motion events if the user 1298 * defaulting to true (1), which could be set to false (0) when the 1299 * user wishes to receive all the motion data) 1300 */ 1301 if (!(dispPtr->flags & TK_DISPLAY_COLLAPSE_MOTION_EVENTS)) { 1302 wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent)); 1303 wevPtr->header.proc = WindowEventProc; 1304 wevPtr->event = *eventPtr; 1305 Tcl_QueueEvent(&wevPtr->header, position); 1306 return; 1307 } 1308 1309 if ((dispPtr->delayedMotionPtr != NULL) && (position == TCL_QUEUE_TAIL)) { 1310 if ((eventPtr->type == MotionNotify) && (eventPtr->xmotion.window 1311 == dispPtr->delayedMotionPtr->event.xmotion.window)) { 1312 /* 1313 * The new event is a motion event in the same window as the 1314 * saved motion event. Just replace the saved event with the 1315 * new one. 1316 */ 1317 1318 dispPtr->delayedMotionPtr->event = *eventPtr; 1319 return; 1320 } else if ((eventPtr->type != GraphicsExpose) 1321 && (eventPtr->type != NoExpose) 1322 && (eventPtr->type != Expose)) { 1323 /* 1324 * The new event may conflict with the saved motion event. Queue 1325 * the saved motion event now so that it will be processed before 1326 * the new event. 1327 */ 1328 1329 Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, position); 1330 dispPtr->delayedMotionPtr = NULL; 1331 Tcl_CancelIdleCall(DelayedMotionProc, (ClientData) dispPtr); 1332 } 1333 } 1334 1335 wevPtr = (TkWindowEvent *) ckalloc(sizeof(TkWindowEvent)); 1336 wevPtr->header.proc = WindowEventProc; 1337 wevPtr->event = *eventPtr; 1338 if ((eventPtr->type == MotionNotify) && (position == TCL_QUEUE_TAIL)) { 1339 /* 1340 * The new event is a motion event so don't queue it immediately; 1341 * save it around in case another motion event arrives that it can 1342 * be collapsed with. 1343 */ 1344 1345 if (dispPtr->delayedMotionPtr != NULL) { 1346 panic("Tk_QueueWindowEvent found unexpected delayed motion event"); 1347 } 1348 dispPtr->delayedMotionPtr = wevPtr; 1349 Tcl_DoWhenIdle(DelayedMotionProc, (ClientData) dispPtr); 1350 } else { 1351 Tcl_QueueEvent(&wevPtr->header, position); 1352 } 1353} 1354 1355/* 1356 *--------------------------------------------------------------------------- 1357 * 1358 * TkQueueEventForAllChildren -- 1359 * 1360 * Given an XEvent, recursively queue the event for this window and 1361 * all non-toplevel children of the given window. 1362 * 1363 * Results: 1364 * None. 1365 * 1366 * Side effects: 1367 * Events queued. 1368 * 1369 *--------------------------------------------------------------------------- 1370 */ 1371 1372void 1373TkQueueEventForAllChildren(winPtr, eventPtr) 1374 TkWindow *winPtr; /* Window to which event is sent. */ 1375 XEvent *eventPtr; /* The event to be sent. */ 1376{ 1377 TkWindow *childPtr; 1378 1379 if (!Tk_IsMapped(winPtr)) { 1380 return; 1381 } 1382 1383 eventPtr->xany.window = winPtr->window; 1384 Tk_QueueWindowEvent(eventPtr, TCL_QUEUE_TAIL); 1385 1386 childPtr = winPtr->childList; 1387 while (childPtr != NULL) { 1388 if (!Tk_TopWinHierarchy(childPtr)) { 1389 TkQueueEventForAllChildren(childPtr, eventPtr); 1390 } 1391 childPtr = childPtr->nextPtr; 1392 } 1393} 1394 1395/* 1396 *---------------------------------------------------------------------- 1397 * 1398 * WindowEventProc -- 1399 * 1400 * This procedure is called by Tcl_DoOneEvent when a window event 1401 * reaches the front of the event queue. This procedure is responsible 1402 * for actually handling the event. 1403 * 1404 * Results: 1405 * Returns 1 if the event was handled, meaning it should be removed 1406 * from the queue. Returns 0 if the event was not handled, meaning 1407 * it should stay on the queue. The event isn't handled if the 1408 * TCL_WINDOW_EVENTS bit isn't set in flags, if a restrict proc 1409 * prevents the event from being handled. 1410 * 1411 * Side effects: 1412 * Whatever the event handlers for the event do. 1413 * 1414 *---------------------------------------------------------------------- 1415 */ 1416 1417static int 1418WindowEventProc(evPtr, flags) 1419 Tcl_Event *evPtr; /* Event to service. */ 1420 int flags; /* Flags that indicate what events to 1421 * handle, such as TCL_WINDOW_EVENTS. */ 1422{ 1423 TkWindowEvent *wevPtr = (TkWindowEvent *) evPtr; 1424 Tk_RestrictAction result; 1425 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 1426 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 1427 1428 if (!(flags & TCL_WINDOW_EVENTS)) { 1429 return 0; 1430 } 1431 if (tsdPtr->restrictProc != NULL) { 1432 result = (*tsdPtr->restrictProc)(tsdPtr->restrictArg, &wevPtr->event); 1433 if (result != TK_PROCESS_EVENT) { 1434 if (result == TK_DEFER_EVENT) { 1435 return 0; 1436 } else { 1437 /* 1438 * TK_DELETE_EVENT: return and say we processed the event, 1439 * even though we didn't do anything at all. 1440 */ 1441 return 1; 1442 } 1443 } 1444 } 1445 Tk_HandleEvent(&wevPtr->event); 1446 return 1; 1447} 1448 1449/* 1450 *---------------------------------------------------------------------- 1451 * 1452 * DelayedMotionProc -- 1453 * 1454 * This procedure is invoked as an idle handler when a mouse motion 1455 * event has been delayed. It queues the delayed event so that it 1456 * will finally be serviced. 1457 * 1458 * Results: 1459 * None. 1460 * 1461 * Side effects: 1462 * The delayed mouse motion event gets added to the Tcl event 1463 * queue for servicing. 1464 * 1465 *---------------------------------------------------------------------- 1466 */ 1467 1468static void 1469DelayedMotionProc(clientData) 1470 ClientData clientData; /* Pointer to display containing a delayed 1471 * motion event to be serviced. */ 1472{ 1473 TkDisplay *dispPtr = (TkDisplay *) clientData; 1474 1475 if (dispPtr->delayedMotionPtr == NULL) { 1476 panic("DelayedMotionProc found no delayed mouse motion event"); 1477 } 1478 Tcl_QueueEvent(&dispPtr->delayedMotionPtr->header, TCL_QUEUE_TAIL); 1479 dispPtr->delayedMotionPtr = NULL; 1480} 1481 1482/* 1483 *-------------------------------------------------------------- 1484 * 1485 * Tk_MainLoop -- 1486 * 1487 * Call Tcl_DoOneEvent over and over again in an infinite 1488 * loop as long as there exist any main windows. 1489 * 1490 * Results: 1491 * None. 1492 * 1493 * Side effects: 1494 * Arbitrary; depends on handlers for events. 1495 * 1496 *-------------------------------------------------------------- 1497 */ 1498 1499void 1500Tk_MainLoop() 1501{ 1502 while (Tk_GetNumMainWindows() > 0) { 1503 Tcl_DoOneEvent(0); 1504 } 1505} 1506