1/* 2 * tkBind.c -- 3 * 4 * This file provides functions that associate Tcl commands with X events 5 * or sequences of X events. 6 * 7 * Copyright (c) 1989-1994 The Regents of the University of California. 8 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 9 * Copyright (c) 1998 by Scriptics Corporation. 10 * 11 * See the file "license.terms" for information on usage and redistribution of 12 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 * 14 * RCS: @(#) $Id$ 15 */ 16 17#include "tkInt.h" 18 19#ifdef __WIN32__ 20#include "tkWinInt.h" 21#endif 22 23#if !(defined(__WIN32__) || defined(MAC_OSX_TK)) /* UNIX */ 24#include "tkUnixInt.h" 25#endif 26 27/* 28 * File structure: 29 * 30 * Structure definitions and static variables. 31 * 32 * Init/Free this package. 33 * 34 * Tcl "bind" command (actually located in tkCmds.c). 35 * "bind" command implementation. 36 * "bind" implementation helpers. 37 * 38 * Tcl "event" command. 39 * "event" command implementation. 40 * "event" implementation helpers. 41 * 42 * Package-specific common helpers. 43 * 44 * Non-package-specific helpers. 45 */ 46 47/* 48 * The following union is used to hold the detail information from an XEvent 49 * (including Tk's XVirtualEvent extension). 50 */ 51 52typedef union { 53 KeySym keySym; /* KeySym that corresponds to xkey.keycode. */ 54 int button; /* Button that was pressed (xbutton.button). */ 55 Tk_Uid name; /* Tk_Uid of virtual event. */ 56 ClientData clientData; /* Used when type of Detail is unknown, and to 57 * ensure that all bytes of Detail are 58 * initialized when this structure is used in 59 * a hash key. */ 60} Detail; 61 62/* 63 * The structure below represents a binding table. A binding table represents 64 * a domain in which event bindings may occur. It includes a space of objects 65 * relative to which events occur (usually windows, but not always), a history 66 * of recent events in the domain, and a set of mappings that associate 67 * particular Tcl commands with sequences of events in the domain. Multiple 68 * binding tables may exist at once, either because there are multiple 69 * applications open, or because there are multiple domains within an 70 * application with separate event bindings for each (for example, each canvas 71 * widget has a separate binding table for associating events with the items 72 * in the canvas). 73 * 74 * Note: it is probably a bad idea to reduce EVENT_BUFFER_SIZE much below 30. 75 * To see this, consider a triple mouse button click while the Shift key is 76 * down (and auto-repeating). There may be as many as 3 auto-repeat events 77 * after each mouse button press or release (see the first large comment block 78 * within Tk_BindEvent for more on this), for a total of 20 events to cover 79 * the three button presses and two intervening releases. If you reduce 80 * EVENT_BUFFER_SIZE too much, shift multi-clicks will be lost. 81 */ 82 83#define EVENT_BUFFER_SIZE 30 84typedef struct BindingTable { 85 XEvent eventRing[EVENT_BUFFER_SIZE]; 86 /* Circular queue of recent events (higher 87 * indices are for more recent events). */ 88 Detail detailRing[EVENT_BUFFER_SIZE]; 89 /* "Detail" information (keySym, button, 90 * Tk_Uid, or 0) for each entry in 91 * eventRing. */ 92 int curEvent; /* Index in eventRing of most recent event. 93 * Newer events have higher indices. */ 94 Tcl_HashTable patternTable; /* Used to map from an event to a list of 95 * patterns that may match that event. Keys 96 * are PatternTableKey structs, values are 97 * (PatSeq *). */ 98 Tcl_HashTable objectTable; /* Used to map from an object to a list of 99 * patterns associated with that object. Keys 100 * are ClientData, values are (PatSeq *). */ 101 Tcl_Interp *interp; /* Interpreter in which commands are 102 * executed. */ 103} BindingTable; 104 105/* 106 * The following structure represents virtual event table. A virtual event 107 * table provides a way to map from platform-specific physical events such as 108 * button clicks or key presses to virtual events such as <<Paste>>, 109 * <<Close>>, or <<ScrollWindow>>. 110 * 111 * A virtual event is usually never part of the event stream, but instead is 112 * synthesized inline by matching low-level events. However, a virtual event 113 * may be generated by platform-specific code or by Tcl scripts. In that case, 114 * no lookup of the virtual event will need to be done using this table, 115 * because the virtual event is actually in the event stream. 116 */ 117 118typedef struct VirtualEventTable { 119 Tcl_HashTable patternTable; /* Used to map from a physical event to a list 120 * of patterns that may match that event. Keys 121 * are PatternTableKey structs, values are 122 * (PatSeq *). */ 123 Tcl_HashTable nameTable; /* Used to map a virtual event name to the 124 * array of physical events that can trigger 125 * it. Keys are the Tk_Uid names of the 126 * virtual events, values are PhysicalsOwned 127 * structs. */ 128} VirtualEventTable; 129 130/* 131 * The following structure is used as a key in a patternTable for both binding 132 * tables and a virtual event tables. 133 * 134 * In a binding table, the object field corresponds to the binding tag for the 135 * widget whose bindings are being accessed. 136 * 137 * In a virtual event table, the object field is always NULL. Virtual events 138 * are a global definiton and are not tied to a particular binding tag. 139 * 140 * The same key is used for both types of pattern tables so that the helper 141 * functions that traverse and match patterns will work for both binding 142 * tables and virtual event tables. 143 */ 144 145typedef struct PatternTableKey { 146 ClientData object; /* For binding table, identifies the binding 147 * tag of the object (or class of objects) 148 * relative to which the event occurred. For 149 * virtual event table, always NULL. */ 150 int type; /* Type of event (from X). */ 151 Detail detail; /* Additional information, such as keysym, 152 * button, Tk_Uid, or 0 if nothing 153 * additional. */ 154} PatternTableKey; 155 156/* 157 * The following structure defines a pattern, which is matched against X 158 * events as part of the process of converting X events into Tcl commands. 159 */ 160 161typedef struct Pattern { 162 int eventType; /* Type of X event, e.g. ButtonPress. */ 163 int needMods; /* Mask of modifiers that must be present (0 164 * means no modifiers are required). */ 165 Detail detail; /* Additional information that must match 166 * event. Normally this is 0, meaning no 167 * additional information must match. For 168 * KeyPress and KeyRelease events, a keySym 169 * may be specified to select a particular 170 * keystroke (0 means any keystrokes). For 171 * button events, specifies a particular 172 * button (0 means any buttons are OK). For 173 * virtual events, specifies the Tk_Uid of the 174 * virtual event name (never 0). */ 175} Pattern; 176 177/* 178 * The following structure defines a pattern sequence, which consists of one 179 * or more patterns. In order to trigger, a pattern sequence must match the 180 * most recent X events (first pattern to most recent event, next pattern to 181 * next event, and so on). It is used as the hash value in a patternTable for 182 * both binding tables and virtual event tables. 183 * 184 * In a binding table, it is the sequence of physical events that make up a 185 * binding for an object. 186 * 187 * In a virtual event table, it is the sequence of physical events that define 188 * a virtual event. 189 * 190 * The same structure is used for both types of pattern tables so that the 191 * helper functions that traverse and match patterns will work for both 192 * binding tables and virtual event tables. 193 */ 194 195typedef struct PatSeq { 196 int numPats; /* Number of patterns in sequence (usually 197 * 1). */ 198 TkBindEvalProc *eventProc; /* The function that will be invoked on the 199 * clientData when this pattern sequence 200 * matches. */ 201 TkBindFreeProc *freeProc; /* The function that will be invoked to 202 * release the clientData when this pattern 203 * sequence is freed. */ 204 ClientData clientData; /* Arbitray data passed to eventProc and 205 * freeProc when sequence matches. */ 206 int flags; /* Miscellaneous flag values; see below for 207 * definitions. */ 208 int refCount; /* Number of times that this binding is in the 209 * midst of executing. If greater than 1, then 210 * a recursive invocation is happening. Only 211 * when this is zero can the binding actually 212 * be freed. */ 213 struct PatSeq *nextSeqPtr; /* Next in list of all pattern sequences that 214 * have the same initial pattern. NULL means 215 * end of list. */ 216 Tcl_HashEntry *hPtr; /* Pointer to hash table entry for the initial 217 * pattern. This is the head of the list of 218 * which nextSeqPtr forms a part. */ 219 struct VirtualOwners *voPtr;/* In a binding table, always NULL. In a 220 * virtual event table, identifies the array 221 * of virtual events that can be triggered by 222 * this event. */ 223 struct PatSeq *nextObjPtr; /* In a binding table, next in list of all 224 * pattern sequences for the same object (NULL 225 * for end of list). Needed to implement 226 * Tk_DeleteAllBindings. In a virtual event 227 * table, always NULL. */ 228 Pattern pats[1]; /* Array of "numPats" patterns. Only one 229 * element is declared here but in actuality 230 * enough space will be allocated for 231 * "numPats" patterns. To match, pats[0] must 232 * match event n, pats[1] must match event 233 * n-1, etc. */ 234} PatSeq; 235 236/* 237 * Flag values for PatSeq structures: 238 * 239 * PAT_NEARBY 1 means that all of the events matching this sequence 240 * must occur with nearby X and Y mouse coordinates and 241 * close in time. This is typically used to restrict 242 * multiple button presses. 243 * MARKED_DELETED 1 means that this binding has been marked as deleted 244 * and removed from the binding table, but its memory 245 * could not be released because it was already queued 246 * for execution. When the binding is actually about to 247 * be executed, this flag will be checked and the binding 248 * skipped if set. 249 */ 250 251#define PAT_NEARBY 0x1 252#define MARKED_DELETED 0x2 253 254/* 255 * Constants that define how close together two events must be in milliseconds 256 * or pixels to meet the PAT_NEARBY constraint: 257 */ 258 259#define NEARBY_PIXELS 5 260#define NEARBY_MS 500 261 262/* 263 * The following structure keeps track of all the virtual events that are 264 * associated with a particular physical event. It is pointed to by the voPtr 265 * field in a PatSeq in the patternTable of a virtual event table. 266 */ 267 268typedef struct VirtualOwners { 269 int numOwners; /* Number of virtual events to trigger. */ 270 Tcl_HashEntry *owners[1]; /* Array of pointers to entries in nameTable. 271 * Enough space will actually be allocated for 272 * numOwners hash entries. */ 273} VirtualOwners; 274 275/* 276 * The following structure is used in the nameTable of a virtual event table 277 * to associate a virtual event with all the physical events that can trigger 278 * it. 279 */ 280typedef struct PhysicalsOwned { 281 int numOwned; /* Number of physical events owned. */ 282 PatSeq *patSeqs[1]; /* Array of pointers to physical event 283 * patterns. Enough space will actually be 284 * allocated to hold numOwned. */ 285} PhysicalsOwned; 286 287/* 288 * One of the following structures exists for each interpreter. This structure 289 * keeps track of the current display and screen in the interpreter, so that a 290 * script can be invoked whenever the display/screen changes (the script does 291 * things like point tk::Priv at a display-specific structure). 292 */ 293 294typedef struct { 295 TkDisplay *curDispPtr; /* Display for last binding command invoked in 296 * this application. */ 297 int curScreenIndex; /* Index of screen for last binding command */ 298 int bindingDepth; /* Number of active instances of Tk_BindEvent 299 * in this application. */ 300} ScreenInfo; 301 302/* 303 * The following structure is used to keep track of all the C bindings that 304 * are awaiting invocation and whether the window they refer to has been 305 * destroyed. If the window is destroyed, then all pending callbacks for that 306 * window will be cancelled. The Tcl bindings will still all be invoked, 307 * however. 308 */ 309 310typedef struct PendingBinding { 311 struct PendingBinding *nextPtr; 312 /* Next in chain of pending bindings, in case 313 * a recursive binding evaluation is in 314 * progress. */ 315 Tk_Window tkwin; /* The window that the following bindings 316 * depend upon. */ 317 int deleted; /* Set to non-zero by window cleanup code if 318 * tkwin is deleted. */ 319 PatSeq *matchArray[5]; /* Array of pending C bindings. The actual 320 * size of this depends on how many C bindings 321 * matched the event passed to Tk_BindEvent. 322 * THIS FIELD MUST BE THE LAST IN THE 323 * STRUCTURE. */ 324} PendingBinding; 325 326/* 327 * The following structure keeps track of all the information local to the 328 * binding package on a per interpreter basis. 329 */ 330 331typedef struct BindInfo { 332 VirtualEventTable virtualEventTable; 333 /* The virtual events that exist in this 334 * interpreter. */ 335 ScreenInfo screenInfo; /* Keeps track of the current display and 336 * screen, so it can be restored after a 337 * binding has executed. */ 338 PendingBinding *pendingList;/* The list of pending C bindings, kept in 339 * case a C or Tcl binding causes the target 340 * window to be deleted. */ 341 int deleted; /* 1 the application has been deleted but the 342 * structure has been preserved. */ 343} BindInfo; 344 345/* 346 * In X11R4 and earlier versions, XStringToKeysym is ridiculously slow. The 347 * data structure and hash table below, along with the code that uses them, 348 * implement a fast mapping from strings to keysyms. In X11R5 and later 349 * releases XStringToKeysym is plenty fast so this stuff isn't needed. The 350 * #define REDO_KEYSYM_LOOKUP is normally undefined, so that XStringToKeysym 351 * gets used. It can be set in the Makefile to enable the use of the hash 352 * table below. 353 */ 354 355#ifdef REDO_KEYSYM_LOOKUP 356typedef struct { 357 char *name; /* Name of keysym. */ 358 KeySym value; /* Numeric identifier for keysym. */ 359} KeySymInfo; 360static KeySymInfo keyArray[] = { 361#ifndef lint 362#include "ks_names.h" 363#endif 364 {NULL, 0} 365}; 366static Tcl_HashTable keySymTable; /* keyArray hashed by keysym value. */ 367static Tcl_HashTable nameTable; /* keyArray hashed by keysym name. */ 368#endif /* REDO_KEYSYM_LOOKUP */ 369 370/* 371 * Set to non-zero when the package-wide static variables have been 372 * initialized. 373 */ 374 375static int initialized = 0; 376TCL_DECLARE_MUTEX(bindMutex) 377 378/* 379 * A hash table is kept to map from the string names of event modifiers to 380 * information about those modifiers. The structure for storing this 381 * information, and the hash table built at initialization time, are defined 382 * below. 383 */ 384 385typedef struct { 386 char *name; /* Name of modifier. */ 387 int mask; /* Button/modifier mask value, such as 388 * Button1Mask. */ 389 int flags; /* Various flags; see below for 390 * definitions. */ 391} ModInfo; 392 393/* 394 * Flags for ModInfo structures: 395 * 396 * DOUBLE - Non-zero means duplicate this event, 397 * e.g. for double-clicks. 398 * TRIPLE - Non-zero means triplicate this event, 399 * e.g. for triple-clicks. 400 * QUADRUPLE - Non-zero means quadruple this event, 401 * e.g. for 4-fold-clicks. 402 * MULT_CLICKS - Combination of all of above. 403 */ 404 405#define DOUBLE 1 406#define TRIPLE 2 407#define QUADRUPLE 4 408#define MULT_CLICKS 7 409 410static ModInfo modArray[] = { 411 {"Control", ControlMask, 0}, 412 {"Shift", ShiftMask, 0}, 413 {"Lock", LockMask, 0}, 414 {"Meta", META_MASK, 0}, 415 {"M", META_MASK, 0}, 416 {"Alt", ALT_MASK, 0}, 417 {"Extended", EXTENDED_MASK, 0}, 418 {"B1", Button1Mask, 0}, 419 {"Button1", Button1Mask, 0}, 420 {"B2", Button2Mask, 0}, 421 {"Button2", Button2Mask, 0}, 422 {"B3", Button3Mask, 0}, 423 {"Button3", Button3Mask, 0}, 424 {"B4", Button4Mask, 0}, 425 {"Button4", Button4Mask, 0}, 426 {"B5", Button5Mask, 0}, 427 {"Button5", Button5Mask, 0}, 428 {"Mod1", Mod1Mask, 0}, 429 {"M1", Mod1Mask, 0}, 430 {"Command", Mod1Mask, 0}, 431 {"Mod2", Mod2Mask, 0}, 432 {"M2", Mod2Mask, 0}, 433 {"Option", Mod2Mask, 0}, 434 {"Mod3", Mod3Mask, 0}, 435 {"M3", Mod3Mask, 0}, 436 {"Mod4", Mod4Mask, 0}, 437 {"M4", Mod4Mask, 0}, 438 {"Mod5", Mod5Mask, 0}, 439 {"M5", Mod5Mask, 0}, 440 {"Double", 0, DOUBLE}, 441 {"Triple", 0, TRIPLE}, 442 {"Quadruple", 0, QUADRUPLE}, 443 {"Any", 0, 0}, /* Ignored: historical relic */ 444 {NULL, 0, 0} 445}; 446static Tcl_HashTable modTable; 447 448/* 449 * This module also keeps a hash table mapping from event names to information 450 * about those events. The structure, an array to use to initialize the hash 451 * table, and the hash table are all defined below. 452 */ 453 454typedef struct { 455 char *name; /* Name of event. */ 456 int type; /* Event type for X, such as ButtonPress. */ 457 int eventMask; /* Mask bits (for XSelectInput) for this event 458 * type. */ 459} EventInfo; 460 461/* 462 * Note: some of the masks below are an OR-ed combination of several masks. 463 * This is necessary because X doesn't report up events unless you also ask 464 * for down events. Also, X doesn't report button state in motion events 465 * unless you've asked about button events. 466 */ 467 468static EventInfo eventArray[] = { 469 {"Key", KeyPress, KeyPressMask}, 470 {"KeyPress", KeyPress, KeyPressMask}, 471 {"KeyRelease", KeyRelease, KeyPressMask|KeyReleaseMask}, 472 {"Button", ButtonPress, ButtonPressMask}, 473 {"ButtonPress", ButtonPress, ButtonPressMask}, 474 {"ButtonRelease", ButtonRelease, 475 ButtonPressMask|ButtonReleaseMask}, 476 {"Motion", MotionNotify, 477 ButtonPressMask|PointerMotionMask}, 478 {"Enter", EnterNotify, EnterWindowMask}, 479 {"Leave", LeaveNotify, LeaveWindowMask}, 480 {"FocusIn", FocusIn, FocusChangeMask}, 481 {"FocusOut", FocusOut, FocusChangeMask}, 482 {"Expose", Expose, ExposureMask}, 483 {"Visibility", VisibilityNotify, VisibilityChangeMask}, 484 {"Destroy", DestroyNotify, StructureNotifyMask}, 485 {"Unmap", UnmapNotify, StructureNotifyMask}, 486 {"Map", MapNotify, StructureNotifyMask}, 487 {"Reparent", ReparentNotify, StructureNotifyMask}, 488 {"Configure", ConfigureNotify, StructureNotifyMask}, 489 {"Gravity", GravityNotify, StructureNotifyMask}, 490 {"Circulate", CirculateNotify, StructureNotifyMask}, 491 {"Property", PropertyNotify, PropertyChangeMask}, 492 {"Colormap", ColormapNotify, ColormapChangeMask}, 493 {"Activate", ActivateNotify, ActivateMask}, 494 {"Deactivate", DeactivateNotify, ActivateMask}, 495 {"MouseWheel", MouseWheelEvent, MouseWheelMask}, 496 {"CirculateRequest", CirculateRequest, SubstructureRedirectMask}, 497 {"ConfigureRequest", ConfigureRequest, SubstructureRedirectMask}, 498 {"Create", CreateNotify, SubstructureNotifyMask}, 499 {"MapRequest", MapRequest, SubstructureRedirectMask}, 500 {"ResizeRequest", ResizeRequest, ResizeRedirectMask}, 501 {NULL, 0, 0} 502}; 503static Tcl_HashTable eventTable; 504 505/* 506 * The defines and table below are used to classify events into various 507 * groups. The reason for this is that logically identical fields (e.g. 508 * "state") appear at different places in different types of events. The 509 * classification masks can be used to figure out quickly where to extract 510 * information from events. 511 */ 512 513#define KEY 0x1 514#define BUTTON 0x2 515#define MOTION 0x4 516#define CROSSING 0x8 517#define FOCUS 0x10 518#define EXPOSE 0x20 519#define VISIBILITY 0x40 520#define CREATE 0x80 521#define DESTROY 0x100 522#define UNMAP 0x200 523#define MAP 0x400 524#define REPARENT 0x800 525#define CONFIG 0x1000 526#define GRAVITY 0x2000 527#define CIRC 0x4000 528#define PROP 0x8000 529#define COLORMAP 0x10000 530#define VIRTUAL 0x20000 531#define ACTIVATE 0x40000 532#define MAPREQ 0x80000 533#define CONFIGREQ 0x100000 534#define RESIZEREQ 0x200000 535#define CIRCREQ 0x400000 536 537#define KEY_BUTTON_MOTION_VIRTUAL (KEY|BUTTON|MOTION|VIRTUAL) 538#define KEY_BUTTON_MOTION_CROSSING (KEY|BUTTON|MOTION|VIRTUAL|CROSSING) 539 540static int flagArray[TK_LASTEVENT] = { 541 /* Not used */ 0, 542 /* Not used */ 0, 543 /* KeyPress */ KEY, 544 /* KeyRelease */ KEY, 545 /* ButtonPress */ BUTTON, 546 /* ButtonRelease */ BUTTON, 547 /* MotionNotify */ MOTION, 548 /* EnterNotify */ CROSSING, 549 /* LeaveNotify */ CROSSING, 550 /* FocusIn */ FOCUS, 551 /* FocusOut */ FOCUS, 552 /* KeymapNotify */ 0, 553 /* Expose */ EXPOSE, 554 /* GraphicsExpose */ EXPOSE, 555 /* NoExpose */ 0, 556 /* VisibilityNotify */ VISIBILITY, 557 /* CreateNotify */ CREATE, 558 /* DestroyNotify */ DESTROY, 559 /* UnmapNotify */ UNMAP, 560 /* MapNotify */ MAP, 561 /* MapRequest */ MAPREQ, 562 /* ReparentNotify */ REPARENT, 563 /* ConfigureNotify */ CONFIG, 564 /* ConfigureRequest */ CONFIGREQ, 565 /* GravityNotify */ GRAVITY, 566 /* ResizeRequest */ RESIZEREQ, 567 /* CirculateNotify */ CIRC, 568 /* CirculateRequest */ 0, 569 /* PropertyNotify */ PROP, 570 /* SelectionClear */ 0, 571 /* SelectionRequest */ 0, 572 /* SelectionNotify */ 0, 573 /* ColormapNotify */ COLORMAP, 574 /* ClientMessage */ 0, 575 /* MappingNotify */ 0, 576 /* VirtualEvent */ VIRTUAL, 577 /* Activate */ ACTIVATE, 578 /* Deactivate */ ACTIVATE, 579 /* MouseWheel */ KEY 580}; 581 582/* 583 * The following table is used to map between the location where an generated 584 * event should be queued and the string used to specify the location. 585 */ 586 587static const TkStateMap queuePosition[] = { 588 {-1, "now"}, 589 {TCL_QUEUE_HEAD, "head"}, 590 {TCL_QUEUE_MARK, "mark"}, 591 {TCL_QUEUE_TAIL, "tail"}, 592 {-2, NULL} 593}; 594 595/* 596 * The following tables are used as a two-way map between X's internal numeric 597 * values for fields in an XEvent and the strings used in Tcl. The tables are 598 * used both when constructing an XEvent from user input and when providing 599 * data from an XEvent to the user. 600 */ 601 602static const TkStateMap notifyMode[] = { 603 {NotifyNormal, "NotifyNormal"}, 604 {NotifyGrab, "NotifyGrab"}, 605 {NotifyUngrab, "NotifyUngrab"}, 606 {NotifyWhileGrabbed, "NotifyWhileGrabbed"}, 607 {-1, NULL} 608}; 609 610static const TkStateMap notifyDetail[] = { 611 {NotifyAncestor, "NotifyAncestor"}, 612 {NotifyVirtual, "NotifyVirtual"}, 613 {NotifyInferior, "NotifyInferior"}, 614 {NotifyNonlinear, "NotifyNonlinear"}, 615 {NotifyNonlinearVirtual, "NotifyNonlinearVirtual"}, 616 {NotifyPointer, "NotifyPointer"}, 617 {NotifyPointerRoot, "NotifyPointerRoot"}, 618 {NotifyDetailNone, "NotifyDetailNone"}, 619 {-1, NULL} 620}; 621 622static const TkStateMap circPlace[] = { 623 {PlaceOnTop, "PlaceOnTop"}, 624 {PlaceOnBottom, "PlaceOnBottom"}, 625 {-1, NULL} 626}; 627 628static const TkStateMap visNotify[] = { 629 {VisibilityUnobscured, "VisibilityUnobscured"}, 630 {VisibilityPartiallyObscured, "VisibilityPartiallyObscured"}, 631 {VisibilityFullyObscured, "VisibilityFullyObscured"}, 632 {-1, NULL} 633}; 634 635static const TkStateMap configureRequestDetail[] = { 636 {None, "None"}, 637 {Above, "Above"}, 638 {Below, "Below"}, 639 {BottomIf, "BottomIf"}, 640 {TopIf, "TopIf"}, 641 {Opposite, "Opposite"}, 642 {-1, NULL} 643}; 644 645static const TkStateMap propNotify[] = { 646 {PropertyNewValue, "NewValue"}, 647 {PropertyDelete, "Delete"}, 648 {-1, NULL} 649}; 650 651/* 652 * Prototypes for local functions defined in this file: 653 */ 654 655static void ChangeScreen(Tcl_Interp *interp, char *dispName, 656 int screenIndex); 657static int CreateVirtualEvent(Tcl_Interp *interp, 658 VirtualEventTable *vetPtr, char *virtString, 659 char *eventString); 660static int DeleteVirtualEvent(Tcl_Interp *interp, 661 VirtualEventTable *vetPtr, char *virtString, 662 char *eventString); 663static void DeleteVirtualEventTable(VirtualEventTable *vetPtr); 664static void ExpandPercents(TkWindow *winPtr, const char *before, 665 XEvent *eventPtr,KeySym keySym,Tcl_DString *dsPtr); 666static void FreeTclBinding(ClientData clientData); 667static PatSeq * FindSequence(Tcl_Interp *interp, 668 Tcl_HashTable *patternTablePtr, ClientData object, 669 const char *eventString, int create, 670 int allowVirtual, unsigned long *maskPtr); 671static void GetAllVirtualEvents(Tcl_Interp *interp, 672 VirtualEventTable *vetPtr); 673static char * GetField(char *p, char *copy, int size); 674static void GetPatternString(PatSeq *psPtr, Tcl_DString *dsPtr); 675static int GetVirtualEvent(Tcl_Interp *interp, 676 VirtualEventTable *vetPtr, char *virtString); 677static Tk_Uid GetVirtualEventUid(Tcl_Interp *interp, 678 char *virtString); 679static int HandleEventGenerate(Tcl_Interp *interp, Tk_Window main, 680 int objc, Tcl_Obj *const objv[]); 681static void InitVirtualEventTable(VirtualEventTable *vetPtr); 682static PatSeq * MatchPatterns(TkDisplay *dispPtr, 683 BindingTable *bindPtr, PatSeq *psPtr, 684 PatSeq *bestPtr, ClientData *objectPtr, 685 PatSeq **sourcePtrPtr); 686static int NameToWindow(Tcl_Interp *interp, Tk_Window main, 687 Tcl_Obj *objPtr, Tk_Window *tkwinPtr); 688static int ParseEventDescription(Tcl_Interp *interp, 689 const char **eventStringPtr, Pattern *patPtr, 690 unsigned long *eventMaskPtr); 691static void DoWarp(ClientData clientData); 692 693/* 694 * The following define is used as a short circuit for the callback function 695 * to evaluate a TclBinding. The actual evaluation of the binding is handled 696 * inline, because special things have to be done with a Tcl binding before 697 * evaluation time. 698 */ 699 700#define EvalTclBinding ((TkBindEvalProc *) 1) 701 702/* 703 *--------------------------------------------------------------------------- 704 * 705 * TkBindInit -- 706 * 707 * This function is called when an application is created. It initializes 708 * all the structures used by bindings and virtual events. It must be 709 * called before any other functions in this file are called. 710 * 711 * Results: 712 * None. 713 * 714 * Side effects: 715 * Memory allocated. 716 * 717 *--------------------------------------------------------------------------- 718 */ 719 720void 721TkBindInit( 722 TkMainInfo *mainPtr) /* The newly created application. */ 723{ 724 BindInfo *bindInfoPtr; 725 726 if (sizeof(XEvent) < sizeof(XVirtualEvent)) { 727 Tcl_Panic("TkBindInit: virtual events can't be supported"); 728 } 729 730 /* 731 * Initialize the static data structures used by the binding package. They 732 * are only initialized once, no matter how many interps are created. 733 */ 734 735 if (!initialized) { 736 Tcl_MutexLock(&bindMutex); 737 if (!initialized) { 738 Tcl_HashEntry *hPtr; 739 ModInfo *modPtr; 740 EventInfo *eiPtr; 741 int newEntry; 742#ifdef REDO_KEYSYM_LOOKUP 743 KeySymInfo *kPtr; 744 745 Tcl_InitHashTable(&keySymTable, TCL_STRING_KEYS); 746 Tcl_InitHashTable(&nameTable, TCL_ONE_WORD_KEYS); 747 for (kPtr = keyArray; kPtr->name != NULL; kPtr++) { 748 hPtr = Tcl_CreateHashEntry(&keySymTable, kPtr->name, &newEntry); 749 Tcl_SetHashValue(hPtr, kPtr->value); 750 hPtr = Tcl_CreateHashEntry(&nameTable, (char *) kPtr->value, 751 &newEntry); 752 if (newEntry) { 753 Tcl_SetHashValue(hPtr, kPtr->name); 754 } 755 } 756#endif /* REDO_KEYSYM_LOOKUP */ 757 758 Tcl_InitHashTable(&modTable, TCL_STRING_KEYS); 759 for (modPtr = modArray; modPtr->name != NULL; modPtr++) { 760 hPtr = Tcl_CreateHashEntry(&modTable, modPtr->name, &newEntry); 761 Tcl_SetHashValue(hPtr, modPtr); 762 } 763 764 Tcl_InitHashTable(&eventTable, TCL_STRING_KEYS); 765 for (eiPtr = eventArray; eiPtr->name != NULL; eiPtr++) { 766 hPtr = Tcl_CreateHashEntry(&eventTable, eiPtr->name, &newEntry); 767 Tcl_SetHashValue(hPtr, eiPtr); 768 } 769 initialized = 1; 770 } 771 Tcl_MutexUnlock(&bindMutex); 772 } 773 774 mainPtr->bindingTable = Tk_CreateBindingTable(mainPtr->interp); 775 776 bindInfoPtr = (BindInfo *) ckalloc(sizeof(BindInfo)); 777 InitVirtualEventTable(&bindInfoPtr->virtualEventTable); 778 bindInfoPtr->screenInfo.curDispPtr = NULL; 779 bindInfoPtr->screenInfo.curScreenIndex = -1; 780 bindInfoPtr->screenInfo.bindingDepth = 0; 781 bindInfoPtr->pendingList = NULL; 782 bindInfoPtr->deleted = 0; 783 mainPtr->bindInfo = (TkBindInfo) bindInfoPtr; 784 785 TkpInitializeMenuBindings(mainPtr->interp, mainPtr->bindingTable); 786} 787 788/* 789 *--------------------------------------------------------------------------- 790 * 791 * TkBindFree -- 792 * 793 * This function is called when an application is deleted. It deletes all 794 * the structures used by bindings and virtual events. 795 * 796 * Results: 797 * None. 798 * 799 * Side effects: 800 * Memory freed. 801 * 802 *--------------------------------------------------------------------------- 803 */ 804 805void 806TkBindFree( 807 TkMainInfo *mainPtr) /* The newly created application. */ 808{ 809 BindInfo *bindInfoPtr; 810 811 Tk_DeleteBindingTable(mainPtr->bindingTable); 812 mainPtr->bindingTable = NULL; 813 814 bindInfoPtr = (BindInfo *) mainPtr->bindInfo; 815 DeleteVirtualEventTable(&bindInfoPtr->virtualEventTable); 816 bindInfoPtr->deleted = 1; 817 Tcl_EventuallyFree((ClientData) bindInfoPtr, TCL_DYNAMIC); 818 mainPtr->bindInfo = NULL; 819} 820 821/* 822 *-------------------------------------------------------------- 823 * 824 * Tk_CreateBindingTable -- 825 * 826 * Set up a new domain in which event bindings may be created. 827 * 828 * Results: 829 * The return value is a token for the new table, which must be passed to 830 * functions like Tk_CreateBinding. 831 * 832 * Side effects: 833 * Memory is allocated for the new table. 834 * 835 *-------------------------------------------------------------- 836 */ 837 838Tk_BindingTable 839Tk_CreateBindingTable( 840 Tcl_Interp *interp) /* Interpreter to associate with the binding 841 * table: commands are executed in this 842 * interpreter. */ 843{ 844 BindingTable *bindPtr; 845 int i; 846 847 /* 848 * Create and initialize a new binding table. 849 */ 850 851 bindPtr = (BindingTable *) ckalloc(sizeof(BindingTable)); 852 for (i = 0; i < EVENT_BUFFER_SIZE; i++) { 853 bindPtr->eventRing[i].type = -1; 854 } 855 bindPtr->curEvent = 0; 856 Tcl_InitHashTable(&bindPtr->patternTable, 857 sizeof(PatternTableKey)/sizeof(int)); 858 Tcl_InitHashTable(&bindPtr->objectTable, TCL_ONE_WORD_KEYS); 859 bindPtr->interp = interp; 860 return (Tk_BindingTable) bindPtr; 861} 862 863/* 864 *-------------------------------------------------------------- 865 * 866 * Tk_DeleteBindingTable -- 867 * 868 * Destroy a binding table and free up all its memory. The caller should 869 * not use bindingTable again after this function returns. 870 * 871 * Results: 872 * None. 873 * 874 * Side effects: 875 * Memory is freed. 876 * 877 *-------------------------------------------------------------- 878 */ 879 880void 881Tk_DeleteBindingTable( 882 Tk_BindingTable bindingTable) 883 /* Token for the binding table to destroy. */ 884{ 885 BindingTable *bindPtr = (BindingTable *) bindingTable; 886 PatSeq *psPtr, *nextPtr; 887 Tcl_HashEntry *hPtr; 888 Tcl_HashSearch search; 889 890 /* 891 * Find and delete all of the patterns associated with the binding table. 892 */ 893 894 for (hPtr = Tcl_FirstHashEntry(&bindPtr->patternTable, &search); 895 hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { 896 for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); 897 psPtr != NULL; psPtr = nextPtr) { 898 nextPtr = psPtr->nextSeqPtr; 899 psPtr->flags |= MARKED_DELETED; 900 if (psPtr->refCount == 0) { 901 if (psPtr->freeProc != NULL) { 902 (*psPtr->freeProc)(psPtr->clientData); 903 } 904 ckfree((char *) psPtr); 905 } 906 } 907 } 908 909 /* 910 * Clean up the rest of the information associated with the binding table. 911 */ 912 913 Tcl_DeleteHashTable(&bindPtr->patternTable); 914 Tcl_DeleteHashTable(&bindPtr->objectTable); 915 ckfree((char *) bindPtr); 916} 917 918/* 919 *-------------------------------------------------------------- 920 * 921 * Tk_CreateBinding -- 922 * 923 * Add a binding to a binding table, so that future calls to Tk_BindEvent 924 * may execute the command in the binding. 925 * 926 * Results: 927 * The return value is 0 if an error occurred while setting up the 928 * binding. In this case, an error message will be left in the interp's 929 * result. If all went well then the return value is a mask of the event 930 * types that must be made available to Tk_BindEvent in order to properly 931 * detect when this binding triggers. This value can be used to determine 932 * what events to select for in a window, for example. 933 * 934 * Side effects: 935 * An existing binding on the same event sequence may be replaced. The 936 * new binding may cause future calls to Tk_BindEvent to behave 937 * differently than they did previously. 938 * 939 *-------------------------------------------------------------- 940 */ 941 942unsigned long 943Tk_CreateBinding( 944 Tcl_Interp *interp, /* Used for error reporting. */ 945 Tk_BindingTable bindingTable, 946 /* Table in which to create binding. */ 947 ClientData object, /* Token for object with which binding is 948 * associated. */ 949 const char *eventString, /* String describing event sequence that 950 * triggers binding. */ 951 const char *command, /* Contains Tcl command to execute when 952 * binding triggers. */ 953 int append) /* 0 means replace any existing binding for 954 * eventString; 1 means append to that 955 * binding. If the existing binding is for a 956 * callback function and not a Tcl command 957 * string, the existing binding will always be 958 * replaced. */ 959{ 960 BindingTable *bindPtr = (BindingTable *) bindingTable; 961 PatSeq *psPtr; 962 unsigned long eventMask; 963 char *newStr, *oldStr; 964 965 if (!*command) { 966 /* Silently ignore empty scripts -- see SF#3006842 */ 967 return 1; 968 } 969 psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString, 970 1, 1, &eventMask); 971 if (psPtr == NULL) { 972 return 0; 973 } 974 if (psPtr->eventProc == NULL) { 975 int isNew; 976 Tcl_HashEntry *hPtr; 977 978 /* 979 * This pattern sequence was just created. Link the pattern into the 980 * list associated with the object, so that if the object goes away, 981 * these bindings will all automatically be deleted. 982 */ 983 984 hPtr = Tcl_CreateHashEntry(&bindPtr->objectTable, (char *) object, 985 &isNew); 986 if (isNew) { 987 psPtr->nextObjPtr = NULL; 988 } else { 989 psPtr->nextObjPtr = (PatSeq *) Tcl_GetHashValue(hPtr); 990 } 991 Tcl_SetHashValue(hPtr, psPtr); 992 } else if (psPtr->eventProc != EvalTclBinding) { 993 /* 994 * Free existing procedural binding. 995 */ 996 997 if (psPtr->freeProc != NULL) { 998 (*psPtr->freeProc)(psPtr->clientData); 999 } 1000 psPtr->clientData = NULL; 1001 append = 0; 1002 } 1003 1004 oldStr = (char *) psPtr->clientData; 1005 if ((append != 0) && (oldStr != NULL)) { 1006 size_t length; 1007 1008 length = strlen(oldStr) + strlen(command) + 2; 1009 newStr = (char *) ckalloc((unsigned) length); 1010 sprintf(newStr, "%s\n%s", oldStr, command); 1011 } else { 1012 newStr = (char *) ckalloc((unsigned) strlen(command) + 1); 1013 strcpy(newStr, command); 1014 } 1015 if (oldStr != NULL) { 1016 ckfree(oldStr); 1017 } 1018 psPtr->eventProc = EvalTclBinding; 1019 psPtr->freeProc = FreeTclBinding; 1020 psPtr->clientData = (ClientData) newStr; 1021 return eventMask; 1022} 1023 1024/* 1025 *--------------------------------------------------------------------------- 1026 * 1027 * TkCreateBindingProcedure -- 1028 * 1029 * Add a C binding to a binding table, so that future calls to 1030 * Tk_BindEvent may callback the function in the binding. 1031 * 1032 * Results: 1033 1034 * The return value is 0 if an error occurred while setting up the 1035 * binding. In this case, an error message will be left in the interp's 1036 * result. If all went well then the return value is a mask of the event 1037 * types that must be made available to Tk_BindEvent in order to properly 1038 * detect when this binding triggers. This value can be used to determine 1039 * what events to select for in a window, for example. 1040 * 1041 * Side effects: 1042 * Any existing binding on the same event sequence will be replaced. 1043 * 1044 *--------------------------------------------------------------------------- 1045 */ 1046 1047unsigned long 1048TkCreateBindingProcedure( 1049 Tcl_Interp *interp, /* Used for error reporting. */ 1050 Tk_BindingTable bindingTable, 1051 /* Table in which to create binding. */ 1052 ClientData object, /* Token for object with which binding is 1053 * associated. */ 1054 const char *eventString, /* String describing event sequence that 1055 * triggers binding. */ 1056 TkBindEvalProc *eventProc, /* Function to invoke when binding triggers. 1057 * Must not be NULL. */ 1058 TkBindFreeProc *freeProc, /* Function to invoke when binding is freed. 1059 * May be NULL for no function. */ 1060 ClientData clientData) /* Arbitrary ClientData to pass to eventProc 1061 * and freeProc. */ 1062{ 1063 BindingTable *bindPtr = (BindingTable *) bindingTable; 1064 PatSeq *psPtr; 1065 unsigned long eventMask; 1066 1067 psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString, 1068 1, 1, &eventMask); 1069 if (psPtr == NULL) { 1070 return 0; 1071 } 1072 if (psPtr->eventProc == NULL) { 1073 int isNew; 1074 Tcl_HashEntry *hPtr; 1075 1076 /* 1077 * This pattern sequence was just created. Link the pattern into the 1078 * list associated with the object, so that if the object goes away, 1079 * these bindings will all automatically be deleted. 1080 */ 1081 1082 hPtr = Tcl_CreateHashEntry(&bindPtr->objectTable, (char *) object, 1083 &isNew); 1084 if (isNew) { 1085 psPtr->nextObjPtr = NULL; 1086 } else { 1087 psPtr->nextObjPtr = (PatSeq *) Tcl_GetHashValue(hPtr); 1088 } 1089 Tcl_SetHashValue(hPtr, psPtr); 1090 } else { 1091 /* 1092 * Free existing callback. 1093 */ 1094 1095 if (psPtr->freeProc != NULL) { 1096 (*psPtr->freeProc)(psPtr->clientData); 1097 } 1098 } 1099 1100 psPtr->eventProc = eventProc; 1101 psPtr->freeProc = freeProc; 1102 psPtr->clientData = clientData; 1103 return eventMask; 1104} 1105 1106/* 1107 *-------------------------------------------------------------- 1108 * 1109 * Tk_DeleteBinding -- 1110 * 1111 * Remove an event binding from a binding table. 1112 * 1113 * Results: 1114 * The result is a standard Tcl return value. If an error occurs then the 1115 * interp's result will contain an error message. 1116 * 1117 * Side effects: 1118 * The binding given by object and eventString is removed from 1119 * bindingTable. 1120 * 1121 *-------------------------------------------------------------- 1122 */ 1123 1124int 1125Tk_DeleteBinding( 1126 Tcl_Interp *interp, /* Used for error reporting. */ 1127 Tk_BindingTable bindingTable, 1128 /* Table in which to delete binding. */ 1129 ClientData object, /* Token for object with which binding is 1130 * associated. */ 1131 const char *eventString) /* String describing event sequence that 1132 * triggers binding. */ 1133{ 1134 BindingTable *bindPtr = (BindingTable *) bindingTable; 1135 PatSeq *psPtr, *prevPtr; 1136 unsigned long eventMask; 1137 Tcl_HashEntry *hPtr; 1138 1139 psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString, 1140 0, 1, &eventMask); 1141 if (psPtr == NULL) { 1142 Tcl_ResetResult(interp); 1143 return TCL_OK; 1144 } 1145 1146 /* 1147 * Unlink the binding from the list for its object, then from the list for 1148 * its pattern. 1149 */ 1150 1151 hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) object); 1152 if (hPtr == NULL) { 1153 Tcl_Panic("Tk_DeleteBinding couldn't find object table entry"); 1154 } 1155 prevPtr = (PatSeq *) Tcl_GetHashValue(hPtr); 1156 if (prevPtr == psPtr) { 1157 Tcl_SetHashValue(hPtr, psPtr->nextObjPtr); 1158 } else { 1159 for ( ; ; prevPtr = prevPtr->nextObjPtr) { 1160 if (prevPtr == NULL) { 1161 Tcl_Panic("Tk_DeleteBinding couldn't find on object list"); 1162 } 1163 if (prevPtr->nextObjPtr == psPtr) { 1164 prevPtr->nextObjPtr = psPtr->nextObjPtr; 1165 break; 1166 } 1167 } 1168 } 1169 prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr); 1170 if (prevPtr == psPtr) { 1171 if (psPtr->nextSeqPtr == NULL) { 1172 Tcl_DeleteHashEntry(psPtr->hPtr); 1173 } else { 1174 Tcl_SetHashValue(psPtr->hPtr, psPtr->nextSeqPtr); 1175 } 1176 } else { 1177 for ( ; ; prevPtr = prevPtr->nextSeqPtr) { 1178 if (prevPtr == NULL) { 1179 Tcl_Panic("Tk_DeleteBinding couldn't find on hash chain"); 1180 } 1181 if (prevPtr->nextSeqPtr == psPtr) { 1182 prevPtr->nextSeqPtr = psPtr->nextSeqPtr; 1183 break; 1184 } 1185 } 1186 } 1187 1188 psPtr->flags |= MARKED_DELETED; 1189 if (psPtr->refCount == 0) { 1190 if (psPtr->freeProc != NULL) { 1191 (*psPtr->freeProc)(psPtr->clientData); 1192 } 1193 ckfree((char *) psPtr); 1194 } 1195 return TCL_OK; 1196} 1197 1198/* 1199 *-------------------------------------------------------------- 1200 * 1201 * Tk_GetBinding -- 1202 * 1203 * Return the command associated with a given event string. 1204 * 1205 * Results: 1206 * The return value is a pointer to the command string associated with 1207 * eventString for object in the domain given by bindingTable. If there 1208 * is no binding for eventString, or if eventString is improperly formed, 1209 * then NULL is returned and an error message is left in the interp's 1210 * result. The return value is semi-static: it will persist until the 1211 * binding is changed or deleted. 1212 * 1213 * Side effects: 1214 * None. 1215 * 1216 *-------------------------------------------------------------- 1217 */ 1218 1219const char * 1220Tk_GetBinding( 1221 Tcl_Interp *interp, /* Interpreter for error reporting. */ 1222 Tk_BindingTable bindingTable, 1223 /* Table in which to look for binding. */ 1224 ClientData object, /* Token for object with which binding is 1225 * associated. */ 1226 const char *eventString) /* String describing event sequence that 1227 * triggers binding. */ 1228{ 1229 BindingTable *bindPtr = (BindingTable *) bindingTable; 1230 PatSeq *psPtr; 1231 unsigned long eventMask; 1232 1233 psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString, 1234 0, 1, &eventMask); 1235 if (psPtr == NULL) { 1236 return NULL; 1237 } 1238 if (psPtr->eventProc == EvalTclBinding) { 1239 return (const char *) psPtr->clientData; 1240 } 1241 return ""; 1242} 1243 1244/* 1245 *-------------------------------------------------------------- 1246 * 1247 * Tk_GetAllBindings -- 1248 * 1249 * Return a list of event strings for all the bindings associated with a 1250 * given object. 1251 * 1252 * Results: 1253 * There is no return value. The interp's result is modified to hold a 1254 * Tcl list with one entry for each binding associated with object in 1255 * bindingTable. Each entry in the list contains the event string 1256 * associated with one binding. 1257 * 1258 * Side effects: 1259 * None. 1260 * 1261 *-------------------------------------------------------------- 1262 */ 1263 1264void 1265Tk_GetAllBindings( 1266 Tcl_Interp *interp, /* Interpreter returning result or error. */ 1267 Tk_BindingTable bindingTable, 1268 /* Table in which to look for bindings. */ 1269 ClientData object) /* Token for object. */ 1270{ 1271 BindingTable *bindPtr = (BindingTable *) bindingTable; 1272 PatSeq *psPtr; 1273 Tcl_HashEntry *hPtr; 1274 Tcl_DString ds; 1275 1276 hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) object); 1277 if (hPtr == NULL) { 1278 return; 1279 } 1280 Tcl_DStringInit(&ds); 1281 for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL; 1282 psPtr = psPtr->nextObjPtr) { 1283 /* 1284 * For each binding, output information about each of the patterns in 1285 * its sequence. 1286 */ 1287 1288 Tcl_DStringSetLength(&ds, 0); 1289 GetPatternString(psPtr, &ds); 1290 Tcl_AppendElement(interp, Tcl_DStringValue(&ds)); 1291 } 1292 Tcl_DStringFree(&ds); 1293} 1294 1295/* 1296 *-------------------------------------------------------------- 1297 * 1298 * Tk_DeleteAllBindings -- 1299 * 1300 * Remove all bindings associated with a given object in a given binding 1301 * table. 1302 * 1303 * Results: 1304 * All bindings associated with object are removed from bindingTable. 1305 * 1306 * Side effects: 1307 * None. 1308 * 1309 *-------------------------------------------------------------- 1310 */ 1311 1312void 1313Tk_DeleteAllBindings( 1314 Tk_BindingTable bindingTable, 1315 /* Table in which to delete bindings. */ 1316 ClientData object) /* Token for object. */ 1317{ 1318 BindingTable *bindPtr = (BindingTable *) bindingTable; 1319 PatSeq *psPtr, *prevPtr; 1320 PatSeq *nextPtr; 1321 Tcl_HashEntry *hPtr; 1322 1323 hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) object); 1324 if (hPtr == NULL) { 1325 return; 1326 } 1327 for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL; 1328 psPtr = nextPtr) { 1329 nextPtr = psPtr->nextObjPtr; 1330 1331 /* 1332 * Be sure to remove each binding from its hash chain in the pattern 1333 * table. If this is the last pattern in the chain, then delete the 1334 * hash entry too. 1335 */ 1336 1337 prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr); 1338 if (prevPtr == psPtr) { 1339 if (psPtr->nextSeqPtr == NULL) { 1340 Tcl_DeleteHashEntry(psPtr->hPtr); 1341 } else { 1342 Tcl_SetHashValue(psPtr->hPtr, psPtr->nextSeqPtr); 1343 } 1344 } else { 1345 for ( ; ; prevPtr = prevPtr->nextSeqPtr) { 1346 if (prevPtr == NULL) { 1347 Tcl_Panic("Tk_DeleteAllBindings couldn't find on hash chain"); 1348 } 1349 if (prevPtr->nextSeqPtr == psPtr) { 1350 prevPtr->nextSeqPtr = psPtr->nextSeqPtr; 1351 break; 1352 } 1353 } 1354 } 1355 psPtr->flags |= MARKED_DELETED; 1356 1357 if (psPtr->refCount == 0) { 1358 if (psPtr->freeProc != NULL) { 1359 (*psPtr->freeProc)(psPtr->clientData); 1360 } 1361 ckfree((char *) psPtr); 1362 } 1363 } 1364 Tcl_DeleteHashEntry(hPtr); 1365} 1366 1367/* 1368 *--------------------------------------------------------------------------- 1369 * 1370 * Tk_BindEvent -- 1371 * 1372 * This function is invoked to process an X event. The event is added to 1373 * those recorded for the binding table. Then each of the objects at 1374 * *objectPtr is checked in order to see if it has a binding that matches 1375 * the recent events. If so, the most specific binding is invoked for 1376 * each object. 1377 * 1378 * Results: 1379 * None. 1380 * 1381 * Side effects: 1382 * Depends on the command associated with the matching binding. 1383 * 1384 * All Tcl bindings scripts for each object are accumulated before the 1385 * first binding is evaluated. If the action of a Tcl binding is to 1386 * change or delete a binding, or delete the window associated with the 1387 * binding, all the original Tcl binding scripts will still fire. 1388 * Contrast this with C binding functions. If a pending C binding (one 1389 * that hasn't fired yet, but is queued to be fired for this window) is 1390 * deleted, it will not be called, and if it is changed, then the new 1391 * binding function will be called. If the window itself is deleted, no 1392 * further C binding functions will be called for this window. When both 1393 * Tcl binding scripts and C binding functions are interleaved, the above 1394 * rules still apply. 1395 * 1396 *--------------------------------------------------------------------------- 1397 */ 1398 1399void 1400Tk_BindEvent( 1401 Tk_BindingTable bindingTable, 1402 /* Table in which to look for bindings. */ 1403 XEvent *eventPtr, /* What actually happened. */ 1404 Tk_Window tkwin, /* Window on display where event occurred 1405 * (needed in order to locate display 1406 * information). */ 1407 int numObjects, /* Number of objects at *objectPtr. */ 1408 ClientData *objectPtr) /* Array of one or more objects to check for a 1409 * matching binding. */ 1410{ 1411 BindingTable *bindPtr; 1412 TkDisplay *dispPtr; 1413 ScreenInfo *screenPtr; 1414 BindInfo *bindInfoPtr; 1415 TkDisplay *oldDispPtr; 1416 XEvent *ringPtr; 1417 PatSeq *vMatchDetailList, *vMatchNoDetailList; 1418 int flags, oldScreen, i, deferModal; 1419 unsigned int matchCount, matchSpace; 1420 Tcl_Interp *interp; 1421 Tcl_DString scripts, savedResult; 1422 Detail detail; 1423 char *p, *end; 1424 PendingBinding staticPending, *pendingPtr; 1425 TkWindow *winPtr = (TkWindow *) tkwin; 1426 PatternTableKey key; 1427 Tk_ClassModalProc *modalProc; 1428 1429 /* 1430 * Ignore events on windows that don't have names: these are windows like 1431 * wrapper windows that shouldn't be visible to the application. 1432 */ 1433 1434 if (winPtr->pathName == NULL) { 1435 return; 1436 } 1437 1438 /* 1439 * Ignore the event completely if it is an Enter, Leave, FocusIn, or 1440 * FocusOut event with detail NotifyInferior. The reason for ignoring 1441 * these events is that we don't want transitions between a window and its 1442 * children to visible to bindings on the parent: this would cause 1443 * problems for mega-widgets, since the internal structure of a 1444 * mega-widget isn't supposed to be visible to people watching the parent. 1445 */ 1446 1447 if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) { 1448 if (eventPtr->xcrossing.detail == NotifyInferior) { 1449 return; 1450 } 1451 } 1452 if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) { 1453 if (eventPtr->xfocus.detail == NotifyInferior) { 1454 return; 1455 } 1456 } 1457 1458 bindPtr = (BindingTable *) bindingTable; 1459 dispPtr = ((TkWindow *) tkwin)->dispPtr; 1460 bindInfoPtr = (BindInfo *) winPtr->mainPtr->bindInfo; 1461 1462 /* 1463 * Add the new event to the ring of saved events for the binding table. 1464 * Two tricky points: 1465 * 1466 * 1. Combine consecutive MotionNotify events. Do this by putting the new 1467 * event *on top* of the previous event. 1468 * 2. If a modifier key is held down, it auto-repeats to generate 1469 * continuous KeyPress and KeyRelease events. These can flush the event 1470 * ring so that valuable information is lost (such as repeated button 1471 * clicks). To handle this, check for the special case of a modifier 1472 * KeyPress arriving when the previous two events are a KeyRelease and 1473 * KeyPress of the same key. If this happens, mark the most recent 1474 * event (the KeyRelease) invalid and put the new event on top of the 1475 * event before that (the KeyPress). 1476 */ 1477 1478 if ((eventPtr->type == MotionNotify) 1479 && (bindPtr->eventRing[bindPtr->curEvent].type == MotionNotify)) { 1480 /* 1481 * Don't advance the ring pointer. 1482 */ 1483 } else if (eventPtr->type == KeyPress) { 1484 int i; 1485 1486 for (i = 0; ; i++) { 1487 if (i >= dispPtr->numModKeyCodes) { 1488 goto advanceRingPointer; 1489 } 1490 if (dispPtr->modKeyCodes[i] == eventPtr->xkey.keycode) { 1491 break; 1492 } 1493 } 1494 ringPtr = &bindPtr->eventRing[bindPtr->curEvent]; 1495 if ((ringPtr->type != KeyRelease) 1496 || (ringPtr->xkey.keycode != eventPtr->xkey.keycode)) { 1497 goto advanceRingPointer; 1498 } 1499 if (bindPtr->curEvent <= 0) { 1500 i = EVENT_BUFFER_SIZE - 1; 1501 } else { 1502 i = bindPtr->curEvent - 1; 1503 } 1504 ringPtr = &bindPtr->eventRing[i]; 1505 if ((ringPtr->type != KeyPress) 1506 || (ringPtr->xkey.keycode != eventPtr->xkey.keycode)) { 1507 goto advanceRingPointer; 1508 } 1509 bindPtr->eventRing[bindPtr->curEvent].type = -1; 1510 bindPtr->curEvent = i; 1511 } else { 1512 1513 advanceRingPointer: 1514 bindPtr->curEvent++; 1515 if (bindPtr->curEvent >= EVENT_BUFFER_SIZE) { 1516 bindPtr->curEvent = 0; 1517 } 1518 } 1519 ringPtr = &bindPtr->eventRing[bindPtr->curEvent]; 1520 memcpy((void *) ringPtr, (void *) eventPtr, sizeof(XEvent)); 1521 detail.clientData = 0; 1522 flags = flagArray[ringPtr->type]; 1523 if (flags & KEY) { 1524 detail.keySym = TkpGetKeySym(dispPtr, ringPtr); 1525 if (detail.keySym == NoSymbol) { 1526 detail.keySym = 0; 1527 } 1528 } else if (flags & BUTTON) { 1529 detail.button = ringPtr->xbutton.button; 1530 } else if (flags & VIRTUAL) { 1531 detail.name = ((XVirtualEvent *) ringPtr)->name; 1532 } 1533 bindPtr->detailRing[bindPtr->curEvent] = detail; 1534 1535 /* 1536 * Find out if there are any virtual events that correspond to this 1537 * physical event (or sequence of physical events). 1538 */ 1539 1540 vMatchDetailList = NULL; 1541 vMatchNoDetailList = NULL; 1542 memset(&key, 0, sizeof(key)); 1543 1544 if (ringPtr->type != VirtualEvent) { 1545 Tcl_HashTable *veptPtr = &bindInfoPtr->virtualEventTable.patternTable; 1546 Tcl_HashEntry *hPtr; 1547 1548 key.object = NULL; 1549 key.type = ringPtr->type; 1550 key.detail = detail; 1551 1552 hPtr = Tcl_FindHashEntry(veptPtr, (char *) &key); 1553 if (hPtr != NULL) { 1554 vMatchDetailList = (PatSeq *) Tcl_GetHashValue(hPtr); 1555 } 1556 1557 if (key.detail.clientData != 0) { 1558 key.detail.clientData = 0; 1559 hPtr = Tcl_FindHashEntry(veptPtr, (char *) &key); 1560 if (hPtr != NULL) { 1561 vMatchNoDetailList = (PatSeq *) Tcl_GetHashValue(hPtr); 1562 } 1563 } 1564 } 1565 1566 /* 1567 * Loop over all the binding tags, finding the binding script or callback 1568 * for each one. Append all of the binding scripts, with %-sequences 1569 * expanded, to "scripts", with null characters separating the scripts for 1570 * each object. Append all the callbacks to the array of pending 1571 * callbacks. 1572 */ 1573 1574 pendingPtr = &staticPending; 1575 matchCount = 0; 1576 matchSpace = sizeof(staticPending.matchArray) / sizeof(PatSeq *); 1577 Tcl_DStringInit(&scripts); 1578 1579 for ( ; numObjects > 0; numObjects--, objectPtr++) { 1580 PatSeq *matchPtr = NULL, *sourcePtr = NULL; 1581 Tcl_HashEntry *hPtr; 1582 1583 /* 1584 * Match the new event against those recorded in the pattern table, 1585 * saving the longest matching pattern. For events with details 1586 * (button and key events), look for a binding for the specific key or 1587 * button. First see if the event matches a physical event that the 1588 * object is interested in, then look for a virtual event. 1589 */ 1590 1591 key.object = *objectPtr; 1592 key.type = ringPtr->type; 1593 key.detail = detail; 1594 hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, (char *) &key); 1595 if (hPtr != NULL) { 1596 matchPtr = MatchPatterns(dispPtr, bindPtr, 1597 (PatSeq *) Tcl_GetHashValue(hPtr), matchPtr, NULL, 1598 &sourcePtr); 1599 } 1600 1601 if (vMatchDetailList != NULL) { 1602 matchPtr = MatchPatterns(dispPtr, bindPtr, vMatchDetailList, 1603 matchPtr, objectPtr, &sourcePtr); 1604 } 1605 1606 /* 1607 * If no match was found, look for a binding for all keys or buttons 1608 * (detail of 0). Again, first match on a virtual event. 1609 */ 1610 1611 if ((detail.clientData != 0) && (matchPtr == NULL)) { 1612 key.detail.clientData = 0; 1613 hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, (char *) &key); 1614 if (hPtr != NULL) { 1615 matchPtr = MatchPatterns(dispPtr, bindPtr, 1616 (PatSeq *) Tcl_GetHashValue(hPtr), matchPtr, NULL, 1617 &sourcePtr); 1618 } 1619 1620 if (vMatchNoDetailList != NULL) { 1621 matchPtr = MatchPatterns(dispPtr, bindPtr, vMatchNoDetailList, 1622 matchPtr, objectPtr, &sourcePtr); 1623 } 1624 1625 } 1626 1627 if (matchPtr != NULL) { 1628 if (sourcePtr->eventProc == NULL) { 1629 Tcl_Panic("Tk_BindEvent: missing command"); 1630 } 1631 if (sourcePtr->eventProc == EvalTclBinding) { 1632 ExpandPercents(winPtr, (char *) sourcePtr->clientData, 1633 eventPtr, detail.keySym, &scripts); 1634 } else { 1635 if (matchCount >= matchSpace) { 1636 PendingBinding *newPtr; 1637 unsigned int oldSize, newSize; 1638 1639 oldSize = sizeof(staticPending) 1640 - sizeof(staticPending.matchArray) 1641 + matchSpace * sizeof(PatSeq*); 1642 matchSpace *= 2; 1643 newSize = sizeof(staticPending) 1644 - sizeof(staticPending.matchArray) 1645 + matchSpace * sizeof(PatSeq*); 1646 newPtr = (PendingBinding *) ckalloc(newSize); 1647 memcpy((void *) newPtr, (void *) pendingPtr, oldSize); 1648 if (pendingPtr != &staticPending) { 1649 ckfree((char *) pendingPtr); 1650 } 1651 pendingPtr = newPtr; 1652 } 1653 sourcePtr->refCount++; 1654 pendingPtr->matchArray[matchCount] = sourcePtr; 1655 matchCount++; 1656 } 1657 1658 /* 1659 * A "" is added to the scripts string to separate the various 1660 * scripts that should be invoked. 1661 */ 1662 1663 Tcl_DStringAppend(&scripts, "", 1); 1664 } 1665 } 1666 if (Tcl_DStringLength(&scripts) == 0) { 1667 return; 1668 } 1669 1670 /* 1671 * Now go back through and evaluate the binding for each object, in order, 1672 * dealing with "break" and "continue" exceptions appropriately. 1673 * 1674 * There are two tricks here: 1675 * 1. Bindings can be invoked from in the middle of Tcl commands, where 1676 * the interp's result is significant (for example, a widget might be 1677 * deleted because of an error in creating it, so the result contains 1678 * an error message that is eventually going to be returned by the 1679 * creating command). To preserve the result, we save it in a dynamic 1680 * string. 1681 * 2. The binding's action can potentially delete the binding, so bindPtr 1682 * may not point to anything valid once the action completes. Thus we 1683 * have to save bindPtr->interp in a local variable in order to restore 1684 * the result. 1685 */ 1686 1687 interp = bindPtr->interp; 1688 Tcl_DStringInit(&savedResult); 1689 1690 /* 1691 * Save information about the current screen, then invoke a script if the 1692 * screen has changed. 1693 */ 1694 1695 Tcl_DStringGetResult(interp, &savedResult); 1696 screenPtr = &bindInfoPtr->screenInfo; 1697 oldDispPtr = screenPtr->curDispPtr; 1698 oldScreen = screenPtr->curScreenIndex; 1699 if ((dispPtr != screenPtr->curDispPtr) 1700 || (Tk_ScreenNumber(tkwin) != screenPtr->curScreenIndex)) { 1701 screenPtr->curDispPtr = dispPtr; 1702 screenPtr->curScreenIndex = Tk_ScreenNumber(tkwin); 1703 ChangeScreen(interp, dispPtr->name, screenPtr->curScreenIndex); 1704 } 1705 1706 if (matchCount > 0) { 1707 /* 1708 * Remember the list of pending C binding callbacks, so we can mark 1709 * them as deleted and not call them if the act of evaluating a C or 1710 * Tcl binding deletes a C binding callback or even the whole window. 1711 */ 1712 1713 pendingPtr->nextPtr = bindInfoPtr->pendingList; 1714 pendingPtr->tkwin = tkwin; 1715 pendingPtr->deleted = 0; 1716 bindInfoPtr->pendingList = pendingPtr; 1717 } 1718 1719 /* 1720 * Save the current value of the TK_DEFER_MODAL flag so we can restore it 1721 * at the end of the loop. Clear the flag so we can detect any recursive 1722 * requests for a modal loop. 1723 */ 1724 1725 flags = winPtr->flags; 1726 winPtr->flags &= ~TK_DEFER_MODAL; 1727 1728 p = Tcl_DStringValue(&scripts); 1729 end = p + Tcl_DStringLength(&scripts); 1730 i = 0; 1731 1732 /* 1733 * Be carefule when dereferencing screenPtr or bindInfoPtr. If we evaluate 1734 * something that destroys ".", bindInfoPtr would have been freed, but we 1735 * can tell that by first checking to see if winPtr->mainPtr == NULL. 1736 */ 1737 1738 Tcl_Preserve((ClientData) bindInfoPtr); 1739 while (p < end) { 1740 int code; 1741 1742 if (!bindInfoPtr->deleted) { 1743 screenPtr->bindingDepth++; 1744 } 1745 Tcl_AllowExceptions(interp); 1746 1747 if (*p == '\0') { 1748 PatSeq *psPtr; 1749 1750 psPtr = pendingPtr->matchArray[i]; 1751 i++; 1752 code = TCL_OK; 1753 if ((pendingPtr->deleted == 0) 1754 && ((psPtr->flags & MARKED_DELETED) == 0)) { 1755 code = (*psPtr->eventProc)(psPtr->clientData, interp, eventPtr, 1756 tkwin, detail.keySym); 1757 } 1758 psPtr->refCount--; 1759 if ((psPtr->refCount == 0) && (psPtr->flags & MARKED_DELETED)) { 1760 if (psPtr->freeProc != NULL) { 1761 (*psPtr->freeProc)(psPtr->clientData); 1762 } 1763 ckfree((char *) psPtr); 1764 } 1765 } else { 1766 int len = (int) strlen(p); 1767 1768 code = Tcl_EvalEx(interp, p, len, TCL_EVAL_GLOBAL); 1769 p += len; 1770 } 1771 p++; 1772 1773 if (!bindInfoPtr->deleted) { 1774 screenPtr->bindingDepth--; 1775 } 1776 if (code != TCL_OK) { 1777 if (code == TCL_CONTINUE) { 1778 /* 1779 * Do nothing: just go on to the next command. 1780 */ 1781 } else if (code == TCL_BREAK) { 1782 break; 1783 } else { 1784 Tcl_AddErrorInfo(interp, "\n (command bound to event)"); 1785 Tcl_BackgroundError(interp); 1786 break; 1787 } 1788 } 1789 } 1790 1791 if (matchCount > 0 && !pendingPtr->deleted) { 1792 /* 1793 * Restore the original modal flag value and invoke the modal loop if 1794 * needed. 1795 */ 1796 1797 deferModal = winPtr->flags & TK_DEFER_MODAL; 1798 winPtr->flags = (winPtr->flags & (unsigned int) ~TK_DEFER_MODAL) 1799 | (flags & TK_DEFER_MODAL); 1800 if (deferModal) { 1801 modalProc = Tk_GetClassProc(winPtr->classProcsPtr, modalProc); 1802 if (modalProc != NULL) { 1803 (*modalProc)(tkwin, eventPtr); 1804 } 1805 } 1806 } 1807 1808 if (!bindInfoPtr->deleted && (screenPtr->bindingDepth != 0) 1809 && ((oldDispPtr != screenPtr->curDispPtr) 1810 || (oldScreen != screenPtr->curScreenIndex))) { 1811 /* 1812 * Some other binding script is currently executing, but its screen is 1813 * no longer current. Change the current display back again. 1814 */ 1815 1816 screenPtr->curDispPtr = oldDispPtr; 1817 screenPtr->curScreenIndex = oldScreen; 1818 ChangeScreen(interp, oldDispPtr->name, oldScreen); 1819 } 1820 Tcl_DStringResult(interp, &savedResult); 1821 Tcl_DStringFree(&scripts); 1822 1823 if (matchCount > 0) { 1824 if (!bindInfoPtr->deleted) { 1825 /* 1826 * Delete the pending list from the list of pending scripts for 1827 * this window. 1828 */ 1829 1830 PendingBinding **curPtrPtr; 1831 1832 for (curPtrPtr = &bindInfoPtr->pendingList; ; ) { 1833 if (*curPtrPtr == pendingPtr) { 1834 *curPtrPtr = pendingPtr->nextPtr; 1835 break; 1836 } 1837 curPtrPtr = &(*curPtrPtr)->nextPtr; 1838 } 1839 } 1840 if (pendingPtr != &staticPending) { 1841 ckfree((char *) pendingPtr); 1842 } 1843 } 1844 Tcl_Release((ClientData) bindInfoPtr); 1845} 1846 1847/* 1848 *--------------------------------------------------------------------------- 1849 * 1850 * TkBindDeadWindow -- 1851 * 1852 * This function is invoked when it is determined that a window is dead. 1853 * It cleans up bind-related information about the window 1854 * 1855 * Results: 1856 * None. 1857 * 1858 * Side effects: 1859 * Any pending C bindings for this window are cancelled. 1860 * 1861 *--------------------------------------------------------------------------- 1862 */ 1863 1864void 1865TkBindDeadWindow( 1866 TkWindow *winPtr) /* The window that is being deleted. */ 1867{ 1868 BindInfo *bindInfoPtr; 1869 PendingBinding *curPtr; 1870 1871 /* 1872 * Certain special windows like those used for send and clipboard have no 1873 * mainPtr. 1874 */ 1875 1876 if (winPtr->mainPtr == NULL) { 1877 return; 1878 } 1879 1880 bindInfoPtr = (BindInfo *) winPtr->mainPtr->bindInfo; 1881 curPtr = bindInfoPtr->pendingList; 1882 while (curPtr != NULL) { 1883 if (curPtr->tkwin == (Tk_Window) winPtr) { 1884 curPtr->deleted = 1; 1885 } 1886 curPtr = curPtr->nextPtr; 1887 } 1888} 1889 1890/* 1891 *---------------------------------------------------------------------- 1892 * 1893 * MatchPatterns -- 1894 * 1895 * Given a list of pattern sequences and a list of recent events, return 1896 * the pattern sequence that best matches the event list, if there is 1897 * one. 1898 * 1899 * This function is used in two different ways. In the simplest use, 1900 * "object" is NULL and psPtr is a list of pattern sequences, each of 1901 * which corresponds to a binding. In this case, the function finds the 1902 * pattern sequences that match the event list and returns the most 1903 * specific of those, if there is more than one. 1904 * 1905 * In the second case, psPtr is a list of pattern sequences, each of 1906 * which corresponds to a definition for a virtual binding. In order for 1907 * one of these sequences to "match", it must match the events (as above) 1908 * but in addition there must be a binding for its associated virtual 1909 * event on the current object. The "object" argument indicates which 1910 * object the binding must be for. 1911 * 1912 * Results: 1913 1914 * The return value is NULL if bestPtr is NULL and no pattern matches the 1915 * recent events from bindPtr. Otherwise the return value is the most 1916 * specific pattern sequence among bestPtr and all those at psPtr that 1917 * match the event list and object. If a pattern sequence other than 1918 * bestPtr is returned, then *bestCommandPtr is filled in with a pointer 1919 * to the command from the best sequence. 1920 * 1921 * Side effects: 1922 * None. 1923 * 1924 *---------------------------------------------------------------------- 1925 */ 1926static PatSeq * 1927MatchPatterns( 1928 TkDisplay *dispPtr, /* Display from which the event came. */ 1929 BindingTable *bindPtr, /* Information about binding table, such as 1930 * ring of recent events. */ 1931 PatSeq *psPtr, /* List of pattern sequences. */ 1932 PatSeq *bestPtr, /* The best match seen so far, from a previous 1933 * call to this function. NULL means no prior 1934 * best match. */ 1935 ClientData *objectPtr, /* If NULL, the sequences at psPtr correspond 1936 * to "normal" bindings. If non-NULL, the 1937 * sequences at psPtr correspond to virtual 1938 * bindings; in order to match each sequence 1939 * must correspond to a virtual binding for 1940 * which a binding exists for object in 1941 * bindPtr. */ 1942 PatSeq **sourcePtrPtr) /* Filled with the pattern sequence that 1943 * contains the eventProc and clientData 1944 * associated with the best match. If this 1945 * differs from the return value, it is the 1946 * virtual event that most closely matched the 1947 * return value (a physical event). Not 1948 * modified unless a result other than bestPtr 1949 * is returned. */ 1950{ 1951 PatSeq *matchPtr, *bestSourcePtr, *sourcePtr; 1952 1953 bestSourcePtr = *sourcePtrPtr; 1954 1955 /* 1956 * Iterate over all the pattern sequences. 1957 */ 1958 1959 for ( ; psPtr != NULL; psPtr = psPtr->nextSeqPtr) { 1960 XEvent *eventPtr = &bindPtr->eventRing[bindPtr->curEvent]; 1961 Detail *detailPtr = &bindPtr->detailRing[bindPtr->curEvent]; 1962 Pattern *patPtr = psPtr->pats; 1963 Window window = eventPtr->xany.window; 1964 int patCount, ringCount, flags, state, modMask, i; 1965 1966 /* 1967 * Iterate over all the patterns in a sequence to be sure that they 1968 * all match. 1969 */ 1970 1971 patCount = psPtr->numPats; 1972 ringCount = EVENT_BUFFER_SIZE; 1973 while (patCount > 0) { 1974 if (ringCount <= 0) { 1975 goto nextSequence; 1976 } 1977 if (eventPtr->xany.type != patPtr->eventType) { 1978 /* 1979 * Most of the event types are considered superfluous in that 1980 * they are ignored if they occur in the middle of a pattern 1981 * sequence and have mismatching types. The only ones that 1982 * cannot be ignored are ButtonPress and ButtonRelease events 1983 * (if the next event in the pattern is a KeyPress or 1984 * KeyRelease) and KeyPress and KeyRelease events (if the next 1985 * pattern event is a ButtonPress or ButtonRelease). Here are 1986 * some tricky cases to consider: 1987 * 1. Double-Button or Double-Key events. 1988 * 2. Double-ButtonRelease or Double-KeyRelease events. 1989 * 3. The arrival of various events like Enter and Leave and 1990 * FocusIn and GraphicsExpose between two button presses or 1991 * key presses. 1992 * 4. Modifier keys like Shift and Control shouldn't generate 1993 * conflicts with button events. 1994 */ 1995 1996 if ((patPtr->eventType == KeyPress) 1997 || (patPtr->eventType == KeyRelease)) { 1998 if ((eventPtr->xany.type == ButtonPress) 1999 || (eventPtr->xany.type == ButtonRelease)) { 2000 goto nextSequence; 2001 } 2002 } else if ((patPtr->eventType == ButtonPress) 2003 || (patPtr->eventType == ButtonRelease)) { 2004 if ((eventPtr->xany.type == KeyPress) 2005 || (eventPtr->xany.type == KeyRelease)) { 2006 /* 2007 * Ignore key events if they are modifier keys. 2008 */ 2009 2010 for (i = 0; i < dispPtr->numModKeyCodes; i++) { 2011 if (dispPtr->modKeyCodes[i] 2012 == eventPtr->xkey.keycode) { 2013 /* 2014 * This key is a modifier key, so ignore it. 2015 */ 2016 2017 goto nextEvent; 2018 } 2019 } 2020 goto nextSequence; 2021 } 2022 } 2023 goto nextEvent; 2024 } 2025 if (eventPtr->xany.type == CreateNotify 2026 && eventPtr->xcreatewindow.parent != window) { 2027 goto nextSequence; 2028 } else if (eventPtr->xany.window != window) { 2029 goto nextSequence; 2030 } 2031 2032 /* 2033 * Note: it's important for the keysym check to go before the 2034 * modifier check, so we can ignore unwanted modifier keys before 2035 * choking on the modifier check. 2036 */ 2037 2038 if ((patPtr->detail.clientData != 0) 2039 && (patPtr->detail.clientData != detailPtr->clientData)) { 2040 /* 2041 * The detail appears not to match. However, if the event is a 2042 * KeyPress for a modifier key then just ignore the event. 2043 * Otherwise event sequences like "aD" never match because the 2044 * shift key goes down between the "a" and the "D". 2045 */ 2046 2047 if (eventPtr->xany.type == KeyPress) { 2048 for (i = 0; i < dispPtr->numModKeyCodes; i++) { 2049 if (dispPtr->modKeyCodes[i] == eventPtr->xkey.keycode) { 2050 goto nextEvent; 2051 } 2052 } 2053 } 2054 goto nextSequence; 2055 } 2056 flags = flagArray[eventPtr->type]; 2057 if (flags & KEY_BUTTON_MOTION_VIRTUAL) { 2058 state = eventPtr->xkey.state; 2059 } else if (flags & CROSSING) { 2060 state = eventPtr->xcrossing.state; 2061 } else { 2062 state = 0; 2063 } 2064 if (patPtr->needMods != 0) { 2065 modMask = patPtr->needMods; 2066 if ((modMask & META_MASK) && (dispPtr->metaModMask != 0)) { 2067 modMask = (modMask & ~META_MASK) | dispPtr->metaModMask; 2068 } 2069 if ((modMask & ALT_MASK) && (dispPtr->altModMask != 0)) { 2070 modMask = (modMask & ~ALT_MASK) | dispPtr->altModMask; 2071 } 2072 2073 if ((state & META_MASK) && (dispPtr->metaModMask != 0)) { 2074 state = (state & ~META_MASK) | dispPtr->metaModMask; 2075 } 2076 if ((state & ALT_MASK) && (dispPtr->altModMask != 0)) { 2077 state = (state & ~ALT_MASK) | dispPtr->altModMask; 2078 } 2079 2080 if ((state & modMask) != modMask) { 2081 goto nextSequence; 2082 } 2083 } 2084 if (psPtr->flags & PAT_NEARBY) { 2085 XEvent *firstPtr = &bindPtr->eventRing[bindPtr->curEvent]; 2086 int timeDiff; 2087 2088 timeDiff = (Time) firstPtr->xkey.time - eventPtr->xkey.time; 2089 if ((firstPtr->xkey.x_root 2090 < (eventPtr->xkey.x_root - NEARBY_PIXELS)) 2091 || (firstPtr->xkey.x_root 2092 > (eventPtr->xkey.x_root + NEARBY_PIXELS)) 2093 || (firstPtr->xkey.y_root 2094 < (eventPtr->xkey.y_root - NEARBY_PIXELS)) 2095 || (firstPtr->xkey.y_root 2096 > (eventPtr->xkey.y_root + NEARBY_PIXELS)) 2097 || (timeDiff > NEARBY_MS)) { 2098 goto nextSequence; 2099 } 2100 } 2101 patPtr++; 2102 patCount--; 2103 nextEvent: 2104 if (eventPtr == bindPtr->eventRing) { 2105 eventPtr = &bindPtr->eventRing[EVENT_BUFFER_SIZE-1]; 2106 detailPtr = &bindPtr->detailRing[EVENT_BUFFER_SIZE-1]; 2107 } else { 2108 eventPtr--; 2109 detailPtr--; 2110 } 2111 ringCount--; 2112 } 2113 2114 matchPtr = psPtr; 2115 sourcePtr = psPtr; 2116 2117 if (objectPtr != NULL) { 2118 int iVirt; 2119 VirtualOwners *voPtr; 2120 PatternTableKey key; 2121 2122 /* 2123 * The sequence matches the physical constraints. Is this object 2124 * interested in any of the virtual events that correspond to this 2125 * sequence? 2126 */ 2127 2128 voPtr = psPtr->voPtr; 2129 2130 memset(&key, 0, sizeof(key)); 2131 key.object = *objectPtr; 2132 key.type = VirtualEvent; 2133 key.detail.clientData = 0; 2134 2135 for (iVirt = 0; iVirt < voPtr->numOwners; iVirt++) { 2136 Tcl_HashEntry *hPtr = voPtr->owners[iVirt]; 2137 2138 key.detail.name = (Tk_Uid) Tcl_GetHashKey(hPtr->tablePtr, 2139 hPtr); 2140 hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, 2141 (char *) &key); 2142 if (hPtr != NULL) { 2143 /* 2144 * This tag is interested in this virtual event and its 2145 * corresponding physical event is a good match with the 2146 * virtual event's definition. 2147 */ 2148 2149 PatSeq *virtMatchPtr = (PatSeq *) Tcl_GetHashValue(hPtr); 2150 2151 if ((virtMatchPtr->numPats != 1) 2152 || (virtMatchPtr->nextSeqPtr != NULL)) { 2153 Tcl_Panic("MatchPattern: badly constructed virtual event"); 2154 } 2155 sourcePtr = virtMatchPtr; 2156 goto match; 2157 } 2158 } 2159 2160 /* 2161 * The physical event matches a virtual event's definition, but 2162 * the tag isn't interested in it. 2163 */ 2164 2165 goto nextSequence; 2166 } 2167 match: 2168 2169 /* 2170 * This sequence matches. If we've already got another match, pick 2171 * whichever is most specific. Detail is most important, then 2172 * needMods. 2173 */ 2174 2175 if (bestPtr != NULL) { 2176 Pattern *patPtr2; 2177 2178 if (matchPtr->numPats != bestPtr->numPats) { 2179 if (bestPtr->numPats > matchPtr->numPats) { 2180 goto nextSequence; 2181 } else { 2182 goto newBest; 2183 } 2184 } 2185 for (i = 0, patPtr = matchPtr->pats, patPtr2 = bestPtr->pats; 2186 i < matchPtr->numPats; i++, patPtr++, patPtr2++) { 2187 if (patPtr->detail.clientData != patPtr2->detail.clientData) { 2188 if (patPtr->detail.clientData == 0) { 2189 goto nextSequence; 2190 } else { 2191 goto newBest; 2192 } 2193 } 2194 if (patPtr->needMods != patPtr2->needMods) { 2195 if ((patPtr->needMods & patPtr2->needMods) 2196 == patPtr->needMods) { 2197 goto nextSequence; 2198 } else if ((patPtr->needMods & patPtr2->needMods) 2199 == patPtr2->needMods) { 2200 goto newBest; 2201 } 2202 } 2203 } 2204 2205 /* 2206 * Tie goes to current best pattern. 2207 * 2208 * (1) For virtual vs. virtual, the least recently defined virtual 2209 * wins, because virtuals are examined in order of definition. 2210 * This order is _not_ guaranteed in the documentation. 2211 * 2212 * (2) For virtual vs. physical, the physical wins because all the 2213 * physicals are examined before the virtuals. This order is 2214 * guaranteed in the documentation. 2215 * 2216 * (3) For physical vs. physical pattern, the most recently 2217 * defined physical wins, because physicals are examined in 2218 * reverse order of definition. This order is guaranteed in the 2219 * documentation. 2220 */ 2221 2222 goto nextSequence; 2223 } 2224 newBest: 2225 bestPtr = matchPtr; 2226 bestSourcePtr = sourcePtr; 2227 2228 nextSequence: 2229 continue; 2230 } 2231 2232 *sourcePtrPtr = bestSourcePtr; 2233 return bestPtr; 2234} 2235 2236/* 2237 *-------------------------------------------------------------- 2238 * 2239 * ExpandPercents -- 2240 * 2241 * Given a command and an event, produce a new command by replacing % 2242 * constructs in the original command with information from the X event. 2243 * 2244 * Results: 2245 * The new expanded command is appended to the dynamic string given by 2246 * dsPtr. 2247 * 2248 * Side effects: 2249 * None. 2250 * 2251 *-------------------------------------------------------------- 2252 */ 2253 2254static void 2255ExpandPercents( 2256 TkWindow *winPtr, /* Window where event occurred: needed to get 2257 * input context. */ 2258 const char *before, /* Command containing percent expressions to 2259 * be replaced. */ 2260 XEvent *eventPtr, /* X event containing information to be used 2261 * in % replacements. */ 2262 KeySym keySym, /* KeySym: only relevant for KeyPress and 2263 * KeyRelease events). */ 2264 Tcl_DString *dsPtr) /* Dynamic string in which to append new 2265 * command. */ 2266{ 2267 int spaceNeeded, cvtFlags; /* Used to substitute string as proper Tcl 2268 * list element. */ 2269 int number, flags, length; 2270#define NUM_SIZE 40 2271 const char *string; 2272 Tcl_DString buf; 2273 char numStorage[NUM_SIZE+1]; 2274 2275 Tcl_DStringInit(&buf); 2276 2277 if (eventPtr->type < TK_LASTEVENT) { 2278 flags = flagArray[eventPtr->type]; 2279 } else { 2280 flags = 0; 2281 } 2282 2283 while (1) { 2284 /* 2285 * Find everything up to the next % character and append it to the 2286 * result string. 2287 */ 2288 2289 for (string = before; (*string != 0) && (*string != '%'); string++) { 2290 /* Empty loop body. */ 2291 } 2292 if (string != before) { 2293 Tcl_DStringAppend(dsPtr, before, (int) (string-before)); 2294 before = string; 2295 } 2296 if (*before == 0) { 2297 break; 2298 } 2299 2300 /* 2301 * There's a percent sequence here. Process it. 2302 */ 2303 2304 number = 0; 2305 string = "??"; 2306 switch (before[1]) { 2307 case '#': 2308 number = eventPtr->xany.serial; 2309 goto doNumber; 2310 case 'a': 2311 if (flags & CONFIG) { 2312 TkpPrintWindowId(numStorage, eventPtr->xconfigure.above); 2313 string = numStorage; 2314 } 2315 goto doString; 2316 case 'b': 2317 if (flags & BUTTON) { 2318 number = eventPtr->xbutton.button; 2319 goto doNumber; 2320 } 2321 goto doString; 2322 case 'c': 2323 if (flags & EXPOSE) { 2324 number = eventPtr->xexpose.count; 2325 goto doNumber; 2326 } 2327 goto doString; 2328 case 'd': 2329 if (flags & (CROSSING|FOCUS)) { 2330 if (flags & FOCUS) { 2331 number = eventPtr->xfocus.detail; 2332 } else { 2333 number = eventPtr->xcrossing.detail; 2334 } 2335 string = TkFindStateString(notifyDetail, number); 2336 } else if (flags & CONFIGREQ) { 2337 if (eventPtr->xconfigurerequest.value_mask & CWStackMode) { 2338 string = TkFindStateString(configureRequestDetail, 2339 eventPtr->xconfigurerequest.detail); 2340 } else { 2341 string = ""; 2342 } 2343 } else if (flags & VIRTUAL) { 2344 XVirtualEvent *vePtr = (XVirtualEvent *) eventPtr; 2345 2346 if (vePtr->user_data != NULL) { 2347 string = Tcl_GetString(vePtr->user_data); 2348 } else { 2349 string = ""; 2350 } 2351 } 2352 goto doString; 2353 case 'f': 2354 if (flags & CROSSING) { 2355 number = eventPtr->xcrossing.focus; 2356 goto doNumber; 2357 } 2358 goto doString; 2359 case 'h': 2360 if (flags & EXPOSE) { 2361 number = eventPtr->xexpose.height; 2362 } else if (flags & CONFIG) { 2363 number = eventPtr->xconfigure.height; 2364 } else if (flags & CREATE) { 2365 number = eventPtr->xcreatewindow.height; 2366 } else if (flags & CONFIGREQ) { 2367 number = eventPtr->xconfigurerequest.height; 2368 } else if (flags & RESIZEREQ) { 2369 number = eventPtr->xresizerequest.height; 2370 } else { 2371 goto doString; 2372 } 2373 goto doNumber; 2374 case 'i': 2375 if (flags & CREATE) { 2376 TkpPrintWindowId(numStorage, eventPtr->xcreatewindow.window); 2377 } else if (flags & CONFIGREQ) { 2378 TkpPrintWindowId(numStorage, 2379 eventPtr->xconfigurerequest.window); 2380 } else if (flags & MAPREQ) { 2381 TkpPrintWindowId(numStorage, eventPtr->xmaprequest.window); 2382 } else { 2383 TkpPrintWindowId(numStorage, eventPtr->xany.window); 2384 } 2385 string = numStorage; 2386 goto doString; 2387 case 'k': 2388 if (flags & KEY) { 2389 number = eventPtr->xkey.keycode; 2390 goto doNumber; 2391 } 2392 goto doString; 2393 case 'm': 2394 if (flags & CROSSING) { 2395 number = eventPtr->xcrossing.mode; 2396 string = TkFindStateString(notifyMode, number); 2397 } else if (flags & FOCUS) { 2398 number = eventPtr->xfocus.mode; 2399 string = TkFindStateString(notifyMode, number); 2400 } 2401 goto doString; 2402 case 'o': 2403 if (flags & CREATE) { 2404 number = eventPtr->xcreatewindow.override_redirect; 2405 } else if (flags & MAP) { 2406 number = eventPtr->xmap.override_redirect; 2407 } else if (flags & REPARENT) { 2408 number = eventPtr->xreparent.override_redirect; 2409 } else if (flags & CONFIG) { 2410 number = eventPtr->xconfigure.override_redirect; 2411 } else { 2412 goto doString; 2413 } 2414 goto doNumber; 2415 case 'p': 2416 if (flags & CIRC) { 2417 string = TkFindStateString(circPlace, 2418 eventPtr->xcirculate.place); 2419 } else if (flags & CIRCREQ) { 2420 string = TkFindStateString(circPlace, 2421 eventPtr->xcirculaterequest.place); 2422 } 2423 goto doString; 2424 case 's': 2425 if (flags & KEY_BUTTON_MOTION_VIRTUAL) { 2426 number = eventPtr->xkey.state; 2427 goto doNumber; 2428 } else if (flags & CROSSING) { 2429 number = eventPtr->xcrossing.state; 2430 goto doNumber; 2431 } else if (flags & PROP) { 2432 string = TkFindStateString(propNotify, 2433 eventPtr->xproperty.state); 2434 } else if (flags & VISIBILITY) { 2435 string = TkFindStateString(visNotify, 2436 eventPtr->xvisibility.state); 2437 } 2438 goto doString; 2439 case 't': 2440 if (flags & KEY_BUTTON_MOTION_VIRTUAL) { 2441 number = (int) eventPtr->xkey.time; 2442 } else if (flags & CROSSING) { 2443 number = (int) eventPtr->xcrossing.time; 2444 } else if (flags & PROP) { 2445 number = (int) eventPtr->xproperty.time; 2446 } else { 2447 goto doString; 2448 } 2449 goto doNumber; 2450 case 'v': 2451 number = eventPtr->xconfigurerequest.value_mask; 2452 goto doNumber; 2453 case 'w': 2454 if (flags & EXPOSE) { 2455 number = eventPtr->xexpose.width; 2456 } else if (flags & CONFIG) { 2457 number = eventPtr->xconfigure.width; 2458 } else if (flags & CREATE) { 2459 number = eventPtr->xcreatewindow.width; 2460 } else if (flags & CONFIGREQ) { 2461 number = eventPtr->xconfigurerequest.width; 2462 } else if (flags & RESIZEREQ) { 2463 number = eventPtr->xresizerequest.width; 2464 } else { 2465 goto doString; 2466 } 2467 goto doNumber; 2468 case 'x': 2469 if (flags & KEY_BUTTON_MOTION_VIRTUAL) { 2470 number = eventPtr->xkey.x; 2471 } else if (flags & CROSSING) { 2472 number = eventPtr->xcrossing.x; 2473 } else if (flags & EXPOSE) { 2474 number = eventPtr->xexpose.x; 2475 } else if (flags & (CREATE|CONFIG|GRAVITY)) { 2476 number = eventPtr->xcreatewindow.x; 2477 } else if (flags & REPARENT) { 2478 number = eventPtr->xreparent.x; 2479 } else if (flags & CREATE) { 2480 number = eventPtr->xcreatewindow.x; 2481 } else if (flags & CONFIGREQ) { 2482 number = eventPtr->xconfigurerequest.x; 2483 } else { 2484 goto doString; 2485 } 2486 goto doNumber; 2487 case 'y': 2488 if (flags & KEY_BUTTON_MOTION_VIRTUAL) { 2489 number = eventPtr->xkey.y; 2490 } else if (flags & EXPOSE) { 2491 number = eventPtr->xexpose.y; 2492 } else if (flags & (CREATE|CONFIG|GRAVITY)) { 2493 number = eventPtr->xcreatewindow.y; 2494 } else if (flags & REPARENT) { 2495 number = eventPtr->xreparent.y; 2496 } else if (flags & CROSSING) { 2497 number = eventPtr->xcrossing.y; 2498 } else if (flags & CREATE) { 2499 number = eventPtr->xcreatewindow.y; 2500 } else if (flags & CONFIGREQ) { 2501 number = eventPtr->xconfigurerequest.y; 2502 } else { 2503 goto doString; 2504 } 2505 goto doNumber; 2506 case 'A': 2507 if (flags & KEY) { 2508 Tcl_DStringFree(&buf); 2509 string = TkpGetString(winPtr, eventPtr, &buf); 2510 } 2511 goto doString; 2512 case 'B': 2513 if (flags & CREATE) { 2514 number = eventPtr->xcreatewindow.border_width; 2515 } else if (flags & CONFIGREQ) { 2516 number = eventPtr->xconfigurerequest.border_width; 2517 } else if (flags & CONFIG) { 2518 number = eventPtr->xconfigure.border_width; 2519 } else { 2520 goto doString; 2521 } 2522 goto doNumber; 2523 case 'D': 2524 /* 2525 * This is used only by the MouseWheel event. 2526 */ 2527 2528 if (flags & KEY) { 2529 number = eventPtr->xkey.keycode; 2530 goto doNumber; 2531 } 2532 goto doString; 2533 case 'E': 2534 number = (int) eventPtr->xany.send_event; 2535 goto doNumber; 2536 case 'K': 2537 if (flags & KEY) { 2538 char *name = TkKeysymToString(keySym); 2539 2540 if (name != NULL) { 2541 string = name; 2542 } 2543 } 2544 goto doString; 2545 case 'N': 2546 if (flags & KEY) { 2547 number = (int) keySym; 2548 goto doNumber; 2549 } 2550 goto doString; 2551 case 'P': 2552 if (flags & PROP) { 2553 string = Tk_GetAtomName((Tk_Window) winPtr, 2554 eventPtr->xproperty.atom); 2555 } 2556 goto doString; 2557 case 'R': 2558 if (flags & KEY_BUTTON_MOTION_CROSSING) { 2559 TkpPrintWindowId(numStorage, eventPtr->xkey.root); 2560 string = numStorage; 2561 } 2562 goto doString; 2563 case 'S': 2564 if (flags & KEY_BUTTON_MOTION_CROSSING) { 2565 TkpPrintWindowId(numStorage, eventPtr->xkey.subwindow); 2566 string = numStorage; 2567 } 2568 goto doString; 2569 case 'T': 2570 number = eventPtr->type; 2571 goto doNumber; 2572 case 'W': { 2573 Tk_Window tkwin; 2574 2575 tkwin = Tk_IdToWindow(eventPtr->xany.display, 2576 eventPtr->xany.window); 2577 if (tkwin != NULL) { 2578 string = Tk_PathName(tkwin); 2579 } else { 2580 string = "??"; 2581 } 2582 goto doString; 2583 } 2584 case 'X': 2585 if (flags & KEY_BUTTON_MOTION_CROSSING) { 2586 Tk_Window tkwin; 2587 int x, y; 2588 int width, height; 2589 2590 number = eventPtr->xkey.x_root; 2591 tkwin = Tk_IdToWindow(eventPtr->xany.display, 2592 eventPtr->xany.window); 2593 if (tkwin != NULL) { 2594 Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); 2595 number -= x; 2596 } 2597 goto doNumber; 2598 } 2599 goto doString; 2600 case 'Y': 2601 if (flags & KEY_BUTTON_MOTION_CROSSING) { 2602 Tk_Window tkwin; 2603 int x, y; 2604 int width, height; 2605 2606 number = eventPtr->xkey.y_root; 2607 tkwin = Tk_IdToWindow(eventPtr->xany.display, 2608 eventPtr->xany.window); 2609 if (tkwin != NULL) { 2610 Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height); 2611 number -= y; 2612 } 2613 goto doNumber; 2614 } 2615 goto doString; 2616 default: 2617 numStorage[0] = before[1]; 2618 numStorage[1] = '\0'; 2619 string = numStorage; 2620 goto doString; 2621 } 2622 2623 doNumber: 2624 sprintf(numStorage, "%d", number); 2625 string = numStorage; 2626 2627 doString: 2628 spaceNeeded = Tcl_ScanElement(string, &cvtFlags); 2629 length = Tcl_DStringLength(dsPtr); 2630 Tcl_DStringSetLength(dsPtr, length + spaceNeeded); 2631 spaceNeeded = Tcl_ConvertElement(string, 2632 Tcl_DStringValue(dsPtr) + length, 2633 cvtFlags | TCL_DONT_USE_BRACES); 2634 Tcl_DStringSetLength(dsPtr, length + spaceNeeded); 2635 before += 2; 2636 } 2637 Tcl_DStringFree(&buf); 2638} 2639 2640/* 2641 *---------------------------------------------------------------------- 2642 * 2643 * ChangeScreen -- 2644 * 2645 * This function is invoked whenever the current screen changes in an 2646 * application. It invokes a Tcl command named "tk::ScreenChanged", 2647 * passing it the screen name as argument. tk::ScreenChanged does things 2648 * like making the tk::Priv variable point to an array for the current 2649 * display. 2650 * 2651 * Results: 2652 * None. 2653 * 2654 * Side effects: 2655 * Depends on what tk::ScreenChanged does. If an error occurs then 2656 * bgerror will be invoked. 2657 * 2658 *---------------------------------------------------------------------- 2659 */ 2660 2661static void 2662ChangeScreen( 2663 Tcl_Interp *interp, /* Interpreter in which to invoke command. */ 2664 char *dispName, /* Name of new display. */ 2665 int screenIndex) /* Index of new screen. */ 2666{ 2667 Tcl_DString cmd; 2668 int code; 2669 char screen[TCL_INTEGER_SPACE]; 2670 2671 Tcl_DStringInit(&cmd); 2672 Tcl_DStringAppend(&cmd, "tk::ScreenChanged ", 18); 2673 Tcl_DStringAppend(&cmd, dispName, -1); 2674 sprintf(screen, ".%d", screenIndex); 2675 Tcl_DStringAppend(&cmd, screen, -1); 2676 code = Tcl_EvalEx(interp, Tcl_DStringValue(&cmd), Tcl_DStringLength(&cmd), 2677 TCL_EVAL_GLOBAL); 2678 Tcl_DStringFree(&cmd); 2679 if (code != TCL_OK) { 2680 Tcl_AddErrorInfo(interp, 2681 "\n (changing screen in event binding)"); 2682 Tcl_BackgroundError(interp); 2683 } 2684} 2685 2686/* 2687 *---------------------------------------------------------------------- 2688 * 2689 * Tk_EventCmd -- 2690 * 2691 * This function is invoked to process the "event" Tcl command. It is 2692 * used to define and generate events. 2693 * 2694 * Results: 2695 * A standard Tcl result. 2696 * 2697 * Side effects: 2698 * See the user documentation. 2699 * 2700 *---------------------------------------------------------------------- 2701 */ 2702 2703int 2704Tk_EventObjCmd( 2705 ClientData clientData, /* Main window associated with interpreter. */ 2706 Tcl_Interp *interp, /* Current interpreter. */ 2707 int objc, /* Number of arguments. */ 2708 Tcl_Obj *const objv[]) /* Argument objects. */ 2709{ 2710 int index; 2711 Tk_Window tkwin; 2712 VirtualEventTable *vetPtr; 2713 TkBindInfo bindInfo; 2714 static const char *optionStrings[] = { 2715 "add", "delete", "generate", "info", 2716 NULL 2717 }; 2718 enum options { 2719 EVENT_ADD, EVENT_DELETE, EVENT_GENERATE, EVENT_INFO 2720 }; 2721 2722 tkwin = (Tk_Window) clientData; 2723 bindInfo = ((TkWindow *) tkwin)->mainPtr->bindInfo; 2724 vetPtr = &((BindInfo *) bindInfo)->virtualEventTable; 2725 2726 if (objc < 2) { 2727 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); 2728 return TCL_ERROR; 2729 } 2730 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, 2731 &index) != TCL_OK) { 2732 return TCL_ERROR; 2733 } 2734 2735 switch ((enum options) index) { 2736 case EVENT_ADD: { 2737 int i; 2738 char *name, *event; 2739 2740 if (objc < 4) { 2741 Tcl_WrongNumArgs(interp, 2, objv, 2742 "virtual sequence ?sequence ...?"); 2743 return TCL_ERROR; 2744 } 2745 name = Tcl_GetString(objv[2]); 2746 for (i = 3; i < objc; i++) { 2747 event = Tcl_GetString(objv[i]); 2748 if (CreateVirtualEvent(interp, vetPtr, name, event) != TCL_OK) { 2749 return TCL_ERROR; 2750 } 2751 } 2752 break; 2753 } 2754 case EVENT_DELETE: { 2755 int i; 2756 char *name, *event; 2757 2758 if (objc < 3) { 2759 Tcl_WrongNumArgs(interp, 2, objv, 2760 "virtual ?sequence sequence ...?"); 2761 return TCL_ERROR; 2762 } 2763 name = Tcl_GetString(objv[2]); 2764 if (objc == 3) { 2765 return DeleteVirtualEvent(interp, vetPtr, name, NULL); 2766 } 2767 for (i = 3; i < objc; i++) { 2768 event = Tcl_GetString(objv[i]); 2769 if (DeleteVirtualEvent(interp, vetPtr, name, event) != TCL_OK) { 2770 return TCL_ERROR; 2771 } 2772 } 2773 break; 2774 } 2775 case EVENT_GENERATE: 2776 if (objc < 4) { 2777 Tcl_WrongNumArgs(interp, 2, objv, "window event ?options?"); 2778 return TCL_ERROR; 2779 } 2780 return HandleEventGenerate(interp, tkwin, objc - 2, objv + 2); 2781 case EVENT_INFO: 2782 if (objc == 2) { 2783 GetAllVirtualEvents(interp, vetPtr); 2784 return TCL_OK; 2785 } else if (objc == 3) { 2786 return GetVirtualEvent(interp, vetPtr, Tcl_GetString(objv[2])); 2787 } else { 2788 Tcl_WrongNumArgs(interp, 2, objv, "?virtual?"); 2789 return TCL_ERROR; 2790 } 2791 } 2792 return TCL_OK; 2793} 2794 2795/* 2796 *--------------------------------------------------------------------------- 2797 * 2798 * InitVirtualEventTable -- 2799 * 2800 * Given storage for a virtual event table, set up the fields to prepare 2801 * a new domain in which virtual events may be defined. 2802 * 2803 * Results: 2804 * None. 2805 * 2806 * Side effects: 2807 * *vetPtr is now initialized. 2808 * 2809 *--------------------------------------------------------------------------- 2810 */ 2811 2812static void 2813InitVirtualEventTable( 2814 VirtualEventTable *vetPtr) /* Pointer to virtual event table. Memory is 2815 * supplied by the caller. */ 2816{ 2817 Tcl_InitHashTable(&vetPtr->patternTable, 2818 sizeof(PatternTableKey) / sizeof(int)); 2819 Tcl_InitHashTable(&vetPtr->nameTable, TCL_ONE_WORD_KEYS); 2820} 2821 2822/* 2823 *--------------------------------------------------------------------------- 2824 * 2825 * DeleteVirtualEventTable -- 2826 * 2827 * Delete the contents of a virtual event table. The caller is 2828 * responsible for freeing any memory used by the table itself. 2829 * 2830 * Results: 2831 * None. 2832 * 2833 * Side effects: 2834 * Memory is freed. 2835 * 2836 *--------------------------------------------------------------------------- 2837 */ 2838 2839static void 2840DeleteVirtualEventTable( 2841 VirtualEventTable *vetPtr) /* The virtual event table to delete. */ 2842{ 2843 Tcl_HashEntry *hPtr; 2844 Tcl_HashSearch search; 2845 PatSeq *psPtr, *nextPtr; 2846 2847 hPtr = Tcl_FirstHashEntry(&vetPtr->patternTable, &search); 2848 for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { 2849 psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); 2850 for ( ; psPtr != NULL; psPtr = nextPtr) { 2851 nextPtr = psPtr->nextSeqPtr; 2852 ckfree((char *) psPtr->voPtr); 2853 ckfree((char *) psPtr); 2854 } 2855 } 2856 Tcl_DeleteHashTable(&vetPtr->patternTable); 2857 2858 hPtr = Tcl_FirstHashEntry(&vetPtr->nameTable, &search); 2859 for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { 2860 ckfree((char *) Tcl_GetHashValue(hPtr)); 2861 } 2862 Tcl_DeleteHashTable(&vetPtr->nameTable); 2863} 2864 2865/* 2866 *---------------------------------------------------------------------- 2867 * 2868 * CreateVirtualEvent -- 2869 * 2870 * Add a new definition for a virtual event. If the virtual event is 2871 * already defined, the new definition augments those that already exist. 2872 * 2873 * Results: 2874 * The return value is TCL_ERROR if an error occured while creating the 2875 * virtual binding. In this case, an error message will be left in the 2876 * interp's result. If all went well then the return value is TCL_OK. 2877 * 2878 * Side effects: 2879 * The virtual event may cause future calls to Tk_BindEvent to behave 2880 * differently than they did previously. 2881 * 2882 *---------------------------------------------------------------------- 2883 */ 2884 2885static int 2886CreateVirtualEvent( 2887 Tcl_Interp *interp, /* Used for error reporting. */ 2888 VirtualEventTable *vetPtr, /* Table in which to augment virtual event. */ 2889 char *virtString, /* Name of new virtual event. */ 2890 char *eventString) /* String describing physical event that 2891 * triggers virtual event. */ 2892{ 2893 PatSeq *psPtr; 2894 int dummy; 2895 Tcl_HashEntry *vhPtr; 2896 unsigned long eventMask; 2897 PhysicalsOwned *poPtr; 2898 VirtualOwners *voPtr; 2899 Tk_Uid virtUid; 2900 2901 virtUid = GetVirtualEventUid(interp, virtString); 2902 if (virtUid == NULL) { 2903 return TCL_ERROR; 2904 } 2905 2906 /* 2907 * Find/create physical event 2908 */ 2909 2910 psPtr = FindSequence(interp, &vetPtr->patternTable, NULL, eventString, 2911 1, 0, &eventMask); 2912 if (psPtr == NULL) { 2913 return TCL_ERROR; 2914 } 2915 2916 /* 2917 * Find/create virtual event. 2918 */ 2919 2920 vhPtr = Tcl_CreateHashEntry(&vetPtr->nameTable, virtUid, &dummy); 2921 2922 /* 2923 * Make virtual event own the physical event. 2924 */ 2925 2926 poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr); 2927 if (poPtr == NULL) { 2928 poPtr = (PhysicalsOwned *) ckalloc(sizeof(PhysicalsOwned)); 2929 poPtr->numOwned = 0; 2930 } else { 2931 /* 2932 * See if this virtual event is already defined for this physical 2933 * event and just return if it is. 2934 */ 2935 2936 int i; 2937 2938 for (i = 0; i < poPtr->numOwned; i++) { 2939 if (poPtr->patSeqs[i] == psPtr) { 2940 return TCL_OK; 2941 } 2942 } 2943 poPtr = (PhysicalsOwned *) ckrealloc((char *) poPtr, 2944 sizeof(PhysicalsOwned) + poPtr->numOwned * sizeof(PatSeq *)); 2945 } 2946 Tcl_SetHashValue(vhPtr, (ClientData) poPtr); 2947 poPtr->patSeqs[poPtr->numOwned] = psPtr; 2948 poPtr->numOwned++; 2949 2950 /* 2951 * Make physical event so it can trigger the virtual event. 2952 */ 2953 2954 voPtr = psPtr->voPtr; 2955 if (voPtr == NULL) { 2956 voPtr = (VirtualOwners *) ckalloc(sizeof(VirtualOwners)); 2957 voPtr->numOwners = 0; 2958 } else { 2959 voPtr = (VirtualOwners *) ckrealloc((char *) voPtr, 2960 sizeof(VirtualOwners) 2961 + voPtr->numOwners * sizeof(Tcl_HashEntry *)); 2962 } 2963 psPtr->voPtr = voPtr; 2964 voPtr->owners[voPtr->numOwners] = vhPtr; 2965 voPtr->numOwners++; 2966 2967 return TCL_OK; 2968} 2969 2970/* 2971 *-------------------------------------------------------------- 2972 * 2973 * DeleteVirtualEvent -- 2974 * 2975 * Remove the definition of a given virtual event. If the event string is 2976 * NULL, all definitions of the virtual event will be removed. 2977 * Otherwise, just the specified definition of the virtual event will be 2978 * removed. 2979 * 2980 * Results: 2981 * The result is a standard Tcl return value. If an error occurs then the 2982 * interp's result will contain an error message. It is not an error to 2983 * attempt to delete a virtual event that does not exist or a definition 2984 * that does not exist. 2985 * 2986 * Side effects: 2987 * The virtual event given by virtString may be removed from the virtual 2988 * event table. 2989 * 2990 *-------------------------------------------------------------- 2991 */ 2992 2993static int 2994DeleteVirtualEvent( 2995 Tcl_Interp *interp, /* Used for error reporting. */ 2996 VirtualEventTable *vetPtr, /* Table in which to delete event. */ 2997 char *virtString, /* String describing event sequence that 2998 * triggers binding. */ 2999 char *eventString) /* The event sequence that should be deleted, 3000 * or NULL to delete all event sequences for 3001 * the entire virtual event. */ 3002{ 3003 int iPhys; 3004 Tk_Uid virtUid; 3005 Tcl_HashEntry *vhPtr; 3006 PhysicalsOwned *poPtr; 3007 PatSeq *eventPSPtr; 3008 3009 virtUid = GetVirtualEventUid(interp, virtString); 3010 if (virtUid == NULL) { 3011 return TCL_ERROR; 3012 } 3013 3014 vhPtr = Tcl_FindHashEntry(&vetPtr->nameTable, virtUid); 3015 if (vhPtr == NULL) { 3016 return TCL_OK; 3017 } 3018 poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr); 3019 3020 eventPSPtr = NULL; 3021 if (eventString != NULL) { 3022 unsigned long eventMask; 3023 3024 /* 3025 * Delete only the specific physical event associated with the virtual 3026 * event. If the physical event doesn't already exist, or the virtual 3027 * event doesn't own that physical event, return w/o doing anything. 3028 */ 3029 3030 eventPSPtr = FindSequence(interp, &vetPtr->patternTable, NULL, 3031 eventString, 0, 0, &eventMask); 3032 if (eventPSPtr == NULL) { 3033 const char *string = Tcl_GetStringResult(interp); 3034 3035 return (string[0] != '\0') ? TCL_ERROR : TCL_OK; 3036 } 3037 } 3038 3039 for (iPhys = poPtr->numOwned; --iPhys >= 0; ) { 3040 PatSeq *psPtr = poPtr->patSeqs[iPhys]; 3041 3042 if ((eventPSPtr == NULL) || (psPtr == eventPSPtr)) { 3043 int iVirt; 3044 VirtualOwners *voPtr; 3045 3046 /* 3047 * Remove association between this physical event and the given 3048 * virtual event that it triggers. 3049 */ 3050 3051 voPtr = psPtr->voPtr; 3052 for (iVirt = 0; iVirt < voPtr->numOwners; iVirt++) { 3053 if (voPtr->owners[iVirt] == vhPtr) { 3054 break; 3055 } 3056 } 3057 if (iVirt == voPtr->numOwners) { 3058 Tcl_Panic("DeleteVirtualEvent: couldn't find owner"); 3059 } 3060 voPtr->numOwners--; 3061 if (voPtr->numOwners == 0) { 3062 /* 3063 * Removed last reference to this physical event, so remove it 3064 * from physical->virtual map. 3065 */ 3066 3067 PatSeq *prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr); 3068 3069 if (prevPtr == psPtr) { 3070 if (psPtr->nextSeqPtr == NULL) { 3071 Tcl_DeleteHashEntry(psPtr->hPtr); 3072 } else { 3073 Tcl_SetHashValue(psPtr->hPtr, 3074 psPtr->nextSeqPtr); 3075 } 3076 } else { 3077 for ( ; ; prevPtr = prevPtr->nextSeqPtr) { 3078 if (prevPtr == NULL) { 3079 Tcl_Panic("DeleteVirtualEvent couldn't find on hash chain"); 3080 } 3081 if (prevPtr->nextSeqPtr == psPtr) { 3082 prevPtr->nextSeqPtr = psPtr->nextSeqPtr; 3083 break; 3084 } 3085 } 3086 } 3087 ckfree((char *) psPtr->voPtr); 3088 ckfree((char *) psPtr); 3089 } else { 3090 /* 3091 * This physical event still triggers some other virtual 3092 * event(s). Consolidate the list of virtual owners for this 3093 * physical event so it no longer triggers the given virtual 3094 * event. 3095 */ 3096 3097 voPtr->owners[iVirt] = voPtr->owners[voPtr->numOwners]; 3098 } 3099 3100 /* 3101 * Now delete the virtual event's reference to the physical event. 3102 */ 3103 3104 poPtr->numOwned--; 3105 if (eventPSPtr != NULL && poPtr->numOwned != 0) { 3106 /* 3107 * Just deleting this one physical event. Consolidate list of 3108 * owned physical events and return. 3109 */ 3110 3111 poPtr->patSeqs[iPhys] = poPtr->patSeqs[poPtr->numOwned]; 3112 return TCL_OK; 3113 } 3114 } 3115 } 3116 3117 if (poPtr->numOwned == 0) { 3118 /* 3119 * All the physical events for this virtual event were deleted, either 3120 * because there was only one associated physical event or because the 3121 * caller was deleting the entire virtual event. Now the virtual event 3122 * itself should be deleted. 3123 */ 3124 3125 ckfree((char *) poPtr); 3126 Tcl_DeleteHashEntry(vhPtr); 3127 } 3128 return TCL_OK; 3129} 3130 3131/* 3132 *--------------------------------------------------------------------------- 3133 * 3134 * GetVirtualEvent -- 3135 * 3136 * Return the list of physical events that can invoke the given virtual 3137 * event. 3138 * 3139 * Results: 3140 * The return value is TCL_OK and the interp's result is filled with the 3141 * string representation of the physical events associated with the 3142 * virtual event; if there are no physical events for the given virtual 3143 * event, the interp's result is filled with and empty string. If the 3144 * virtual event string is improperly formed, then TCL_ERROR is returned 3145 * and an error message is left in the interp's result. 3146 * 3147 * Side effects: 3148 * None. 3149 * 3150 *--------------------------------------------------------------------------- 3151 */ 3152 3153static int 3154GetVirtualEvent( 3155 Tcl_Interp *interp, /* Interpreter for reporting. */ 3156 VirtualEventTable *vetPtr, /* Table in which to look for event. */ 3157 char *virtString) /* String describing virtual event. */ 3158{ 3159 Tcl_HashEntry *vhPtr; 3160 Tcl_DString ds; 3161 int iPhys; 3162 PhysicalsOwned *poPtr; 3163 Tk_Uid virtUid; 3164 3165 virtUid = GetVirtualEventUid(interp, virtString); 3166 if (virtUid == NULL) { 3167 return TCL_ERROR; 3168 } 3169 3170 vhPtr = Tcl_FindHashEntry(&vetPtr->nameTable, virtUid); 3171 if (vhPtr == NULL) { 3172 return TCL_OK; 3173 } 3174 3175 Tcl_DStringInit(&ds); 3176 3177 poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr); 3178 for (iPhys = 0; iPhys < poPtr->numOwned; iPhys++) { 3179 Tcl_DStringSetLength(&ds, 0); 3180 GetPatternString(poPtr->patSeqs[iPhys], &ds); 3181 Tcl_AppendElement(interp, Tcl_DStringValue(&ds)); 3182 } 3183 Tcl_DStringFree(&ds); 3184 3185 return TCL_OK; 3186} 3187 3188/* 3189 *-------------------------------------------------------------- 3190 * 3191 * GetAllVirtualEvents -- 3192 * 3193 * Return a list that contains the names of all the virtual event 3194 * defined. 3195 * 3196 * Results: 3197 * There is no return value. The interp's result is modified to hold a 3198 * Tcl list with one entry for each virtual event in nameTable. 3199 * 3200 * Side effects: 3201 * None. 3202 * 3203 *-------------------------------------------------------------- 3204 */ 3205 3206static void 3207GetAllVirtualEvents( 3208 Tcl_Interp *interp, /* Interpreter returning result. */ 3209 VirtualEventTable *vetPtr) /* Table containing events. */ 3210{ 3211 Tcl_HashEntry *hPtr; 3212 Tcl_HashSearch search; 3213 Tcl_DString ds; 3214 3215 Tcl_DStringInit(&ds); 3216 3217 hPtr = Tcl_FirstHashEntry(&vetPtr->nameTable, &search); 3218 for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { 3219 Tcl_DStringSetLength(&ds, 0); 3220 Tcl_DStringAppend(&ds, "<<", 2); 3221 Tcl_DStringAppend(&ds, Tcl_GetHashKey(hPtr->tablePtr, hPtr), -1); 3222 Tcl_DStringAppend(&ds, ">>", 2); 3223 Tcl_AppendElement(interp, Tcl_DStringValue(&ds)); 3224 } 3225 3226 Tcl_DStringFree(&ds); 3227} 3228 3229/* 3230 *--------------------------------------------------------------------------- 3231 * 3232 * HandleEventGenerate -- 3233 * 3234 * Helper function for the "event generate" command. Generate and process 3235 * an XEvent, constructed from information parsed from the event 3236 * description string and its optional arguments. 3237 * 3238 * argv[0] contains name of the target window. 3239 * argv[1] contains pattern string for one event (e.g, <Control-v>). 3240 * argv[2..argc-1] contains -field/option pairs for specifying additional 3241 * detail in the generated event. 3242 * 3243 * Either virtual or physical events can be generated this way. The event 3244 * description string must contain the specification for only one event. 3245 * 3246 * Results: 3247 * None. 3248 * 3249 * Side effects: 3250 * When constructing the event, 3251 * event.xany.serial is filled with the current X serial number. 3252 * event.xany.window is filled with the target window. 3253 * event.xany.display is filled with the target window's display. 3254 * Any other fields in eventPtr which are not specified by the pattern 3255 * string or the optional arguments, are set to 0. 3256 * 3257 * The event may be handled sychronously or asynchronously, depending on 3258 * the value specified by the optional "-when" option. The default 3259 * setting is synchronous. 3260 * 3261 *--------------------------------------------------------------------------- 3262 */ 3263 3264static int 3265HandleEventGenerate( 3266 Tcl_Interp *interp, /* Interp for errors return and name lookup. */ 3267 Tk_Window mainWin, /* Main window associated with interp. */ 3268 int objc, /* Number of arguments. */ 3269 Tcl_Obj *const objv[]) /* Argument objects. */ 3270{ 3271 union {XEvent general; XVirtualEvent virtual;} event; 3272 const char *p; 3273 char *name, *windowName; 3274 int count, flags, synch, i, number, warp; 3275 Tcl_QueuePosition pos; 3276 Pattern pat; 3277 Tk_Window tkwin, tkwin2; 3278 TkWindow *mainPtr; 3279 unsigned long eventMask; 3280 Tcl_Obj *userDataObj; 3281 static const char *fieldStrings[] = { 3282 "-when", "-above", "-borderwidth", "-button", 3283 "-count", "-data", "-delta", "-detail", 3284 "-focus", "-height", 3285 "-keycode", "-keysym", "-mode", "-override", 3286 "-place", "-root", "-rootx", "-rooty", 3287 "-sendevent", "-serial", "-state", "-subwindow", 3288 "-time", "-warp", "-width", "-window", 3289 "-x", "-y", NULL 3290 }; 3291 enum field { 3292 EVENT_WHEN, EVENT_ABOVE, EVENT_BORDER, EVENT_BUTTON, 3293 EVENT_COUNT, EVENT_DATA, EVENT_DELTA, EVENT_DETAIL, 3294 EVENT_FOCUS, EVENT_HEIGHT, 3295 EVENT_KEYCODE, EVENT_KEYSYM, EVENT_MODE, EVENT_OVERRIDE, 3296 EVENT_PLACE, EVENT_ROOT, EVENT_ROOTX, EVENT_ROOTY, 3297 EVENT_SEND, EVENT_SERIAL, EVENT_STATE, EVENT_SUBWINDOW, 3298 EVENT_TIME, EVENT_WARP, EVENT_WIDTH, EVENT_WINDOW, 3299 EVENT_X, EVENT_Y 3300 }; 3301 3302 windowName = Tcl_GetString(objv[0]); 3303 if (!windowName[0]) { 3304 tkwin = mainWin; 3305 } else if (NameToWindow(interp, mainWin, objv[0], &tkwin) != TCL_OK) { 3306 return TCL_ERROR; 3307 } 3308 3309 mainPtr = (TkWindow *) mainWin; 3310 if ((tkwin == NULL) 3311 || (mainPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr)) { 3312 Tcl_AppendResult(interp, "window id \"", Tcl_GetString(objv[0]), 3313 "\" doesn't exist in this application", NULL); 3314 return TCL_ERROR; 3315 } 3316 3317 name = Tcl_GetString(objv[1]); 3318 3319 p = name; 3320 eventMask = 0; 3321 userDataObj = NULL; 3322 count = ParseEventDescription(interp, &p, &pat, &eventMask); 3323 if (count == 0) { 3324 return TCL_ERROR; 3325 } 3326 if (count != 1) { 3327 Tcl_SetResult(interp, "Double or Triple modifier not allowed", 3328 TCL_STATIC); 3329 return TCL_ERROR; 3330 } 3331 if (*p != '\0') { 3332 Tcl_SetResult(interp, "only one event specification allowed", 3333 TCL_STATIC); 3334 return TCL_ERROR; 3335 } 3336 3337 memset((void *) &event, 0, sizeof(event)); 3338 event.general.xany.type = pat.eventType; 3339 event.general.xany.serial = NextRequest(Tk_Display(tkwin)); 3340 event.general.xany.send_event = False; 3341 if (windowName[0]) { 3342 event.general.xany.window = Tk_WindowId(tkwin); 3343 } else { 3344 event.general.xany.window = 3345 RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin)); 3346 } 3347 event.general.xany.display = Tk_Display(tkwin); 3348 3349 flags = flagArray[event.general.xany.type]; 3350 if (flags & DESTROY) { 3351 /* 3352 * Event DestroyNotify should be generated by destroying the window. 3353 */ 3354 3355 Tk_DestroyWindow(tkwin); 3356 return TCL_OK; 3357 } 3358 if (flags & KEY_BUTTON_MOTION_VIRTUAL) { 3359 event.general.xkey.state = pat.needMods; 3360 if ((flags & KEY) && (event.general.xany.type != MouseWheelEvent)) { 3361 TkpSetKeycodeAndState(tkwin, pat.detail.keySym, &event.general); 3362 } else if (flags & BUTTON) { 3363 event.general.xbutton.button = pat.detail.button; 3364 } else if (flags & VIRTUAL) { 3365 event.virtual.name = pat.detail.name; 3366 } 3367 } 3368 if (flags & (CREATE|UNMAP|MAP|REPARENT|CONFIG|GRAVITY|CIRC)) { 3369 event.general.xcreatewindow.window = event.general.xany.window; 3370 } 3371 3372 if (flags & KEY_BUTTON_MOTION_CROSSING) { 3373 event.general.xkey.x_root = -1; 3374 event.general.xkey.y_root = -1; 3375 } 3376 3377 /* 3378 * Process the remaining arguments to fill in additional fields of the 3379 * event. 3380 */ 3381 3382 synch = 1; 3383 warp = 0; 3384 pos = TCL_QUEUE_TAIL; 3385 for (i = 2; i < objc; i += 2) { 3386 Tcl_Obj *optionPtr, *valuePtr; 3387 int index; 3388 3389 optionPtr = objv[i]; 3390 valuePtr = objv[i + 1]; 3391 3392 if (Tcl_GetIndexFromObj(interp, optionPtr, fieldStrings, "option", 3393 TCL_EXACT, &index) != TCL_OK) { 3394 return TCL_ERROR; 3395 } 3396 if (objc & 1) { 3397 /* 3398 * This test occurs after Tcl_GetIndexFromObj() so that "event 3399 * generate <Button> -xyz" will return the error message that 3400 * "-xyz" is a bad option, rather than that the value for "-xyz" 3401 * is missing. 3402 */ 3403 3404 Tcl_AppendResult(interp, "value for \"", Tcl_GetString(optionPtr), 3405 "\" missing", NULL); 3406 return TCL_ERROR; 3407 } 3408 3409 switch ((enum field) index) { 3410 case EVENT_WARP: 3411 if (Tcl_GetBooleanFromObj(interp, valuePtr, &warp) != TCL_OK) { 3412 return TCL_ERROR; 3413 } 3414 if (!(flags & KEY_BUTTON_MOTION_VIRTUAL)) { 3415 goto badopt; 3416 } 3417 break; 3418 case EVENT_WHEN: 3419 pos = (Tcl_QueuePosition) TkFindStateNumObj(interp, optionPtr, 3420 queuePosition, valuePtr); 3421 if ((int) pos < -1) { 3422 return TCL_ERROR; 3423 } 3424 synch = 0; 3425 if ((int) pos == -1) { 3426 synch = 1; 3427 } 3428 break; 3429 case EVENT_ABOVE: 3430 if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) { 3431 return TCL_ERROR; 3432 } 3433 if (flags & CONFIG) { 3434 event.general.xconfigure.above = Tk_WindowId(tkwin2); 3435 } else { 3436 goto badopt; 3437 } 3438 break; 3439 case EVENT_BORDER: 3440 if (Tk_GetPixelsFromObj(interp,tkwin,valuePtr,&number) != TCL_OK) { 3441 return TCL_ERROR; 3442 } 3443 if (flags & (CREATE|CONFIG)) { 3444 event.general.xcreatewindow.border_width = number; 3445 } else { 3446 goto badopt; 3447 } 3448 break; 3449 case EVENT_BUTTON: 3450 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { 3451 return TCL_ERROR; 3452 } 3453 if (flags & BUTTON) { 3454 event.general.xbutton.button = number; 3455 } else { 3456 goto badopt; 3457 } 3458 break; 3459 case EVENT_COUNT: 3460 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { 3461 return TCL_ERROR; 3462 } 3463 if (flags & EXPOSE) { 3464 event.general.xexpose.count = number; 3465 } else { 3466 goto badopt; 3467 } 3468 break; 3469 case EVENT_DATA: 3470 if (flags & VIRTUAL) { 3471 /* 3472 * Do not increment reference count until after parsing 3473 * completes and we know that the event generation is really 3474 * going to happen. 3475 */ 3476 3477 userDataObj = valuePtr; 3478 } else { 3479 goto badopt; 3480 } 3481 break; 3482 case EVENT_DELTA: 3483 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { 3484 return TCL_ERROR; 3485 } 3486 if ((flags & KEY) && (event.general.xkey.type == MouseWheelEvent)) { 3487 event.general.xkey.keycode = number; 3488 } else { 3489 goto badopt; 3490 } 3491 break; 3492 case EVENT_DETAIL: 3493 number = TkFindStateNumObj(interp, optionPtr, notifyDetail, 3494 valuePtr); 3495 if (number < 0) { 3496 return TCL_ERROR; 3497 } 3498 if (flags & FOCUS) { 3499 event.general.xfocus.detail = number; 3500 } else if (flags & CROSSING) { 3501 event.general.xcrossing.detail = number; 3502 } else { 3503 goto badopt; 3504 } 3505 break; 3506 case EVENT_FOCUS: 3507 if (Tcl_GetBooleanFromObj(interp, valuePtr, &number) != TCL_OK) { 3508 return TCL_ERROR; 3509 } 3510 if (flags & CROSSING) { 3511 event.general.xcrossing.focus = number; 3512 } else { 3513 goto badopt; 3514 } 3515 break; 3516 case EVENT_HEIGHT: 3517 if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, 3518 &number) != TCL_OK) { 3519 return TCL_ERROR; 3520 } 3521 if (flags & EXPOSE) { 3522 event.general.xexpose.height = number; 3523 } else if (flags & CONFIG) { 3524 event.general.xconfigure.height = number; 3525 } else { 3526 goto badopt; 3527 } 3528 break; 3529 case EVENT_KEYCODE: 3530 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { 3531 return TCL_ERROR; 3532 } 3533 if ((flags & KEY) && (event.general.xkey.type != MouseWheelEvent)) { 3534 event.general.xkey.keycode = number; 3535 } else { 3536 goto badopt; 3537 } 3538 break; 3539 case EVENT_KEYSYM: { 3540 KeySym keysym; 3541 char *value; 3542 3543 value = Tcl_GetString(valuePtr); 3544 keysym = TkStringToKeysym(value); 3545 if (keysym == NoSymbol) { 3546 Tcl_AppendResult(interp, "unknown keysym \"", value, "\"", 3547 NULL); 3548 return TCL_ERROR; 3549 } 3550 3551 TkpSetKeycodeAndState(tkwin, keysym, &event.general); 3552 if (event.general.xkey.keycode == 0) { 3553 Tcl_AppendResult(interp, "no keycode for keysym \"", value, 3554 "\"", NULL); 3555 return TCL_ERROR; 3556 } 3557 if (!(flags & KEY) 3558 || (event.general.xkey.type == MouseWheelEvent)) { 3559 goto badopt; 3560 } 3561 break; 3562 } 3563 case EVENT_MODE: 3564 number = TkFindStateNumObj(interp,optionPtr,notifyMode,valuePtr); 3565 if (number < 0) { 3566 return TCL_ERROR; 3567 } 3568 if (flags & CROSSING) { 3569 event.general.xcrossing.mode = number; 3570 } else if (flags & FOCUS) { 3571 event.general.xfocus.mode = number; 3572 } else { 3573 goto badopt; 3574 } 3575 break; 3576 case EVENT_OVERRIDE: 3577 if (Tcl_GetBooleanFromObj(interp, valuePtr, &number) != TCL_OK) { 3578 return TCL_ERROR; 3579 } 3580 if (flags & CREATE) { 3581 event.general.xcreatewindow.override_redirect = number; 3582 } else if (flags & MAP) { 3583 event.general.xmap.override_redirect = number; 3584 } else if (flags & REPARENT) { 3585 event.general.xreparent.override_redirect = number; 3586 } else if (flags & CONFIG) { 3587 event.general.xconfigure.override_redirect = number; 3588 } else { 3589 goto badopt; 3590 } 3591 break; 3592 case EVENT_PLACE: 3593 number = TkFindStateNumObj(interp, optionPtr, circPlace, valuePtr); 3594 if (number < 0) { 3595 return TCL_ERROR; 3596 } 3597 if (flags & CIRC) { 3598 event.general.xcirculate.place = number; 3599 } else { 3600 goto badopt; 3601 } 3602 break; 3603 case EVENT_ROOT: 3604 if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) { 3605 return TCL_ERROR; 3606 } 3607 if (flags & KEY_BUTTON_MOTION_CROSSING) { 3608 event.general.xkey.root = Tk_WindowId(tkwin2); 3609 } else { 3610 goto badopt; 3611 } 3612 break; 3613 case EVENT_ROOTX: 3614 if (Tk_GetPixelsFromObj(interp,tkwin,valuePtr,&number) != TCL_OK) { 3615 return TCL_ERROR; 3616 } 3617 if (flags & KEY_BUTTON_MOTION_CROSSING) { 3618 event.general.xkey.x_root = number; 3619 } else { 3620 goto badopt; 3621 } 3622 break; 3623 case EVENT_ROOTY: 3624 if (Tk_GetPixelsFromObj(interp,tkwin,valuePtr,&number) != TCL_OK) { 3625 return TCL_ERROR; 3626 } 3627 if (flags & KEY_BUTTON_MOTION_CROSSING) { 3628 event.general.xkey.y_root = number; 3629 } else { 3630 goto badopt; 3631 } 3632 break; 3633 case EVENT_SEND: { 3634 const char *value; 3635 3636 value = Tcl_GetString(valuePtr); 3637 if (isdigit(UCHAR(value[0]))) { 3638 /* 3639 * Allow arbitrary integer values for the field; they are 3640 * needed by a few of the tests in the Tk test suite. 3641 */ 3642 3643 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { 3644 return TCL_ERROR; 3645 } 3646 } else { 3647 if (Tcl_GetBooleanFromObj(interp,valuePtr,&number) != TCL_OK) { 3648 return TCL_ERROR; 3649 } 3650 } 3651 event.general.xany.send_event = number; 3652 break; 3653 } 3654 case EVENT_SERIAL: 3655 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { 3656 return TCL_ERROR; 3657 } 3658 event.general.xany.serial = number; 3659 break; 3660 case EVENT_STATE: 3661 if (flags & KEY_BUTTON_MOTION_CROSSING) { 3662 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { 3663 return TCL_ERROR; 3664 } 3665 if (flags & KEY_BUTTON_MOTION_VIRTUAL) { 3666 event.general.xkey.state = number; 3667 } else { 3668 event.general.xcrossing.state = number; 3669 } 3670 } else if (flags & VISIBILITY) { 3671 number = TkFindStateNumObj(interp, optionPtr, visNotify, 3672 valuePtr); 3673 if (number < 0) { 3674 return TCL_ERROR; 3675 } 3676 event.general.xvisibility.state = number; 3677 } else { 3678 goto badopt; 3679 } 3680 break; 3681 case EVENT_SUBWINDOW: 3682 if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) { 3683 return TCL_ERROR; 3684 } 3685 if (flags & KEY_BUTTON_MOTION_CROSSING) { 3686 event.general.xkey.subwindow = Tk_WindowId(tkwin2); 3687 } else { 3688 goto badopt; 3689 } 3690 break; 3691 case EVENT_TIME: 3692 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) { 3693 return TCL_ERROR; 3694 } 3695 if (flags & KEY_BUTTON_MOTION_CROSSING) { 3696 event.general.xkey.time = (Time) number; 3697 } else if (flags & PROP) { 3698 event.general.xproperty.time = (Time) number; 3699 } else { 3700 goto badopt; 3701 } 3702 break; 3703 case EVENT_WIDTH: 3704 if (Tk_GetPixelsFromObj(interp,tkwin,valuePtr,&number) != TCL_OK) { 3705 return TCL_ERROR; 3706 } 3707 if (flags & EXPOSE) { 3708 event.general.xexpose.width = number; 3709 } else if (flags & (CREATE|CONFIG)) { 3710 event.general.xcreatewindow.width = number; 3711 } else { 3712 goto badopt; 3713 } 3714 break; 3715 case EVENT_WINDOW: 3716 if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) { 3717 return TCL_ERROR; 3718 } 3719 if (flags & (CREATE|UNMAP|MAP|REPARENT|CONFIG|GRAVITY|CIRC)) { 3720 event.general.xcreatewindow.window = Tk_WindowId(tkwin2); 3721 } else { 3722 goto badopt; 3723 } 3724 break; 3725 case EVENT_X: 3726 if (Tk_GetPixelsFromObj(interp,tkwin,valuePtr,&number) != TCL_OK) { 3727 return TCL_ERROR; 3728 } 3729 if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) { 3730 event.general.xkey.x = number; 3731 3732 /* 3733 * Only modify rootx as well if it hasn't been changed. 3734 */ 3735 3736 if (event.general.xkey.x_root == -1) { 3737 int rootX, rootY; 3738 3739 Tk_GetRootCoords(tkwin, &rootX, &rootY); 3740 event.general.xkey.x_root = rootX + number; 3741 } 3742 } else if (flags & EXPOSE) { 3743 event.general.xexpose.x = number; 3744 } else if (flags & (CREATE|CONFIG|GRAVITY)) { 3745 event.general.xcreatewindow.x = number; 3746 } else if (flags & REPARENT) { 3747 event.general.xreparent.x = number; 3748 } else { 3749 goto badopt; 3750 } 3751 break; 3752 case EVENT_Y: 3753 if (Tk_GetPixelsFromObj(interp,tkwin,valuePtr,&number) != TCL_OK) { 3754 return TCL_ERROR; 3755 } 3756 if (flags & KEY_BUTTON_MOTION_CROSSING) { 3757 event.general.xkey.y = number; 3758 3759 /* 3760 * Only modify rooty as well if it hasn't been changed. 3761 */ 3762 3763 if (event.general.xkey.y_root == -1) { 3764 int rootX, rootY; 3765 3766 Tk_GetRootCoords(tkwin, &rootX, &rootY); 3767 event.general.xkey.y_root = rootY + number; 3768 } 3769 } else if (flags & EXPOSE) { 3770 event.general.xexpose.y = number; 3771 } else if (flags & (CREATE|CONFIG|GRAVITY)) { 3772 event.general.xcreatewindow.y = number; 3773 } else if (flags & REPARENT) { 3774 event.general.xreparent.y = number; 3775 } else { 3776 goto badopt; 3777 } 3778 break; 3779 } 3780 continue; 3781 3782 badopt: 3783 Tcl_AppendResult(interp, name, " event doesn't accept \"", 3784 Tcl_GetString(optionPtr), "\" option", NULL); 3785 return TCL_ERROR; 3786 } 3787 3788 /* 3789 * Don't generate events for windows that don't exist yet. 3790 */ 3791 3792 if (!event.general.xany.window) { 3793 goto done; 3794 } 3795 3796 if (userDataObj != NULL) { 3797 XVirtualEvent *vePtr = (XVirtualEvent *) &event; 3798 3799 /* 3800 * Must be virtual event to set that variable to non-NULL. Now we want 3801 * to install the object into the event. Note that we must incr the 3802 * refcount before firing it into the low-level event subsystem; the 3803 * refcount will be decremented once the event has been processed. 3804 */ 3805 3806 vePtr->user_data = userDataObj; 3807 Tcl_IncrRefCount(userDataObj); 3808 } 3809 3810 /* 3811 * Now we have constructed the event, inject it into the event handling 3812 * code. 3813 */ 3814 3815 if (synch != 0) { 3816 Tk_HandleEvent(&event.general); 3817 } else { 3818 Tk_QueueWindowEvent(&event.general, pos); 3819 } 3820 3821 /* 3822 * We only allow warping if the window is mapped. 3823 */ 3824 3825 if ((warp != 0) && Tk_IsMapped(tkwin)) { 3826 TkDisplay *dispPtr = TkGetDisplay(event.general.xmotion.display); 3827 3828 if (!(dispPtr->flags & TK_DISPLAY_IN_WARP)) { 3829 Tcl_DoWhenIdle(DoWarp, (ClientData) dispPtr); 3830 dispPtr->flags |= TK_DISPLAY_IN_WARP; 3831 } 3832 dispPtr->warpWindow = event.general.xany.window; 3833 dispPtr->warpX = event.general.xkey.x; 3834 dispPtr->warpY = event.general.xkey.y; 3835 } 3836 3837done: 3838 Tcl_ResetResult(interp); 3839 return TCL_OK; 3840} 3841 3842static int 3843NameToWindow( 3844 Tcl_Interp *interp, /* Interp for error return and name lookup. */ 3845 Tk_Window mainWin, /* Main window of application. */ 3846 Tcl_Obj *objPtr, /* Contains name or id string of window. */ 3847 Tk_Window *tkwinPtr) /* Filled with token for window. */ 3848{ 3849 char *name; 3850 Tk_Window tkwin; 3851 Window id; 3852 3853 name = Tcl_GetString(objPtr); 3854 if (name[0] == '.') { 3855 tkwin = Tk_NameToWindow(interp, name, mainWin); 3856 if (tkwin == NULL) { 3857 return TCL_ERROR; 3858 } 3859 *tkwinPtr = tkwin; 3860 } else { 3861 /* 3862 * Check for the winPtr being valid, even if it looks ok to 3863 * TkpScanWindowId. [Bug #411307] 3864 */ 3865 3866 if ((TkpScanWindowId(NULL, name, &id) != TCL_OK) || 3867 ((*tkwinPtr = Tk_IdToWindow(Tk_Display(mainWin), id)) 3868 == NULL)) { 3869 Tcl_AppendResult(interp, "bad window name/identifier \"", 3870 name, "\"", NULL); 3871 return TCL_ERROR; 3872 } 3873 } 3874 return TCL_OK; 3875} 3876 3877/* 3878 *------------------------------------------------------------------------- 3879 * 3880 * DoWarp -- 3881 * 3882 * Perform Warping of X pointer. Executed as an idle handler only. 3883 * 3884 * Results: 3885 * None 3886 * 3887 * Side effects: 3888 * X Pointer will move to a new location. 3889 * 3890 *------------------------------------------------------------------------- 3891 */ 3892static void 3893DoWarp( 3894 ClientData clientData) 3895{ 3896 TkDisplay *dispPtr = (TkDisplay *) clientData; 3897 3898 XWarpPointer(dispPtr->display, (Window) None, (Window) dispPtr->warpWindow, 3899 0, 0, 0, 0, (int) dispPtr->warpX, (int) dispPtr->warpY); 3900 XForceScreenSaver(dispPtr->display, ScreenSaverReset); 3901 dispPtr->flags &= ~TK_DISPLAY_IN_WARP; 3902} 3903 3904/* 3905 *------------------------------------------------------------------------- 3906 * 3907 * GetVirtualEventUid -- 3908 * 3909 * Determine if the given string is in the proper format for a virtual 3910 * event. 3911 * 3912 * Results: 3913 * The return value is NULL if the virtual event string was not in the 3914 * proper format. In this case, an error message will be left in the 3915 * interp's result. Otherwise the return value is a Tk_Uid that 3916 * represents the virtual event. 3917 * 3918 * Side effects: 3919 * None. 3920 * 3921 *------------------------------------------------------------------------- 3922 */ 3923 3924static Tk_Uid 3925GetVirtualEventUid( 3926 Tcl_Interp *interp, 3927 char *virtString) 3928{ 3929 Tk_Uid uid; 3930 size_t length; 3931 3932 length = strlen(virtString); 3933 3934 if (length < 5 || virtString[0] != '<' || virtString[1] != '<' || 3935 virtString[length - 2] != '>' || virtString[length - 1] != '>') { 3936 Tcl_AppendResult(interp, "virtual event \"", virtString, 3937 "\" is badly formed", NULL); 3938 return NULL; 3939 } 3940 virtString[length - 2] = '\0'; 3941 uid = Tk_GetUid(virtString + 2); 3942 virtString[length - 2] = '>'; 3943 3944 return uid; 3945} 3946 3947/* 3948 *---------------------------------------------------------------------- 3949 * 3950 * FindSequence -- 3951 * 3952 * Find the entry in the pattern table that corresponds to a particular 3953 * pattern string, and return a pointer to that entry. 3954 * 3955 * Results: 3956 * The return value is normally a pointer to the PatSeq in patternTable 3957 * that corresponds to eventString. If an error was found while parsing 3958 * eventString, or if "create" is 0 and no pattern sequence previously 3959 * existed, then NULL is returned and the interp's result contains a 3960 * message describing the problem. If no pattern sequence previously 3961 * existed for eventString, then a new one is created with a NULL command 3962 * field. In a successful return, *maskPtr is filled in with a mask of 3963 * the event types on which the pattern sequence depends. 3964 * 3965 * Side effects: 3966 * A new pattern sequence may be allocated. 3967 * 3968 *---------------------------------------------------------------------- 3969 */ 3970 3971static PatSeq * 3972FindSequence( 3973 Tcl_Interp *interp, /* Interpreter to use for error reporting. */ 3974 Tcl_HashTable *patternTablePtr, 3975 /* Table to use for lookup. */ 3976 ClientData object, /* For binding table, token for object with 3977 * which binding is associated. For virtual 3978 * event table, NULL. */ 3979 const char *eventString, /* String description of pattern to match on. 3980 * See user documentation for details. */ 3981 int create, /* 0 means don't create the entry if it 3982 * doesn't already exist. Non-zero means 3983 * create. */ 3984 int allowVirtual, /* 0 means that virtual events are not allowed 3985 * in the sequence. Non-zero otherwise. */ 3986 unsigned long *maskPtr) /* *maskPtr is filled in with the event types 3987 * on which this pattern sequence depends. */ 3988{ 3989 Pattern pats[EVENT_BUFFER_SIZE]; 3990 int numPats, virtualFound; 3991 const char *p; 3992 Pattern *patPtr; 3993 PatSeq *psPtr; 3994 Tcl_HashEntry *hPtr; 3995 int flags, count, isNew; 3996 size_t sequenceSize; 3997 unsigned long eventMask; 3998 PatternTableKey key; 3999 4000 /* 4001 *------------------------------------------------------------- 4002 * Step 1: parse the pattern string to produce an array of Patterns. The 4003 * array is generated backwards, so that the lowest-indexed pattern 4004 * corresponds to the last event that must occur. 4005 *------------------------------------------------------------- 4006 */ 4007 4008 p = eventString; 4009 flags = 0; 4010 eventMask = 0; 4011 virtualFound = 0; 4012 4013 patPtr = &pats[EVENT_BUFFER_SIZE-1]; 4014 for (numPats = 0; numPats < EVENT_BUFFER_SIZE; numPats++, patPtr--) { 4015 while (isspace(UCHAR(*p))) { 4016 p++; 4017 } 4018 if (*p == '\0') { 4019 break; 4020 } 4021 4022 count = ParseEventDescription(interp, &p, patPtr, &eventMask); 4023 if (count == 0) { 4024 return NULL; 4025 } 4026 4027 if (eventMask & VirtualEventMask) { 4028 if (allowVirtual == 0) { 4029 Tcl_SetResult(interp, 4030 "virtual event not allowed in definition of another virtual event", 4031 TCL_STATIC); 4032 return NULL; 4033 } 4034 virtualFound = 1; 4035 } 4036 4037 /* 4038 * Replicate events for DOUBLE, TRIPLE, QUADRUPLE. 4039 */ 4040 4041 while ((count-- > 1) && (numPats < EVENT_BUFFER_SIZE-1)) { 4042 flags |= PAT_NEARBY; 4043 patPtr[-1] = patPtr[0]; 4044 patPtr--; 4045 numPats++; 4046 } 4047 } 4048 4049 /* 4050 *------------------------------------------------------------- 4051 * Step 2: find the sequence in the binding table if it exists, and add a 4052 * new sequence to the table if it doesn't. 4053 *------------------------------------------------------------- 4054 */ 4055 4056 if (numPats == 0) { 4057 Tcl_SetResult(interp, "no events specified in binding", TCL_STATIC); 4058 return NULL; 4059 } 4060 if ((numPats > 1) && (virtualFound != 0)) { 4061 Tcl_SetResult(interp, "virtual events may not be composed", 4062 TCL_STATIC); 4063 return NULL; 4064 } 4065 4066 patPtr = &pats[EVENT_BUFFER_SIZE-numPats]; 4067 memset(&key, 0, sizeof(key)); 4068 key.object = object; 4069 key.type = patPtr->eventType; 4070 key.detail = patPtr->detail; 4071 hPtr = Tcl_CreateHashEntry(patternTablePtr, (char *) &key, &isNew); 4072 sequenceSize = numPats*sizeof(Pattern); 4073 if (!isNew) { 4074 for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL; 4075 psPtr = psPtr->nextSeqPtr) { 4076 if ((numPats == psPtr->numPats) 4077 && ((flags & PAT_NEARBY) == (psPtr->flags & PAT_NEARBY)) 4078 && (memcmp((char *) patPtr, (char *) psPtr->pats, 4079 sequenceSize) == 0)) { 4080 goto done; 4081 } 4082 } 4083 } 4084 if (!create) { 4085 if (isNew) { 4086 Tcl_DeleteHashEntry(hPtr); 4087 } 4088 4089 /* 4090 * No binding exists for the sequence, so return an empty error. This 4091 * is a special error that the caller will check for in order to 4092 * silently ignore this case. This is a hack that maintains backward 4093 * compatibility for Tk_GetBinding but the various "bind" commands 4094 * silently ignore missing bindings. 4095 */ 4096 4097 return NULL; 4098 } 4099 psPtr = (PatSeq *) ckalloc((unsigned) (sizeof(PatSeq) 4100 + (numPats-1)*sizeof(Pattern))); 4101 psPtr->numPats = numPats; 4102 psPtr->eventProc = NULL; 4103 psPtr->freeProc = NULL; 4104 psPtr->clientData = NULL; 4105 psPtr->flags = flags; 4106 psPtr->refCount = 0; 4107 psPtr->nextSeqPtr = (PatSeq *) Tcl_GetHashValue(hPtr); 4108 psPtr->hPtr = hPtr; 4109 psPtr->voPtr = NULL; 4110 psPtr->nextObjPtr = NULL; 4111 Tcl_SetHashValue(hPtr, psPtr); 4112 4113 memcpy((void *) psPtr->pats, (void *) patPtr, sequenceSize); 4114 4115 done: 4116 *maskPtr = eventMask; 4117 return psPtr; 4118} 4119 4120/* 4121 *--------------------------------------------------------------------------- 4122 * 4123 * ParseEventDescription -- 4124 * 4125 * Fill Pattern buffer with information about event from event string. 4126 * 4127 * Results: 4128 * Leaves error message in interp and returns 0 if there was an error due 4129 * to a badly formed event string. Returns 1 if proper event was 4130 * specified, 2 if Double modifier was used in event string, or 3 if 4131 * Triple was used. 4132 * 4133 * Side effects: 4134 * On exit, eventStringPtr points to rest of event string (after the 4135 * closing '>', so that this function can be called repeatedly to parse 4136 * all the events in the entire sequence. 4137 * 4138 *--------------------------------------------------------------------------- 4139 */ 4140 4141static int 4142ParseEventDescription( 4143 Tcl_Interp *interp, /* For error messages. */ 4144 const char **eventStringPtr,/* On input, holds a pointer to start of event 4145 * string. On exit, gets pointer to rest of 4146 * string after parsed event. */ 4147 Pattern *patPtr, /* Filled with the pattern parsed from the 4148 * event string. */ 4149 unsigned long *eventMaskPtr)/* Filled with event mask of matched event. */ 4150{ 4151 char *p; 4152 unsigned long eventMask; 4153 int count, eventFlags; 4154#define FIELD_SIZE 48 4155 char field[FIELD_SIZE]; 4156 Tcl_HashEntry *hPtr; 4157 Tcl_DString copy; 4158 4159 Tcl_DStringInit(©); 4160 p = Tcl_DStringAppend(©, *eventStringPtr, -1); 4161 4162 patPtr->eventType = -1; 4163 patPtr->needMods = 0; 4164 patPtr->detail.clientData = 0; 4165 4166 eventMask = 0; 4167 count = 1; 4168 4169 /* 4170 * Handle simple ASCII characters. 4171 */ 4172 4173 if (*p != '<') { 4174 char string[2]; 4175 4176 patPtr->eventType = KeyPress; 4177 eventMask = KeyPressMask; 4178 string[0] = *p; 4179 string[1] = 0; 4180 patPtr->detail.keySym = TkStringToKeysym(string); 4181 if (patPtr->detail.keySym == NoSymbol) { 4182 if (isprint(UCHAR(*p))) { 4183 patPtr->detail.keySym = *p; 4184 } else { 4185 char buf[64]; 4186 4187 sprintf(buf, "bad ASCII character 0x%x", (unsigned char) *p); 4188 Tcl_SetResult(interp, buf, TCL_VOLATILE); 4189 count = 0; 4190 goto done; 4191 } 4192 } 4193 p++; 4194 goto end; 4195 } 4196 4197 /* 4198 * A fancier event description. This can be either a virtual event or a 4199 * physical event. 4200 * 4201 * A virtual event description consists of: 4202 * 4203 * 1. double open angle brackets. 4204 * 2. virtual event name. 4205 * 3. double close angle brackets. 4206 * 4207 * A physical event description consists of: 4208 * 4209 * 1. open angle bracket. 4210 * 2. any number of modifiers, each followed by spaces or dashes. 4211 * 3. an optional event name. 4212 * 4. an option button or keysym name. Either this or item 3 *must* be 4213 * present; if both are present then they are separated by spaces or 4214 * dashes. 4215 * 5. a close angle bracket. 4216 */ 4217 4218 p++; 4219 if (*p == '<') { 4220 /* 4221 * This is a virtual event: soak up all the characters up to the next 4222 * '>'. 4223 */ 4224 4225 char *field = p + 1; 4226 4227 p = strchr(field, '>'); 4228 if (p == field) { 4229 Tcl_SetResult(interp, "virtual event \"<<>>\" is badly formed", 4230 TCL_STATIC); 4231 count = 0; 4232 goto done; 4233 } 4234 if ((p == NULL) || (p[1] != '>')) { 4235 Tcl_SetResult(interp, "missing \">\" in virtual binding", 4236 TCL_STATIC); 4237 count = 0; 4238 goto done; 4239 } 4240 *p = '\0'; 4241 patPtr->eventType = VirtualEvent; 4242 eventMask = VirtualEventMask; 4243 patPtr->detail.name = Tk_GetUid(field); 4244 *p = '>'; 4245 4246 p += 2; 4247 goto end; 4248 } 4249 4250 while (1) { 4251 ModInfo *modPtr; 4252 4253 p = GetField(p, field, FIELD_SIZE); 4254 if (*p == '>') { 4255 /* 4256 * This solves the problem of, e.g., <Control-M> being 4257 * misinterpreted as Control + Meta + missing keysym instead of 4258 * Control + KeyPress + M. 4259 */ 4260 4261 break; 4262 } 4263 hPtr = Tcl_FindHashEntry(&modTable, field); 4264 if (hPtr == NULL) { 4265 break; 4266 } 4267 modPtr = (ModInfo *) Tcl_GetHashValue(hPtr); 4268 patPtr->needMods |= modPtr->mask; 4269 if (modPtr->flags & MULT_CLICKS) { 4270 int i = modPtr->flags & MULT_CLICKS; 4271 4272 count = 2; 4273 while (i >>= 1) { 4274 count++; 4275 } 4276 } 4277 while ((*p == '-') || isspace(UCHAR(*p))) { 4278 p++; 4279 } 4280 } 4281 4282 eventFlags = 0; 4283 hPtr = Tcl_FindHashEntry(&eventTable, field); 4284 if (hPtr != NULL) { 4285 EventInfo *eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); 4286 4287 patPtr->eventType = eiPtr->type; 4288 eventFlags = flagArray[eiPtr->type]; 4289 eventMask = eiPtr->eventMask; 4290 while ((*p == '-') || isspace(UCHAR(*p))) { 4291 p++; 4292 } 4293 p = GetField(p, field, FIELD_SIZE); 4294 } 4295 if (*field != '\0') { 4296 if ((*field >= '1') && (*field <= '5') && (field[1] == '\0')) { 4297 if (eventFlags == 0) { 4298 patPtr->eventType = ButtonPress; 4299 eventMask = ButtonPressMask; 4300 } else if (eventFlags & KEY) { 4301 goto getKeysym; 4302 } else if ((eventFlags & BUTTON) == 0) { 4303 Tcl_AppendResult(interp, "specified button \"", field, 4304 "\" for non-button event", NULL); 4305 count = 0; 4306 goto done; 4307 } 4308 patPtr->detail.button = (*field - '0'); 4309 } else { 4310 4311 getKeysym: 4312 patPtr->detail.keySym = TkStringToKeysym(field); 4313 if (patPtr->detail.keySym == NoSymbol) { 4314 Tcl_AppendResult(interp, "bad event type or keysym \"", 4315 field, "\"", NULL); 4316 count = 0; 4317 goto done; 4318 } 4319 if (eventFlags == 0) { 4320 patPtr->eventType = KeyPress; 4321 eventMask = KeyPressMask; 4322 } else if ((eventFlags & KEY) == 0) { 4323 Tcl_AppendResult(interp, "specified keysym \"", field, 4324 "\" for non-key event", NULL); 4325 count = 0; 4326 goto done; 4327 } 4328 } 4329 } else if (eventFlags == 0) { 4330 Tcl_SetResult(interp, "no event type or button # or keysym", 4331 TCL_STATIC); 4332 count = 0; 4333 goto done; 4334 } 4335 4336 while ((*p == '-') || isspace(UCHAR(*p))) { 4337 p++; 4338 } 4339 if (*p != '>') { 4340 while (*p != '\0') { 4341 p++; 4342 if (*p == '>') { 4343 Tcl_SetResult(interp, 4344 "extra characters after detail in binding", 4345 TCL_STATIC); 4346 count = 0; 4347 goto done; 4348 } 4349 } 4350 Tcl_SetResult(interp, "missing \">\" in binding", TCL_STATIC); 4351 count = 0; 4352 goto done; 4353 } 4354 p++; 4355 4356 end: 4357 *eventStringPtr += (p - Tcl_DStringValue(©)); 4358 *eventMaskPtr |= eventMask; 4359 done: 4360 Tcl_DStringFree(©); 4361 return count; 4362} 4363 4364/* 4365 *---------------------------------------------------------------------- 4366 * 4367 * GetField -- 4368 * 4369 * Used to parse pattern descriptions. Copies up to size characters from 4370 * p to copy, stopping at end of string, space, "-", ">", or whenever 4371 * size is exceeded. 4372 * 4373 * Results: 4374 * The return value is a pointer to the character just after the last one 4375 * copied (usually "-" or space or ">", but could be anything if size was 4376 * exceeded). Also places NULL-terminated string (up to size character, 4377 * including NULL), at copy. 4378 * 4379 * Side effects: 4380 * None. 4381 * 4382 *---------------------------------------------------------------------- 4383 */ 4384 4385static char * 4386GetField( 4387 char *p, /* Pointer to part of pattern. */ 4388 char *copy, /* Place to copy field. */ 4389 int size) /* Maximum number of characters to copy. */ 4390{ 4391 while ((*p != '\0') && !isspace(UCHAR(*p)) && (*p != '>') 4392 && (*p != '-') && (size > 1)) { 4393 *copy = *p; 4394 p++; 4395 copy++; 4396 size--; 4397 } 4398 *copy = '\0'; 4399 return p; 4400} 4401 4402/* 4403 *--------------------------------------------------------------------------- 4404 * 4405 * GetPatternString -- 4406 * 4407 * Produce a string version of the given event, for displaying to the 4408 * user. 4409 * 4410 * Results: 4411 * The string is left in dsPtr. 4412 * 4413 * Side effects: 4414 * It is the caller's responsibility to initialize the DString before and 4415 * to free it after calling this function. 4416 * 4417 *--------------------------------------------------------------------------- 4418 */ 4419 4420static void 4421GetPatternString( 4422 PatSeq *psPtr, 4423 Tcl_DString *dsPtr) 4424{ 4425 Pattern *patPtr; 4426 char c, buffer[TCL_INTEGER_SPACE]; 4427 int patsLeft, needMods; 4428 ModInfo *modPtr; 4429 EventInfo *eiPtr; 4430 4431 /* 4432 * The order of the patterns in the sequence is backwards from the order 4433 * in which they must be output. 4434 */ 4435 4436 for (patsLeft = psPtr->numPats, patPtr = &psPtr->pats[psPtr->numPats - 1]; 4437 patsLeft > 0; patsLeft--, patPtr--) { 4438 /* 4439 * Check for simple case of an ASCII character. 4440 */ 4441 4442 if ((patPtr->eventType == KeyPress) 4443 && ((psPtr->flags & PAT_NEARBY) == 0) 4444 && (patPtr->needMods == 0) 4445 && (patPtr->detail.keySym < 128) 4446 && isprint(UCHAR(patPtr->detail.keySym)) 4447 && (patPtr->detail.keySym != '<') 4448 && (patPtr->detail.keySym != ' ')) { 4449 c = (char) patPtr->detail.keySym; 4450 Tcl_DStringAppend(dsPtr, &c, 1); 4451 continue; 4452 } 4453 4454 /* 4455 * Check for virtual event. 4456 */ 4457 4458 if (patPtr->eventType == VirtualEvent) { 4459 Tcl_DStringAppend(dsPtr, "<<", 2); 4460 Tcl_DStringAppend(dsPtr, patPtr->detail.name, -1); 4461 Tcl_DStringAppend(dsPtr, ">>", 2); 4462 continue; 4463 } 4464 4465 /* 4466 * It's a more general event specification. First check for "Double", 4467 * "Triple", "Quadruple", then modifiers, then event type, then keysym 4468 * or button detail. 4469 */ 4470 4471 Tcl_DStringAppend(dsPtr, "<", 1); 4472 4473 if ((psPtr->flags & PAT_NEARBY) && (patsLeft > 1) 4474 && (memcmp((char *) patPtr, (char *) (patPtr-1), 4475 sizeof(Pattern)) == 0)) { 4476 patsLeft--; 4477 patPtr--; 4478 if ((patsLeft > 1) && (memcmp((char *) patPtr, 4479 (char *) (patPtr-1), sizeof(Pattern)) == 0)) { 4480 patsLeft--; 4481 patPtr--; 4482 if ((patsLeft > 1) && (memcmp((char *) patPtr, 4483 (char *) (patPtr-1), sizeof(Pattern)) == 0)) { 4484 patsLeft--; 4485 patPtr--; 4486 Tcl_DStringAppend(dsPtr, "Quadruple-", 10); 4487 } else { 4488 Tcl_DStringAppend(dsPtr, "Triple-", 7); 4489 } 4490 } else { 4491 Tcl_DStringAppend(dsPtr, "Double-", 7); 4492 } 4493 } 4494 4495 for (needMods = patPtr->needMods, modPtr = modArray; 4496 needMods != 0; modPtr++) { 4497 if (modPtr->mask & needMods) { 4498 needMods &= ~modPtr->mask; 4499 Tcl_DStringAppend(dsPtr, modPtr->name, -1); 4500 Tcl_DStringAppend(dsPtr, "-", 1); 4501 } 4502 } 4503 4504 for (eiPtr = eventArray; eiPtr->name != NULL; eiPtr++) { 4505 if (eiPtr->type == patPtr->eventType) { 4506 Tcl_DStringAppend(dsPtr, eiPtr->name, -1); 4507 if (patPtr->detail.clientData != 0) { 4508 Tcl_DStringAppend(dsPtr, "-", 1); 4509 } 4510 break; 4511 } 4512 } 4513 4514 if (patPtr->detail.clientData != 0) { 4515 if ((patPtr->eventType == KeyPress) 4516 || (patPtr->eventType == KeyRelease)) { 4517 char *string = TkKeysymToString(patPtr->detail.keySym); 4518 if (string != NULL) { 4519 Tcl_DStringAppend(dsPtr, string, -1); 4520 } 4521 } else { 4522 sprintf(buffer, "%d", patPtr->detail.button); 4523 Tcl_DStringAppend(dsPtr, buffer, -1); 4524 } 4525 } 4526 4527 Tcl_DStringAppend(dsPtr, ">", 1); 4528 } 4529} 4530 4531/* 4532 *--------------------------------------------------------------------------- 4533 * 4534 * EvalTclBinding -- 4535 * 4536 * The function that is invoked by Tk_BindEvent when a Tcl binding is 4537 * fired. 4538 * 4539 * Results: 4540 * A standard Tcl result code, the result of globally evaluating the 4541 * percent-substitued binding string. 4542 * 4543 * Side effects: 4544 * Normal side effects due to eval. 4545 * 4546 *--------------------------------------------------------------------------- 4547 */ 4548 4549static void 4550FreeTclBinding( 4551 ClientData clientData) 4552{ 4553 ckfree((char *) clientData); 4554} 4555 4556/* 4557 *---------------------------------------------------------------------- 4558 * 4559 * TkStringToKeysym -- 4560 * 4561 * This function finds the keysym associated with a given keysym name. 4562 * 4563 * Results: 4564 * The return value is the keysym that corresponds to name, or NoSymbol 4565 * if there is no such keysym. 4566 * 4567 * Side effects: 4568 * None. 4569 * 4570 *---------------------------------------------------------------------- 4571 */ 4572 4573KeySym 4574TkStringToKeysym( 4575 char *name) /* Name of a keysym. */ 4576{ 4577#ifdef REDO_KEYSYM_LOOKUP 4578 Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&keySymTable, name); 4579 4580 if (hPtr != NULL) { 4581 return (KeySym) Tcl_GetHashValue(hPtr); 4582 } 4583 if (strlen(name) == 1) { 4584 KeySym keysym = (KeySym) (unsigned char) name[0]; 4585 4586 if (TkKeysymToString(keysym) != NULL) { 4587 return keysym; 4588 } 4589 } 4590#endif /* REDO_KEYSYM_LOOKUP */ 4591 return XStringToKeysym(name); 4592} 4593 4594/* 4595 *---------------------------------------------------------------------- 4596 * 4597 * TkKeysymToString -- 4598 * 4599 * This function finds the keysym name associated with a given keysym. 4600 * 4601 * Results: 4602 * The return value is a pointer to a static string containing the name 4603 * of the given keysym, or NULL if there is no known name. 4604 * 4605 * Side effects: 4606 * None. 4607 * 4608 *---------------------------------------------------------------------- 4609 */ 4610 4611char * 4612TkKeysymToString( 4613 KeySym keysym) 4614{ 4615#ifdef REDO_KEYSYM_LOOKUP 4616 Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&nameTable, (char *)keysym); 4617 4618 if (hPtr != NULL) { 4619 return (char *) Tcl_GetHashValue(hPtr); 4620 } 4621#endif /* REDO_KEYSYM_LOOKUP */ 4622 4623 return XKeysymToString(keysym); 4624} 4625 4626/* 4627 *---------------------------------------------------------------------- 4628 * 4629 * TkCopyAndGlobalEval -- 4630 * 4631 * This function makes a copy of a script then calls Tcl_GlobalEval to 4632 * evaluate it. It's used in situations where the execution of a command 4633 * may cause the original command string to be reallocated. 4634 * 4635 * Results: 4636 * Returns the result of evaluating script, including both a standard Tcl 4637 * completion code and a string in the interp's result. 4638 * 4639 * Side effects: 4640 * Any; depends on script. 4641 * 4642 *---------------------------------------------------------------------- 4643 */ 4644 4645int 4646TkCopyAndGlobalEval( 4647 Tcl_Interp *interp, /* Interpreter in which to evaluate script. */ 4648 char *script) /* Script to evaluate. */ 4649{ 4650 Tcl_DString buffer; 4651 int code; 4652 4653 Tcl_DStringInit(&buffer); 4654 Tcl_DStringAppend(&buffer, script, -1); 4655 code = Tcl_EvalEx(interp, Tcl_DStringValue(&buffer), 4656 Tcl_DStringLength(&buffer), TCL_EVAL_GLOBAL); 4657 Tcl_DStringFree(&buffer); 4658 return code; 4659} 4660 4661/* 4662 *---------------------------------------------------------------------- 4663 * 4664 * TkpGetBindingXEvent -- 4665 * 4666 * This function returns the XEvent associated with the currently 4667 * executing binding. This function can only be invoked while a binding 4668 * is executing. 4669 * 4670 * Results: 4671 * Returns a pointer to the XEvent that caused the current binding code 4672 * to be run. 4673 * 4674 * Side effects: 4675 * None. 4676 * 4677 *---------------------------------------------------------------------- 4678 */ 4679 4680XEvent * 4681TkpGetBindingXEvent( 4682 Tcl_Interp *interp) /* Interpreter. */ 4683{ 4684 TkWindow *winPtr = (TkWindow *) Tk_MainWindow(interp); 4685 BindingTable *bindPtr = (BindingTable *) winPtr->mainPtr->bindingTable; 4686 4687 return &(bindPtr->eventRing[bindPtr->curEvent]); 4688} 4689 4690/* 4691 * Local Variables: 4692 * mode: c 4693 * c-basic-offset: 4 4694 * fill-column: 78 4695 * End: 4696 */ 4697