4 * This file provides procedures that associate Tcl commands
5 * with X events or sequences of X events.
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.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
24 #if !(defined(__WIN32__) || defined(MAC_TCL) || defined(MAC_OSX_TK)) /* UNIX */
25 #include "tkUnixInt.h"
32 * Structure definitions and static variables.
34 * Init/Free this package.
36 * Tcl "bind" command (actually located in tkCmds.c).
37 * "bind" command implementation.
38 * "bind" implementation helpers.
40 * Tcl "event" command.
41 * "event" command implementation.
42 * "event" implementation helpers.
44 * Package-specific common helpers.
46 * Non-package-specific helpers.
51 * The following union is used to hold the detail information from an
52 * XEvent (including Tk's XVirtualEvent extension).
55 KeySym keySym; /* KeySym that corresponds to xkey.keycode. */
56 int button; /* Button that was pressed (xbutton.button). */
57 Tk_Uid name; /* Tk_Uid of virtual event. */
58 ClientData clientData; /* Used when type of Detail is unknown, and to
59 * ensure that all bytes of Detail are initialized
60 * when this structure is used in a hash key. */
64 * The structure below represents a binding table. A binding table
65 * represents a domain in which event bindings may occur. It includes
66 * a space of objects relative to which events occur (usually windows,
67 * but not always), a history of recent events in the domain, and
68 * a set of mappings that associate particular Tcl commands with sequences
69 * of events in the domain. Multiple binding tables may exist at once,
70 * either because there are multiple applications open, or because there
71 * are multiple domains within an application with separate event
72 * bindings for each (for example, each canvas widget has a separate
73 * binding table for associating events with the items in the canvas).
75 * Note: it is probably a bad idea to reduce EVENT_BUFFER_SIZE much
76 * below 30. To see this, consider a triple mouse button click while
77 * the Shift key is down (and auto-repeating). There may be as many
78 * as 3 auto-repeat events after each mouse button press or release
79 * (see the first large comment block within Tk_BindEvent for more on
80 * this), for a total of 20 events to cover the three button presses
81 * and two intervening releases. If you reduce EVENT_BUFFER_SIZE too
82 * much, shift multi-clicks will be lost.
86 #define EVENT_BUFFER_SIZE 30
87 typedef struct BindingTable {
88 XEvent eventRing[EVENT_BUFFER_SIZE];/* Circular queue of recent events
89 * (higher indices are for more recent
91 Detail detailRing[EVENT_BUFFER_SIZE];/* "Detail" information (keySym,
92 * button, Tk_Uid, or 0) for each
93 * entry in eventRing. */
94 int curEvent; /* Index in eventRing of most recent
95 * event. Newer events have higher
97 Tcl_HashTable patternTable; /* Used to map from an event to a
98 * list of patterns that may match that
99 * event. Keys are PatternTableKey
100 * structs, values are (PatSeq *). */
101 Tcl_HashTable objectTable; /* Used to map from an object to a
102 * list of patterns associated with
103 * that object. Keys are ClientData,
104 * values are (PatSeq *). */
105 Tcl_Interp *interp; /* Interpreter in which commands are
110 * The following structure represents virtual event table. A virtual event
111 * table provides a way to map from platform-specific physical events such
112 * as button clicks or key presses to virtual events such as <<Paste>>,
113 * <<Close>>, or <<ScrollWindow>>.
115 * A virtual event is usually never part of the event stream, but instead is
116 * synthesized inline by matching low-level events. However, a virtual
117 * event may be generated by platform-specific code or by Tcl scripts. In
118 * that case, no lookup of the virtual event will need to be done using
119 * this table, because the virtual event is actually in the event stream.
122 typedef struct VirtualEventTable {
123 Tcl_HashTable patternTable; /* Used to map from a physical event to
124 * a list of patterns that may match that
125 * event. Keys are PatternTableKey
126 * structs, values are (PatSeq *). */
127 Tcl_HashTable nameTable; /* Used to map a virtual event name to
128 * the array of physical events that can
129 * trigger it. Keys are the Tk_Uid names
130 * of the virtual events, values are
131 * PhysicalsOwned structs. */
135 * The following structure is used as a key in a patternTable for both
136 * binding tables and a virtual event tables.
138 * In a binding table, the object field corresponds to the binding tag
139 * for the widget whose bindings are being accessed.
141 * In a virtual event table, the object field is always NULL. Virtual
142 * events are a global definiton and are not tied to a particular
145 * The same key is used for both types of pattern tables so that the
146 * helper functions that traverse and match patterns will work for both
147 * binding tables and virtual event tables.
149 typedef struct PatternTableKey {
150 ClientData object; /* For binding table, identifies the binding
151 * tag of the object (or class of objects)
152 * relative to which the event occurred.
153 * For virtual event table, always NULL. */
154 int type; /* Type of event (from X). */
155 Detail detail; /* Additional information, such as keysym,
156 * button, Tk_Uid, or 0 if nothing
161 * The following structure defines a pattern, which is matched against X
162 * events as part of the process of converting X events into Tcl commands.
165 typedef struct Pattern {
166 int eventType; /* Type of X event, e.g. ButtonPress. */
167 int needMods; /* Mask of modifiers that must be
168 * present (0 means no modifiers are
170 Detail detail; /* Additional information that must
171 * match event. Normally this is 0,
172 * meaning no additional information
173 * must match. For KeyPress and
174 * KeyRelease events, a keySym may
175 * be specified to select a
176 * particular keystroke (0 means any
177 * keystrokes). For button events,
178 * specifies a particular button (0
179 * means any buttons are OK). For virtual
180 * events, specifies the Tk_Uid of the
181 * virtual event name (never 0). */
185 * The following structure defines a pattern sequence, which consists of one
186 * or more patterns. In order to trigger, a pattern sequence must match
187 * the most recent X events (first pattern to most recent event, next
188 * pattern to next event, and so on). It is used as the hash value in a
189 * patternTable for both binding tables and virtual event tables.
191 * In a binding table, it is the sequence of physical events that make up
192 * a binding for an object.
194 * In a virtual event table, it is the sequence of physical events that
195 * define a virtual event.
197 * The same structure is used for both types of pattern tables so that the
198 * helper functions that traverse and match patterns will work for both
199 * binding tables and virtual event tables.
202 typedef struct PatSeq {
203 int numPats; /* Number of patterns in sequence (usually
205 TkBindEvalProc *eventProc; /* The procedure that will be invoked on
206 * the clientData when this pattern sequence
208 TkBindFreeProc *freeProc; /* The procedure that will be invoked to
209 * release the clientData when this pattern
210 * sequence is freed. */
211 ClientData clientData; /* Arbitray data passed to eventProc and
212 * freeProc when sequence matches. */
213 int flags; /* Miscellaneous flag values; see below for
215 int refCount; /* Number of times that this binding is in
216 * the midst of executing. If greater than 1,
217 * then a recursive invocation is happening.
218 * Only when this is zero can the binding
219 * actually be freed. */
220 struct PatSeq *nextSeqPtr; /* Next in list of all pattern sequences
221 * that have the same initial pattern. NULL
222 * means end of list. */
223 Tcl_HashEntry *hPtr; /* Pointer to hash table entry for the
224 * initial pattern. This is the head of the
225 * list of which nextSeqPtr forms a part. */
226 struct VirtualOwners *voPtr;/* In a binding table, always NULL. In a
227 * virtual event table, identifies the array
228 * of virtual events that can be triggered by
230 struct PatSeq *nextObjPtr; /* In a binding table, next in list of all
231 * pattern sequences for the same object (NULL
232 * for end of list). Needed to implement
233 * Tk_DeleteAllBindings. In a virtual event
234 * table, always NULL. */
235 Pattern pats[1]; /* Array of "numPats" patterns. Only one
236 * element is declared here but in actuality
237 * enough space will be allocated for "numPats"
238 * patterns. To match, pats[0] must match
239 * event n, pats[1] must match event n-1, etc.
244 * Flag values for PatSeq structures:
246 * PAT_NEARBY 1 means that all of the events matching
247 * this sequence must occur with nearby X
248 * and Y mouse coordinates and close in time.
249 * This is typically used to restrict multiple
251 * MARKED_DELETED 1 means that this binding has been marked as deleted
252 * and removed from the binding table, but its memory
253 * could not be released because it was already queued for
254 * execution. When the binding is actually about to be
255 * executed, this flag will be checked and the binding
259 #define PAT_NEARBY 0x1
260 #define MARKED_DELETED 0x2
263 * Constants that define how close together two events must be
264 * in milliseconds or pixels to meet the PAT_NEARBY constraint:
267 #define NEARBY_PIXELS 5
268 #define NEARBY_MS 500
272 * The following structure keeps track of all the virtual events that are
273 * associated with a particular physical event. It is pointed to by the
274 * voPtr field in a PatSeq in the patternTable of a virtual event table.
277 typedef struct VirtualOwners {
278 int numOwners; /* Number of virtual events to trigger. */
279 Tcl_HashEntry *owners[1]; /* Array of pointers to entries in
280 * nameTable. Enough space will
281 * actually be allocated for numOwners
286 * The following structure is used in the nameTable of a virtual event
287 * table to associate a virtual event with all the physical events that can
290 typedef struct PhysicalsOwned {
291 int numOwned; /* Number of physical events owned. */
292 PatSeq *patSeqs[1]; /* Array of pointers to physical event
293 * patterns. Enough space will actually
294 * be allocated to hold numOwned. */
298 * One of the following structures exists for each interpreter. This
299 * structure keeps track of the current display and screen in the
300 * interpreter, so that a script can be invoked whenever the display/screen
301 * changes (the script does things like point tk::Priv at a display-specific
306 TkDisplay *curDispPtr; /* Display for last binding command invoked
307 * in this application. */
308 int curScreenIndex; /* Index of screen for last binding command. */
309 int bindingDepth; /* Number of active instances of Tk_BindEvent
310 * in this application. */
314 * The following structure is used to keep track of all the C bindings that
315 * are awaiting invocation and whether the window they refer to has been
316 * destroyed. If the window is destroyed, then all pending callbacks for
317 * that window will be cancelled. The Tcl bindings will still all be
321 typedef struct PendingBinding {
322 struct PendingBinding *nextPtr;
323 /* Next in chain of pending bindings, in
324 * case a recursive binding evaluation is in
326 Tk_Window tkwin; /* The window that the following bindings
328 int deleted; /* Set to non-zero by window cleanup code
329 * if tkwin is deleted. */
330 PatSeq *matchArray[5]; /* Array of pending C bindings. The actual
331 * size of this depends on how many C bindings
332 * matched the event passed to Tk_BindEvent.
333 * THIS FIELD MUST BE THE LAST IN THE
338 * The following structure keeps track of all the information local to
339 * the binding package on a per interpreter basis.
342 typedef struct BindInfo {
343 VirtualEventTable virtualEventTable;
344 /* The virtual events that exist in this
346 ScreenInfo screenInfo; /* Keeps track of the current display and
347 * screen, so it can be restored after
348 * a binding has executed. */
349 PendingBinding *pendingList;/* The list of pending C bindings, kept in
350 * case a C or Tcl binding causes the target
351 * window to be deleted. */
352 int deleted; /* 1 the application has been deleted but
353 * the structure has been preserved. */
357 * In X11R4 and earlier versions, XStringToKeysym is ridiculously
358 * slow. The data structure and hash table below, along with the
359 * code that uses them, implement a fast mapping from strings to
360 * keysyms. In X11R5 and later releases XStringToKeysym is plenty
361 * fast so this stuff isn't needed. The #define REDO_KEYSYM_LOOKUP
362 * is normally undefined, so that XStringToKeysym gets used. It
363 * can be set in the Makefile to enable the use of the hash table
367 #ifdef REDO_KEYSYM_LOOKUP
369 char *name; /* Name of keysym. */
370 KeySym value; /* Numeric identifier for keysym. */
372 static KeySymInfo keyArray[] = {
374 #include "ks_names.h"
378 static Tcl_HashTable keySymTable; /* keyArray hashed by keysym value. */
379 static Tcl_HashTable nameTable; /* keyArray hashed by keysym name. */
380 #endif /* REDO_KEYSYM_LOOKUP */
383 * Set to non-zero when the package-wide static variables have been
387 static int initialized = 0;
388 TCL_DECLARE_MUTEX(bindMutex)
391 * A hash table is kept to map from the string names of event
392 * modifiers to information about those modifiers. The structure
393 * for storing this information, and the hash table built at
394 * initialization time, are defined below.
398 char *name; /* Name of modifier. */
399 int mask; /* Button/modifier mask value, * such as Button1Mask. */
400 int flags; /* Various flags; see below for
405 * Flags for ModInfo structures:
407 * DOUBLE - Non-zero means duplicate this event,
408 * e.g. for double-clicks.
409 * TRIPLE - Non-zero means triplicate this event,
410 * e.g. for triple-clicks.
411 * QUADRUPLE - Non-zero means quadruple this event,
412 * e.g. for 4-fold-clicks.
413 * MULT_CLICKS - Combination of all of above.
419 #define MULT_CLICKS 7
421 static ModInfo modArray[] = {
422 {"Control", ControlMask, 0},
423 {"Shift", ShiftMask, 0},
424 {"Lock", LockMask, 0},
425 {"Meta", META_MASK, 0},
427 {"Alt", ALT_MASK, 0},
428 {"B1", Button1Mask, 0},
429 {"Button1", Button1Mask, 0},
430 {"B2", Button2Mask, 0},
431 {"Button2", Button2Mask, 0},
432 {"B3", Button3Mask, 0},
433 {"Button3", Button3Mask, 0},
434 {"B4", Button4Mask, 0},
435 {"Button4", Button4Mask, 0},
436 {"B5", Button5Mask, 0},
437 {"Button5", Button5Mask, 0},
438 {"Mod1", Mod1Mask, 0},
440 {"Command", Mod1Mask, 0},
441 {"Mod2", Mod2Mask, 0},
443 {"Option", Mod2Mask, 0},
444 {"Mod3", Mod3Mask, 0},
446 {"Mod4", Mod4Mask, 0},
448 {"Mod5", Mod5Mask, 0},
450 {"Double", 0, DOUBLE},
451 {"Triple", 0, TRIPLE},
452 {"Quadruple", 0, QUADRUPLE},
453 {"Any", 0, 0}, /* Ignored: historical relic. */
456 static Tcl_HashTable modTable;
459 * This module also keeps a hash table mapping from event names
460 * to information about those events. The structure, an array
461 * to use to initialize the hash table, and the hash table are
466 char *name; /* Name of event. */
467 int type; /* Event type for X, such as
469 int eventMask; /* Mask bits (for XSelectInput)
470 * for this event type. */
474 * Note: some of the masks below are an OR-ed combination of
475 * several masks. This is necessary because X doesn't report
476 * up events unless you also ask for down events. Also, X
477 * doesn't report button state in motion events unless you've
478 * asked about button events.
481 static EventInfo eventArray[] = {
482 {"Key", KeyPress, KeyPressMask},
483 {"KeyPress", KeyPress, KeyPressMask},
484 {"KeyRelease", KeyRelease, KeyPressMask|KeyReleaseMask},
485 {"Button", ButtonPress, ButtonPressMask},
486 {"ButtonPress", ButtonPress, ButtonPressMask},
487 {"ButtonRelease", ButtonRelease,
488 ButtonPressMask|ButtonReleaseMask},
489 {"Motion", MotionNotify,
490 ButtonPressMask|PointerMotionMask},
491 {"Enter", EnterNotify, EnterWindowMask},
492 {"Leave", LeaveNotify, LeaveWindowMask},
493 {"FocusIn", FocusIn, FocusChangeMask},
494 {"FocusOut", FocusOut, FocusChangeMask},
495 {"Expose", Expose, ExposureMask},
496 {"Visibility", VisibilityNotify, VisibilityChangeMask},
497 {"Destroy", DestroyNotify, StructureNotifyMask},
498 {"Unmap", UnmapNotify, StructureNotifyMask},
499 {"Map", MapNotify, StructureNotifyMask},
500 {"Reparent", ReparentNotify, StructureNotifyMask},
501 {"Configure", ConfigureNotify, StructureNotifyMask},
502 {"Gravity", GravityNotify, StructureNotifyMask},
503 {"Circulate", CirculateNotify, StructureNotifyMask},
504 {"Property", PropertyNotify, PropertyChangeMask},
505 {"Colormap", ColormapNotify, ColormapChangeMask},
506 {"Activate", ActivateNotify, ActivateMask},
507 {"Deactivate", DeactivateNotify, ActivateMask},
508 {"MouseWheel", MouseWheelEvent, MouseWheelMask},
509 {"CirculateRequest", CirculateRequest, SubstructureRedirectMask},
510 {"ConfigureRequest", ConfigureRequest, SubstructureRedirectMask},
511 {"Create", CreateNotify, SubstructureNotifyMask},
512 {"MapRequest", MapRequest, SubstructureRedirectMask},
513 {"ResizeRequest", ResizeRequest, ResizeRedirectMask},
514 {(char *) NULL, 0, 0}
516 static Tcl_HashTable eventTable;
519 * The defines and table below are used to classify events into
520 * various groups. The reason for this is that logically identical
521 * fields (e.g. "state") appear at different places in different
522 * types of events. The classification masks can be used to figure
523 * out quickly where to extract information from events.
532 #define VISIBILITY 0x40
534 #define DESTROY 0x100
537 #define REPARENT 0x800
538 #define CONFIG 0x1000
539 #define GRAVITY 0x2000
542 #define COLORMAP 0x10000
543 #define VIRTUAL 0x20000
544 #define ACTIVATE 0x40000
545 #define MAPREQ 0x80000
546 #define CONFIGREQ 0x100000
547 #define RESIZEREQ 0x200000
548 #define CIRCREQ 0x400000
550 #define KEY_BUTTON_MOTION_VIRTUAL (KEY|BUTTON|MOTION|VIRTUAL)
552 static int flagArray[TK_LASTEVENT] = {
556 /* KeyRelease */ KEY,
557 /* ButtonPress */ BUTTON,
558 /* ButtonRelease */ BUTTON,
559 /* MotionNotify */ MOTION,
560 /* EnterNotify */ CROSSING,
561 /* LeaveNotify */ CROSSING,
563 /* FocusOut */ FOCUS,
564 /* KeymapNotify */ 0,
566 /* GraphicsExpose */ EXPOSE,
568 /* VisibilityNotify */ VISIBILITY,
569 /* CreateNotify */ CREATE,
570 /* DestroyNotify */ DESTROY,
571 /* UnmapNotify */ UNMAP,
573 /* MapRequest */ MAPREQ,
574 /* ReparentNotify */ REPARENT,
575 /* ConfigureNotify */ CONFIG,
576 /* ConfigureRequest */ CONFIGREQ,
577 /* GravityNotify */ GRAVITY,
578 /* ResizeRequest */ RESIZEREQ,
579 /* CirculateNotify */ CIRC,
580 /* CirculateRequest */ 0,
581 /* PropertyNotify */ PROP,
582 /* SelectionClear */ 0,
583 /* SelectionRequest */ 0,
584 /* SelectionNotify */ 0,
585 /* ColormapNotify */ COLORMAP,
586 /* ClientMessage */ 0,
587 /* MappingNotify */ 0,
588 /* VirtualEvent */ VIRTUAL,
589 /* Activate */ ACTIVATE,
590 /* Deactivate */ ACTIVATE,
595 * The following table is used to map between the location where an
596 * generated event should be queued and the string used to specify the
600 static TkStateMap queuePosition[] = {
602 {TCL_QUEUE_HEAD, "head"},
603 {TCL_QUEUE_MARK, "mark"},
604 {TCL_QUEUE_TAIL, "tail"},
609 * The following tables are used as a two-way map between X's internal
610 * numeric values for fields in an XEvent and the strings used in Tcl. The
611 * tables are used both when constructing an XEvent from user input and
612 * when providing data from an XEvent to the user.
615 static TkStateMap notifyMode[] = {
616 {NotifyNormal, "NotifyNormal"},
617 {NotifyGrab, "NotifyGrab"},
618 {NotifyUngrab, "NotifyUngrab"},
619 {NotifyWhileGrabbed, "NotifyWhileGrabbed"},
623 static TkStateMap notifyDetail[] = {
624 {NotifyAncestor, "NotifyAncestor"},
625 {NotifyVirtual, "NotifyVirtual"},
626 {NotifyInferior, "NotifyInferior"},
627 {NotifyNonlinear, "NotifyNonlinear"},
628 {NotifyNonlinearVirtual, "NotifyNonlinearVirtual"},
629 {NotifyPointer, "NotifyPointer"},
630 {NotifyPointerRoot, "NotifyPointerRoot"},
631 {NotifyDetailNone, "NotifyDetailNone"},
635 static TkStateMap circPlace[] = {
636 {PlaceOnTop, "PlaceOnTop"},
637 {PlaceOnBottom, "PlaceOnBottom"},
641 static TkStateMap visNotify[] = {
642 {VisibilityUnobscured, "VisibilityUnobscured"},
643 {VisibilityPartiallyObscured, "VisibilityPartiallyObscured"},
644 {VisibilityFullyObscured, "VisibilityFullyObscured"},
648 static TkStateMap configureRequestDetail[] = {
652 {BottomIf, "BottomIf"},
654 {Opposite, "Opposite"},
658 static TkStateMap propNotify[] = {
659 {PropertyNewValue, "NewValue"},
660 {PropertyDelete, "Delete"},
665 * Prototypes for local procedures defined in this file:
668 static void ChangeScreen _ANSI_ARGS_((Tcl_Interp *interp,
669 char *dispName, int screenIndex));
670 static int CreateVirtualEvent _ANSI_ARGS_((Tcl_Interp *interp,
671 VirtualEventTable *vetPtr, char *virtString,
673 static int DeleteVirtualEvent _ANSI_ARGS_((Tcl_Interp *interp,
674 VirtualEventTable *vetPtr, char *virtString,
676 static void DeleteVirtualEventTable _ANSI_ARGS_((
677 VirtualEventTable *vetPtr));
678 static void ExpandPercents _ANSI_ARGS_((TkWindow *winPtr,
679 CONST char *before, XEvent *eventPtr, KeySym keySym,
680 Tcl_DString *dsPtr));
681 static void FreeTclBinding _ANSI_ARGS_((ClientData clientData));
682 static PatSeq * FindSequence _ANSI_ARGS_((Tcl_Interp *interp,
683 Tcl_HashTable *patternTablePtr, ClientData object,
684 CONST char *eventString, int create,
685 int allowVirtual, unsigned long *maskPtr));
686 static void GetAllVirtualEvents _ANSI_ARGS_((Tcl_Interp *interp,
687 VirtualEventTable *vetPtr));
688 static char * GetField _ANSI_ARGS_((char *p, char *copy, int size));
689 static void GetPatternString _ANSI_ARGS_((PatSeq *psPtr,
690 Tcl_DString *dsPtr));
691 static int GetVirtualEvent _ANSI_ARGS_((Tcl_Interp *interp,
692 VirtualEventTable *vetPtr, char *virtString));
693 static Tk_Uid GetVirtualEventUid _ANSI_ARGS_((Tcl_Interp *interp,
695 static int HandleEventGenerate _ANSI_ARGS_((Tcl_Interp *interp,
696 Tk_Window main, int objc,
697 Tcl_Obj *CONST objv[]));
698 static void InitVirtualEventTable _ANSI_ARGS_((
699 VirtualEventTable *vetPtr));
700 static PatSeq * MatchPatterns _ANSI_ARGS_((TkDisplay *dispPtr,
701 BindingTable *bindPtr, PatSeq *psPtr,
702 PatSeq *bestPtr, ClientData *objectPtr,
703 PatSeq **sourcePtrPtr));
704 static int NameToWindow _ANSI_ARGS_((Tcl_Interp *interp,
705 Tk_Window main, Tcl_Obj *objPtr,
706 Tk_Window *tkwinPtr));
707 static int ParseEventDescription _ANSI_ARGS_((Tcl_Interp *interp,
708 CONST char **eventStringPtr, Pattern *patPtr,
709 unsigned long *eventMaskPtr));
710 static void DoWarp _ANSI_ARGS_((ClientData clientData));
713 * The following define is used as a short circuit for the callback
714 * procedure to evaluate a TclBinding. The actual evaluation of the
715 * binding is handled inline, because special things have to be done
716 * with a Tcl binding before evaluation time.
719 #define EvalTclBinding ((TkBindEvalProc *) 1)
723 *---------------------------------------------------------------------------
727 * This procedure is called when an application is created. It
728 * initializes all the structures used by bindings and virtual
729 * events. It must be called before any other functions in this
738 *---------------------------------------------------------------------------
743 TkMainInfo *mainPtr; /* The newly created application. */
745 BindInfo *bindInfoPtr;
747 if (sizeof(XEvent) < sizeof(XVirtualEvent)) {
748 panic("TkBindInit: virtual events can't be supported");
752 * Initialize the static data structures used by the binding package.
753 * They are only initialized once, no matter how many interps are
758 Tcl_MutexLock(&bindMutex);
765 #ifdef REDO_KEYSYM_LOOKUP
768 Tcl_InitHashTable(&keySymTable, TCL_STRING_KEYS);
769 Tcl_InitHashTable(&nameTable, TCL_ONE_WORD_KEYS);
770 for (kPtr = keyArray; kPtr->name != NULL; kPtr++) {
771 hPtr = Tcl_CreateHashEntry(&keySymTable, kPtr->name, &dummy);
772 Tcl_SetHashValue(hPtr, kPtr->value);
773 hPtr = Tcl_CreateHashEntry(&nameTable, (char *) kPtr->value,
775 Tcl_SetHashValue(hPtr, kPtr->name);
777 #endif /* REDO_KEYSYM_LOOKUP */
779 Tcl_InitHashTable(&modTable, TCL_STRING_KEYS);
780 for (modPtr = modArray; modPtr->name != NULL; modPtr++) {
781 hPtr = Tcl_CreateHashEntry(&modTable, modPtr->name, &dummy);
782 Tcl_SetHashValue(hPtr, modPtr);
785 Tcl_InitHashTable(&eventTable, TCL_STRING_KEYS);
786 for (eiPtr = eventArray; eiPtr->name != NULL; eiPtr++) {
787 hPtr = Tcl_CreateHashEntry(&eventTable, eiPtr->name, &dummy);
788 Tcl_SetHashValue(hPtr, eiPtr);
792 Tcl_MutexUnlock(&bindMutex);
795 mainPtr->bindingTable = Tk_CreateBindingTable(mainPtr->interp);
797 bindInfoPtr = (BindInfo *) ckalloc(sizeof(BindInfo));
798 InitVirtualEventTable(&bindInfoPtr->virtualEventTable);
799 bindInfoPtr->screenInfo.curDispPtr = NULL;
800 bindInfoPtr->screenInfo.curScreenIndex = -1;
801 bindInfoPtr->screenInfo.bindingDepth = 0;
802 bindInfoPtr->pendingList = NULL;
803 bindInfoPtr->deleted = 0;
804 mainPtr->bindInfo = (TkBindInfo) bindInfoPtr;
806 TkpInitializeMenuBindings(mainPtr->interp, mainPtr->bindingTable);
810 *---------------------------------------------------------------------------
814 * This procedure is called when an application is deleted. It
815 * deletes all the structures used by bindings and virtual events.
823 *---------------------------------------------------------------------------
828 TkMainInfo *mainPtr; /* The newly created application. */
830 BindInfo *bindInfoPtr;
832 Tk_DeleteBindingTable(mainPtr->bindingTable);
833 mainPtr->bindingTable = NULL;
835 bindInfoPtr = (BindInfo *) mainPtr->bindInfo;
836 DeleteVirtualEventTable(&bindInfoPtr->virtualEventTable);
837 bindInfoPtr->deleted = 1;
838 Tcl_EventuallyFree((ClientData) bindInfoPtr, TCL_DYNAMIC);
839 mainPtr->bindInfo = NULL;
843 *--------------------------------------------------------------
845 * Tk_CreateBindingTable --
847 * Set up a new domain in which event bindings may be created.
850 * The return value is a token for the new table, which must
851 * be passed to procedures like Tk_CreateBinding.
854 * Memory is allocated for the new table.
856 *--------------------------------------------------------------
860 Tk_CreateBindingTable(interp)
861 Tcl_Interp *interp; /* Interpreter to associate with the binding
862 * table: commands are executed in this
865 BindingTable *bindPtr;
869 * Create and initialize a new binding table.
872 bindPtr = (BindingTable *) ckalloc(sizeof(BindingTable));
873 for (i = 0; i < EVENT_BUFFER_SIZE; i++) {
874 bindPtr->eventRing[i].type = -1;
876 bindPtr->curEvent = 0;
877 Tcl_InitHashTable(&bindPtr->patternTable,
878 sizeof(PatternTableKey)/sizeof(int));
879 Tcl_InitHashTable(&bindPtr->objectTable, TCL_ONE_WORD_KEYS);
880 bindPtr->interp = interp;
881 return (Tk_BindingTable) bindPtr;
885 *--------------------------------------------------------------
887 * Tk_DeleteBindingTable --
889 * Destroy a binding table and free up all its memory.
890 * The caller should not use bindingTable again after
891 * this procedure returns.
899 *--------------------------------------------------------------
903 Tk_DeleteBindingTable(bindingTable)
904 Tk_BindingTable bindingTable; /* Token for the binding table to
907 BindingTable *bindPtr = (BindingTable *) bindingTable;
908 PatSeq *psPtr, *nextPtr;
910 Tcl_HashSearch search;
913 * Find and delete all of the patterns associated with the binding
917 for (hPtr = Tcl_FirstHashEntry(&bindPtr->patternTable, &search);
918 hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
919 for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr);
920 psPtr != NULL; psPtr = nextPtr) {
921 nextPtr = psPtr->nextSeqPtr;
922 psPtr->flags |= MARKED_DELETED;
923 if (psPtr->refCount == 0) {
924 if (psPtr->freeProc != NULL) {
925 (*psPtr->freeProc)(psPtr->clientData);
927 ckfree((char *) psPtr);
933 * Clean up the rest of the information associated with the
937 Tcl_DeleteHashTable(&bindPtr->patternTable);
938 Tcl_DeleteHashTable(&bindPtr->objectTable);
939 ckfree((char *) bindPtr);
943 *--------------------------------------------------------------
945 * Tk_CreateBinding --
947 * Add a binding to a binding table, so that future calls to
948 * Tk_BindEvent may execute the command in the binding.
951 * The return value is 0 if an error occurred while setting
952 * up the binding. In this case, an error message will be
953 * left in the interp's result. If all went well then the return
954 * value is a mask of the event types that must be made
955 * available to Tk_BindEvent in order to properly detect when
956 * this binding triggers. This value can be used to determine
957 * what events to select for in a window, for example.
960 * An existing binding on the same event sequence may be
962 * The new binding may cause future calls to Tk_BindEvent to
963 * behave differently than they did previously.
965 *--------------------------------------------------------------
969 Tk_CreateBinding(interp, bindingTable, object, eventString, command, append)
970 Tcl_Interp *interp; /* Used for error reporting. */
971 Tk_BindingTable bindingTable;
972 /* Table in which to create binding. */
973 ClientData object; /* Token for object with which binding is
975 CONST char *eventString; /* String describing event sequence that
976 * triggers binding. */
977 CONST char *command; /* Contains Tcl command to execute when
978 * binding triggers. */
979 int append; /* 0 means replace any existing binding for
980 * eventString; 1 means append to that
981 * binding. If the existing binding is for a
982 * callback function and not a Tcl command
983 * string, the existing binding will always be
986 BindingTable *bindPtr = (BindingTable *) bindingTable;
988 unsigned long eventMask;
991 psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString,
996 if (psPtr->eventProc == NULL) {
1001 * This pattern sequence was just created.
1002 * Link the pattern into the list associated with the object, so
1003 * that if the object goes away, these bindings will all
1004 * automatically be deleted.
1007 hPtr = Tcl_CreateHashEntry(&bindPtr->objectTable, (char *) object,
1010 psPtr->nextObjPtr = NULL;
1012 psPtr->nextObjPtr = (PatSeq *) Tcl_GetHashValue(hPtr);
1014 Tcl_SetHashValue(hPtr, psPtr);
1015 } else if (psPtr->eventProc != EvalTclBinding) {
1017 * Free existing procedural binding.
1020 if (psPtr->freeProc != NULL) {
1021 (*psPtr->freeProc)(psPtr->clientData);
1023 psPtr->clientData = NULL;
1027 old = (char *) psPtr->clientData;
1028 if ((append != 0) && (old != NULL)) {
1031 length = strlen(old) + strlen(command) + 2;
1032 new = (char *) ckalloc((unsigned) length);
1033 sprintf(new, "%s\n%s", old, command);
1035 new = (char *) ckalloc((unsigned) strlen(command) + 1);
1036 strcpy(new, command);
1041 psPtr->eventProc = EvalTclBinding;
1042 psPtr->freeProc = FreeTclBinding;
1043 psPtr->clientData = (ClientData) new;
1048 *---------------------------------------------------------------------------
1050 * TkCreateBindingProcedure --
1052 * Add a C binding to a binding table, so that future calls to
1053 * Tk_BindEvent may callback the procedure in the binding.
1056 * The return value is 0 if an error occurred while setting
1057 * up the binding. In this case, an error message will be
1058 * left in the interp's result. If all went well then the return
1059 * value is a mask of the event types that must be made
1060 * available to Tk_BindEvent in order to properly detect when
1061 * this binding triggers. This value can be used to determine
1062 * what events to select for in a window, for example.
1065 * Any existing binding on the same event sequence will be
1068 *---------------------------------------------------------------------------
1072 TkCreateBindingProcedure(interp, bindingTable, object, eventString,
1073 eventProc, freeProc, clientData)
1074 Tcl_Interp *interp; /* Used for error reporting. */
1075 Tk_BindingTable bindingTable;
1076 /* Table in which to create binding. */
1077 ClientData object; /* Token for object with which binding is
1079 CONST char *eventString; /* String describing event sequence that
1080 * triggers binding. */
1081 TkBindEvalProc *eventProc; /* Procedure to invoke when binding
1082 * triggers. Must not be NULL. */
1083 TkBindFreeProc *freeProc; /* Procedure to invoke when binding is
1084 * freed. May be NULL for no procedure. */
1085 ClientData clientData; /* Arbitrary ClientData to pass to eventProc
1088 BindingTable *bindPtr = (BindingTable *) bindingTable;
1090 unsigned long eventMask;
1092 psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString,
1094 if (psPtr == NULL) {
1097 if (psPtr->eventProc == NULL) {
1099 Tcl_HashEntry *hPtr;
1102 * This pattern sequence was just created.
1103 * Link the pattern into the list associated with the object, so
1104 * that if the object goes away, these bindings will all
1105 * automatically be deleted.
1108 hPtr = Tcl_CreateHashEntry(&bindPtr->objectTable, (char *) object,
1111 psPtr->nextObjPtr = NULL;
1113 psPtr->nextObjPtr = (PatSeq *) Tcl_GetHashValue(hPtr);
1115 Tcl_SetHashValue(hPtr, psPtr);
1119 * Free existing callback.
1122 if (psPtr->freeProc != NULL) {
1123 (*psPtr->freeProc)(psPtr->clientData);
1127 psPtr->eventProc = eventProc;
1128 psPtr->freeProc = freeProc;
1129 psPtr->clientData = clientData;
1134 *--------------------------------------------------------------
1136 * Tk_DeleteBinding --
1138 * Remove an event binding from a binding table.
1141 * The result is a standard Tcl return value. If an error
1142 * occurs then the interp's result will contain an error message.
1145 * The binding given by object and eventString is removed
1146 * from bindingTable.
1148 *--------------------------------------------------------------
1152 Tk_DeleteBinding(interp, bindingTable, object, eventString)
1153 Tcl_Interp *interp; /* Used for error reporting. */
1154 Tk_BindingTable bindingTable; /* Table in which to delete binding. */
1155 ClientData object; /* Token for object with which binding
1157 CONST char *eventString; /* String describing event sequence
1158 * that triggers binding. */
1160 BindingTable *bindPtr = (BindingTable *) bindingTable;
1161 PatSeq *psPtr, *prevPtr;
1162 unsigned long eventMask;
1163 Tcl_HashEntry *hPtr;
1165 psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString,
1167 if (psPtr == NULL) {
1168 Tcl_ResetResult(interp);
1173 * Unlink the binding from the list for its object, then from the
1174 * list for its pattern.
1177 hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) object);
1179 panic("Tk_DeleteBinding couldn't find object table entry");
1181 prevPtr = (PatSeq *) Tcl_GetHashValue(hPtr);
1182 if (prevPtr == psPtr) {
1183 Tcl_SetHashValue(hPtr, psPtr->nextObjPtr);
1185 for ( ; ; prevPtr = prevPtr->nextObjPtr) {
1186 if (prevPtr == NULL) {
1187 panic("Tk_DeleteBinding couldn't find on object list");
1189 if (prevPtr->nextObjPtr == psPtr) {
1190 prevPtr->nextObjPtr = psPtr->nextObjPtr;
1195 prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr);
1196 if (prevPtr == psPtr) {
1197 if (psPtr->nextSeqPtr == NULL) {
1198 Tcl_DeleteHashEntry(psPtr->hPtr);
1200 Tcl_SetHashValue(psPtr->hPtr, psPtr->nextSeqPtr);
1203 for ( ; ; prevPtr = prevPtr->nextSeqPtr) {
1204 if (prevPtr == NULL) {
1205 panic("Tk_DeleteBinding couldn't find on hash chain");
1207 if (prevPtr->nextSeqPtr == psPtr) {
1208 prevPtr->nextSeqPtr = psPtr->nextSeqPtr;
1214 psPtr->flags |= MARKED_DELETED;
1215 if (psPtr->refCount == 0) {
1216 if (psPtr->freeProc != NULL) {
1217 (*psPtr->freeProc)(psPtr->clientData);
1219 ckfree((char *) psPtr);
1225 *--------------------------------------------------------------
1229 * Return the command associated with a given event string.
1232 * The return value is a pointer to the command string
1233 * associated with eventString for object in the domain
1234 * given by bindingTable. If there is no binding for
1235 * eventString, or if eventString is improperly formed,
1236 * then NULL is returned and an error message is left in
1237 * the interp's result. The return value is semi-static: it
1238 * will persist until the binding is changed or deleted.
1243 *--------------------------------------------------------------
1247 Tk_GetBinding(interp, bindingTable, object, eventString)
1248 Tcl_Interp *interp; /* Interpreter for error reporting. */
1249 Tk_BindingTable bindingTable; /* Table in which to look for
1251 ClientData object; /* Token for object with which binding
1253 CONST char *eventString; /* String describing event sequence
1254 * that triggers binding. */
1256 BindingTable *bindPtr = (BindingTable *) bindingTable;
1258 unsigned long eventMask;
1260 psPtr = FindSequence(interp, &bindPtr->patternTable, object, eventString,
1262 if (psPtr == NULL) {
1265 if (psPtr->eventProc == EvalTclBinding) {
1266 return (CONST char *) psPtr->clientData;
1272 *--------------------------------------------------------------
1274 * Tk_GetAllBindings --
1276 * Return a list of event strings for all the bindings
1277 * associated with a given object.
1280 * There is no return value. The interp's result is modified to
1281 * hold a Tcl list with one entry for each binding associated
1282 * with object in bindingTable. Each entry in the list
1283 * contains the event string associated with one binding.
1288 *--------------------------------------------------------------
1292 Tk_GetAllBindings(interp, bindingTable, object)
1293 Tcl_Interp *interp; /* Interpreter returning result or
1295 Tk_BindingTable bindingTable; /* Table in which to look for
1297 ClientData object; /* Token for object. */
1300 BindingTable *bindPtr = (BindingTable *) bindingTable;
1302 Tcl_HashEntry *hPtr;
1305 hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) object);
1309 Tcl_DStringInit(&ds);
1310 for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL;
1311 psPtr = psPtr->nextObjPtr) {
1313 * For each binding, output information about each of the
1314 * patterns in its sequence.
1317 Tcl_DStringSetLength(&ds, 0);
1318 GetPatternString(psPtr, &ds);
1319 Tcl_AppendElement(interp, Tcl_DStringValue(&ds));
1321 Tcl_DStringFree(&ds);
1325 *--------------------------------------------------------------
1327 * Tk_DeleteAllBindings --
1329 * Remove all bindings associated with a given object in a
1330 * given binding table.
1333 * All bindings associated with object are removed from
1339 *--------------------------------------------------------------
1343 Tk_DeleteAllBindings(bindingTable, object)
1344 Tk_BindingTable bindingTable; /* Table in which to delete
1346 ClientData object; /* Token for object. */
1348 BindingTable *bindPtr = (BindingTable *) bindingTable;
1349 PatSeq *psPtr, *prevPtr;
1351 Tcl_HashEntry *hPtr;
1353 hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) object);
1357 for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL;
1359 nextPtr = psPtr->nextObjPtr;
1362 * Be sure to remove each binding from its hash chain in the
1363 * pattern table. If this is the last pattern in the chain,
1364 * then delete the hash entry too.
1367 prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr);
1368 if (prevPtr == psPtr) {
1369 if (psPtr->nextSeqPtr == NULL) {
1370 Tcl_DeleteHashEntry(psPtr->hPtr);
1372 Tcl_SetHashValue(psPtr->hPtr, psPtr->nextSeqPtr);
1375 for ( ; ; prevPtr = prevPtr->nextSeqPtr) {
1376 if (prevPtr == NULL) {
1377 panic("Tk_DeleteAllBindings couldn't find on hash chain");
1379 if (prevPtr->nextSeqPtr == psPtr) {
1380 prevPtr->nextSeqPtr = psPtr->nextSeqPtr;
1385 psPtr->flags |= MARKED_DELETED;
1387 if (psPtr->refCount == 0) {
1388 if (psPtr->freeProc != NULL) {
1389 (*psPtr->freeProc)(psPtr->clientData);
1391 ckfree((char *) psPtr);
1394 Tcl_DeleteHashEntry(hPtr);
1398 *---------------------------------------------------------------------------
1402 * This procedure is invoked to process an X event. The
1403 * event is added to those recorded for the binding table.
1404 * Then each of the objects at *objectPtr is checked in
1405 * order to see if it has a binding that matches the recent
1406 * events. If so, the most specific binding is invoked for
1413 * Depends on the command associated with the matching binding.
1415 * All Tcl bindings scripts for each object are accumulated before
1416 * the first binding is evaluated. If the action of a Tcl binding
1417 * is to change or delete a binding, or delete the window associated
1418 * with the binding, all the original Tcl binding scripts will still
1419 * fire. Contrast this with C binding procedures. If a pending C
1420 * binding (one that hasn't fired yet, but is queued to be fired for
1421 * this window) is deleted, it will not be called, and if it is
1422 * changed, then the new binding procedure will be called. If the
1423 * window itself is deleted, no further C binding procedures will be
1424 * called for this window. When both Tcl binding scripts and C binding
1425 * procedures are interleaved, the above rules still apply.
1427 *---------------------------------------------------------------------------
1431 Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr)
1432 Tk_BindingTable bindingTable; /* Table in which to look for
1434 XEvent *eventPtr; /* What actually happened. */
1435 Tk_Window tkwin; /* Window on display where event
1436 * occurred (needed in order to
1437 * locate display information). */
1438 int numObjects; /* Number of objects at *objectPtr. */
1439 ClientData *objectPtr; /* Array of one or more objects
1440 * to check for a matching binding. */
1442 BindingTable *bindPtr;
1444 ScreenInfo *screenPtr;
1445 BindInfo *bindInfoPtr;
1446 TkDisplay *oldDispPtr;
1448 PatSeq *vMatchDetailList, *vMatchNoDetailList;
1449 int flags, oldScreen, i, deferModal;
1450 unsigned int matchCount, matchSpace;
1452 Tcl_DString scripts, savedResult;
1455 PendingBinding *pendingPtr;
1456 PendingBinding staticPending;
1457 TkWindow *winPtr = (TkWindow *)tkwin;
1458 PatternTableKey key;
1459 Tk_ClassModalProc *modalProc;
1461 * Ignore events on windows that don't have names: these are windows
1462 * like wrapper windows that shouldn't be visible to the
1466 if (winPtr->pathName == NULL) {
1471 * Ignore the event completely if it is an Enter, Leave, FocusIn,
1472 * or FocusOut event with detail NotifyInferior. The reason for
1473 * ignoring these events is that we don't want transitions between
1474 * a window and its children to visible to bindings on the parent:
1475 * this would cause problems for mega-widgets, since the internal
1476 * structure of a mega-widget isn't supposed to be visible to
1477 * people watching the parent.
1480 if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) {
1481 if (eventPtr->xcrossing.detail == NotifyInferior) {
1485 if ((eventPtr->type == FocusIn) || (eventPtr->type == FocusOut)) {
1486 if (eventPtr->xfocus.detail == NotifyInferior) {
1491 bindPtr = (BindingTable *) bindingTable;
1492 dispPtr = ((TkWindow *) tkwin)->dispPtr;
1493 bindInfoPtr = (BindInfo *) winPtr->mainPtr->bindInfo;
1496 * Add the new event to the ring of saved events for the
1497 * binding table. Two tricky points:
1499 * 1. Combine consecutive MotionNotify events. Do this by putting
1500 * the new event *on top* of the previous event.
1501 * 2. If a modifier key is held down, it auto-repeats to generate
1502 * continuous KeyPress and KeyRelease events. These can flush
1503 * the event ring so that valuable information is lost (such
1504 * as repeated button clicks). To handle this, check for the
1505 * special case of a modifier KeyPress arriving when the previous
1506 * two events are a KeyRelease and KeyPress of the same key.
1507 * If this happens, mark the most recent event (the KeyRelease)
1508 * invalid and put the new event on top of the event before that
1512 if ((eventPtr->type == MotionNotify)
1513 && (bindPtr->eventRing[bindPtr->curEvent].type == MotionNotify)) {
1515 * Don't advance the ring pointer.
1517 } else if (eventPtr->type == KeyPress) {
1519 for (i = 0; ; i++) {
1520 if (i >= dispPtr->numModKeyCodes) {
1521 goto advanceRingPointer;
1523 if (dispPtr->modKeyCodes[i] == eventPtr->xkey.keycode) {
1527 ringPtr = &bindPtr->eventRing[bindPtr->curEvent];
1528 if ((ringPtr->type != KeyRelease)
1529 || (ringPtr->xkey.keycode != eventPtr->xkey.keycode)) {
1530 goto advanceRingPointer;
1532 if (bindPtr->curEvent <= 0) {
1533 i = EVENT_BUFFER_SIZE - 1;
1535 i = bindPtr->curEvent - 1;
1537 ringPtr = &bindPtr->eventRing[i];
1538 if ((ringPtr->type != KeyPress)
1539 || (ringPtr->xkey.keycode != eventPtr->xkey.keycode)) {
1540 goto advanceRingPointer;
1542 bindPtr->eventRing[bindPtr->curEvent].type = -1;
1543 bindPtr->curEvent = i;
1546 bindPtr->curEvent++;
1547 if (bindPtr->curEvent >= EVENT_BUFFER_SIZE) {
1548 bindPtr->curEvent = 0;
1551 ringPtr = &bindPtr->eventRing[bindPtr->curEvent];
1552 memcpy((VOID *) ringPtr, (VOID *) eventPtr, sizeof(XEvent));
1553 detail.clientData = 0;
1554 flags = flagArray[ringPtr->type];
1556 detail.keySym = TkpGetKeySym(dispPtr, ringPtr);
1557 if (detail.keySym == NoSymbol) {
1560 } else if (flags & BUTTON) {
1561 detail.button = ringPtr->xbutton.button;
1562 } else if (flags & VIRTUAL) {
1563 detail.name = ((XVirtualEvent *) ringPtr)->name;
1565 bindPtr->detailRing[bindPtr->curEvent] = detail;
1568 * Find out if there are any virtual events that correspond to this
1569 * physical event (or sequence of physical events).
1572 vMatchDetailList = NULL;
1573 vMatchNoDetailList = NULL;
1574 memset(&key, 0, sizeof(key));
1576 if (ringPtr->type != VirtualEvent) {
1577 Tcl_HashTable *veptPtr;
1578 Tcl_HashEntry *hPtr;
1580 veptPtr = &bindInfoPtr->virtualEventTable.patternTable;
1583 key.type = ringPtr->type;
1584 key.detail = detail;
1586 hPtr = Tcl_FindHashEntry(veptPtr, (char *) &key);
1588 vMatchDetailList = (PatSeq *) Tcl_GetHashValue(hPtr);
1591 if (key.detail.clientData != 0) {
1592 key.detail.clientData = 0;
1593 hPtr = Tcl_FindHashEntry(veptPtr, (char *) &key);
1595 vMatchNoDetailList = (PatSeq *) Tcl_GetHashValue(hPtr);
1601 * Loop over all the binding tags, finding the binding script or
1602 * callback for each one. Append all of the binding scripts, with
1603 * %-sequences expanded, to "scripts", with null characters separating
1604 * the scripts for each object. Append all the callbacks to the array
1605 * of pending callbacks.
1608 pendingPtr = &staticPending;
1610 matchSpace = sizeof(staticPending.matchArray) / sizeof(PatSeq *);
1611 Tcl_DStringInit(&scripts);
1613 for ( ; numObjects > 0; numObjects--, objectPtr++) {
1614 PatSeq *matchPtr, *sourcePtr;
1615 Tcl_HashEntry *hPtr;
1621 * Match the new event against those recorded in the pattern table,
1622 * saving the longest matching pattern. For events with details
1623 * (button and key events), look for a binding for the specific
1624 * key or button. First see if the event matches a physical event
1625 * that the object is interested in, then look for a virtual event.
1628 key.object = *objectPtr;
1629 key.type = ringPtr->type;
1630 key.detail = detail;
1631 hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, (char *) &key);
1633 matchPtr = MatchPatterns(dispPtr, bindPtr,
1634 (PatSeq *) Tcl_GetHashValue(hPtr), matchPtr, NULL,
1638 if (vMatchDetailList != NULL) {
1639 matchPtr = MatchPatterns(dispPtr, bindPtr, vMatchDetailList,
1640 matchPtr, objectPtr, &sourcePtr);
1644 * If no match was found, look for a binding for all keys or buttons
1645 * (detail of 0). Again, first match on a virtual event.
1648 if ((detail.clientData != 0) && (matchPtr == NULL)) {
1649 key.detail.clientData = 0;
1650 hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, (char *) &key);
1652 matchPtr = MatchPatterns(dispPtr, bindPtr,
1653 (PatSeq *) Tcl_GetHashValue(hPtr), matchPtr, NULL,
1657 if (vMatchNoDetailList != NULL) {
1658 matchPtr = MatchPatterns(dispPtr, bindPtr, vMatchNoDetailList,
1659 matchPtr, objectPtr, &sourcePtr);
1664 if (matchPtr != NULL) {
1665 if (sourcePtr->eventProc == NULL) {
1666 panic("Tk_BindEvent: missing command");
1668 if (sourcePtr->eventProc == EvalTclBinding) {
1669 ExpandPercents(winPtr, (char *) sourcePtr->clientData,
1670 eventPtr, detail.keySym, &scripts);
1672 if (matchCount >= matchSpace) {
1673 PendingBinding *new;
1674 unsigned int oldSize, newSize;
1676 oldSize = sizeof(staticPending)
1677 - sizeof(staticPending.matchArray)
1678 + matchSpace * sizeof(PatSeq*);
1680 newSize = sizeof(staticPending)
1681 - sizeof(staticPending.matchArray)
1682 + matchSpace * sizeof(PatSeq*);
1683 new = (PendingBinding *) ckalloc(newSize);
1684 memcpy((VOID *) new, (VOID *) pendingPtr, oldSize);
1685 if (pendingPtr != &staticPending) {
1686 ckfree((char *) pendingPtr);
1690 sourcePtr->refCount++;
1691 pendingPtr->matchArray[matchCount] = sourcePtr;
1695 * A "" is added to the scripts string to separate the
1696 * various scripts that should be invoked.
1699 Tcl_DStringAppend(&scripts, "", 1);
1702 if (Tcl_DStringLength(&scripts) == 0) {
1707 * Now go back through and evaluate the binding for each object,
1708 * in order, dealing with "break" and "continue" exceptions
1711 * There are two tricks here:
1712 * 1. Bindings can be invoked from in the middle of Tcl commands,
1713 * where the interp's result is significant (for example, a widget
1714 * might be deleted because of an error in creating it, so the
1715 * result contains an error message that is eventually going to
1716 * be returned by the creating command). To preserve the result,
1717 * we save it in a dynamic string.
1718 * 2. The binding's action can potentially delete the binding,
1719 * so bindPtr may not point to anything valid once the action
1720 * completes. Thus we have to save bindPtr->interp in a
1721 * local variable in order to restore the result.
1724 interp = bindPtr->interp;
1725 Tcl_DStringInit(&savedResult);
1728 * Save information about the current screen, then invoke a script
1729 * if the screen has changed.
1732 Tcl_DStringGetResult(interp, &savedResult);
1733 screenPtr = &bindInfoPtr->screenInfo;
1734 oldDispPtr = screenPtr->curDispPtr;
1735 oldScreen = screenPtr->curScreenIndex;
1736 if ((dispPtr != screenPtr->curDispPtr)
1737 || (Tk_ScreenNumber(tkwin) != screenPtr->curScreenIndex)) {
1738 screenPtr->curDispPtr = dispPtr;
1739 screenPtr->curScreenIndex = Tk_ScreenNumber(tkwin);
1740 ChangeScreen(interp, dispPtr->name, screenPtr->curScreenIndex);
1743 if (matchCount > 0) {
1745 * Remember the list of pending C binding callbacks, so we can mark
1746 * them as deleted and not call them if the act of evaluating a C
1747 * or Tcl binding deletes a C binding callback or even the whole
1751 pendingPtr->nextPtr = bindInfoPtr->pendingList;
1752 pendingPtr->tkwin = tkwin;
1753 pendingPtr->deleted = 0;
1754 bindInfoPtr->pendingList = pendingPtr;
1758 * Save the current value of the TK_DEFER_MODAL flag so we can
1759 * restore it at the end of the loop. Clear the flag so we can
1760 * detect any recursive requests for a modal loop.
1763 flags = winPtr->flags;
1764 winPtr->flags &= ~TK_DEFER_MODAL;
1766 p = Tcl_DStringValue(&scripts);
1767 end = p + Tcl_DStringLength(&scripts);
1771 * Be carefule when dereferencing screenPtr or bindInfoPtr. If we
1772 * evaluate something that destroys ".", bindInfoPtr would have been
1773 * freed, but we can tell that by first checking to see if
1774 * winPtr->mainPtr == NULL.
1777 Tcl_Preserve((ClientData) bindInfoPtr);
1781 if (!bindInfoPtr->deleted) {
1782 screenPtr->bindingDepth++;
1784 Tcl_AllowExceptions(interp);
1789 psPtr = pendingPtr->matchArray[i];
1792 if ((pendingPtr->deleted == 0)
1793 && ((psPtr->flags & MARKED_DELETED) == 0)) {
1794 code = (*psPtr->eventProc)(psPtr->clientData, interp, eventPtr,
1795 tkwin, detail.keySym);
1798 if ((psPtr->refCount == 0) && (psPtr->flags & MARKED_DELETED)) {
1799 if (psPtr->freeProc != NULL) {
1800 (*psPtr->freeProc)(psPtr->clientData);
1802 ckfree((char *) psPtr);
1805 code = Tcl_GlobalEval(interp, p);
1810 if (!bindInfoPtr->deleted) {
1811 screenPtr->bindingDepth--;
1813 if (code != TCL_OK) {
1814 if (code == TCL_CONTINUE) {
1816 * Do nothing: just go on to the next command.
1818 } else if (code == TCL_BREAK) {
1821 Tcl_AddErrorInfo(interp, "\n (command bound to event)");
1822 Tcl_BackgroundError(interp);
1828 if (matchCount > 0 && !pendingPtr->deleted) {
1830 * Restore the original modal flag value and invoke the modal loop
1834 deferModal = winPtr->flags & TK_DEFER_MODAL;
1835 winPtr->flags = (winPtr->flags & (unsigned int) ~TK_DEFER_MODAL)
1836 | (flags & TK_DEFER_MODAL);
1838 modalProc = Tk_GetClassProc(winPtr->classProcsPtr, modalProc);
1839 if (modalProc != NULL) {
1840 (*modalProc)(tkwin, eventPtr);
1845 if (!bindInfoPtr->deleted && (screenPtr->bindingDepth != 0)
1846 && ((oldDispPtr != screenPtr->curDispPtr)
1847 || (oldScreen != screenPtr->curScreenIndex))) {
1850 * Some other binding script is currently executing, but its
1851 * screen is no longer current. Change the current display
1855 screenPtr->curDispPtr = oldDispPtr;
1856 screenPtr->curScreenIndex = oldScreen;
1857 ChangeScreen(interp, oldDispPtr->name, oldScreen);
1859 Tcl_DStringResult(interp, &savedResult);
1860 Tcl_DStringFree(&scripts);
1862 if (matchCount > 0) {
1863 if (!bindInfoPtr->deleted) {
1865 * Delete the pending list from the list of pending scripts
1869 PendingBinding **curPtrPtr;
1871 for (curPtrPtr = &bindInfoPtr->pendingList; ; ) {
1872 if (*curPtrPtr == pendingPtr) {
1873 *curPtrPtr = pendingPtr->nextPtr;
1876 curPtrPtr = &(*curPtrPtr)->nextPtr;
1879 if (pendingPtr != &staticPending) {
1880 ckfree((char *) pendingPtr);
1883 Tcl_Release((ClientData) bindInfoPtr);
1887 *---------------------------------------------------------------------------
1889 * TkBindDeadWindow --
1891 * This procedure is invoked when it is determined that a window is
1892 * dead. It cleans up bind-related information about the window
1898 * Any pending C bindings for this window are cancelled.
1900 *---------------------------------------------------------------------------
1904 TkBindDeadWindow(winPtr)
1905 TkWindow *winPtr; /* The window that is being deleted. */
1907 BindInfo *bindInfoPtr;
1908 PendingBinding *curPtr;
1911 * Certain special windows like those used for send and clipboard
1914 if (winPtr->mainPtr == NULL)
1917 bindInfoPtr = (BindInfo *) winPtr->mainPtr->bindInfo;
1918 curPtr = bindInfoPtr->pendingList;
1919 while (curPtr != NULL) {
1920 if (curPtr->tkwin == (Tk_Window) winPtr) {
1921 curPtr->deleted = 1;
1923 curPtr = curPtr->nextPtr;
1928 *----------------------------------------------------------------------
1932 * Given a list of pattern sequences and a list of recent events,
1933 * return the pattern sequence that best matches the event list,
1936 * This procedure is used in two different ways. In the simplest
1937 * use, "object" is NULL and psPtr is a list of pattern sequences,
1938 * each of which corresponds to a binding. In this case, the
1939 * procedure finds the pattern sequences that match the event list
1940 * and returns the most specific of those, if there is more than one.
1942 * In the second case, psPtr is a list of pattern sequences, each
1943 * of which corresponds to a definition for a virtual binding.
1944 * In order for one of these sequences to "match", it must match
1945 * the events (as above) but in addition there must be a binding
1946 * for its associated virtual event on the current object. The
1947 * "object" argument indicates which object the binding must be for.
1950 * The return value is NULL if bestPtr is NULL and no pattern matches
1951 * the recent events from bindPtr. Otherwise the return value is
1952 * the most specific pattern sequence among bestPtr and all those
1953 * at psPtr that match the event list and object. If a pattern
1954 * sequence other than bestPtr is returned, then *bestCommandPtr
1955 * is filled in with a pointer to the command from the best sequence.
1960 *----------------------------------------------------------------------
1963 MatchPatterns(dispPtr, bindPtr, psPtr, bestPtr, objectPtr, sourcePtrPtr)
1964 TkDisplay *dispPtr; /* Display from which the event came. */
1965 BindingTable *bindPtr; /* Information about binding table, such as
1966 * ring of recent events. */
1967 PatSeq *psPtr; /* List of pattern sequences. */
1968 PatSeq *bestPtr; /* The best match seen so far, from a
1969 * previous call to this procedure. NULL
1970 * means no prior best match. */
1971 ClientData *objectPtr; /* If NULL, the sequences at psPtr
1972 * correspond to "normal" bindings. If
1973 * non-NULL, the sequences at psPtr correspond
1974 * to virtual bindings; in order to match each
1975 * sequence must correspond to a virtual
1976 * binding for which a binding exists for
1977 * object in bindPtr. */
1978 PatSeq **sourcePtrPtr; /* Filled with the pattern sequence that
1979 * contains the eventProc and clientData
1980 * associated with the best match. If this
1981 * differs from the return value, it is the
1982 * virtual event that most closely matched the
1983 * return value (a physical event). Not
1984 * modified unless a result other than bestPtr
1987 PatSeq *matchPtr, *bestSourcePtr, *sourcePtr;
1989 bestSourcePtr = *sourcePtrPtr;
1992 * Iterate over all the pattern sequences.
1995 for ( ; psPtr != NULL; psPtr = psPtr->nextSeqPtr) {
2000 int patCount, ringCount, flags, state;
2004 * Iterate over all the patterns in a sequence to be
2005 * sure that they all match.
2008 eventPtr = &bindPtr->eventRing[bindPtr->curEvent];
2009 detailPtr = &bindPtr->detailRing[bindPtr->curEvent];
2010 window = eventPtr->xany.window;
2011 patPtr = psPtr->pats;
2012 patCount = psPtr->numPats;
2013 ringCount = EVENT_BUFFER_SIZE;
2014 while (patCount > 0) {
2015 if (ringCount <= 0) {
2018 if (eventPtr->xany.type != patPtr->eventType) {
2020 * Most of the event types are considered superfluous
2021 * in that they are ignored if they occur in the middle
2022 * of a pattern sequence and have mismatching types. The
2023 * only ones that cannot be ignored are ButtonPress and
2024 * ButtonRelease events (if the next event in the pattern
2025 * is a KeyPress or KeyRelease) and KeyPress and KeyRelease
2026 * events (if the next pattern event is a ButtonPress or
2027 * ButtonRelease). Here are some tricky cases to consider:
2028 * 1. Double-Button or Double-Key events.
2029 * 2. Double-ButtonRelease or Double-KeyRelease events.
2030 * 3. The arrival of various events like Enter and Leave
2031 * and FocusIn and GraphicsExpose between two button
2032 * presses or key presses.
2033 * 4. Modifier keys like Shift and Control shouldn't
2034 * generate conflicts with button events.
2037 if ((patPtr->eventType == KeyPress)
2038 || (patPtr->eventType == KeyRelease)) {
2039 if ((eventPtr->xany.type == ButtonPress)
2040 || (eventPtr->xany.type == ButtonRelease)) {
2043 } else if ((patPtr->eventType == ButtonPress)
2044 || (patPtr->eventType == ButtonRelease)) {
2045 if ((eventPtr->xany.type == KeyPress)
2046 || (eventPtr->xany.type == KeyRelease)) {
2050 * Ignore key events if they are modifier keys.
2053 for (i = 0; i < dispPtr->numModKeyCodes; i++) {
2054 if (dispPtr->modKeyCodes[i]
2055 == eventPtr->xkey.keycode) {
2057 * This key is a modifier key, so ignore it.
2067 if (eventPtr->xany.type == CreateNotify
2068 && eventPtr->xcreatewindow.parent != window) {
2071 if (eventPtr->xany.window != window) {
2076 * Note: it's important for the keysym check to go before
2077 * the modifier check, so we can ignore unwanted modifier
2078 * keys before choking on the modifier check.
2081 if ((patPtr->detail.clientData != 0)
2082 && (patPtr->detail.clientData != detailPtr->clientData)) {
2084 * The detail appears not to match. However, if the event
2085 * is a KeyPress for a modifier key then just ignore the
2086 * event. Otherwise event sequences like "aD" never match
2087 * because the shift key goes down between the "a" and the
2091 if (eventPtr->xany.type == KeyPress) {
2094 for (i = 0; i < dispPtr->numModKeyCodes; i++) {
2095 if (dispPtr->modKeyCodes[i] == eventPtr->xkey.keycode) {
2102 flags = flagArray[eventPtr->type];
2103 if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
2104 state = eventPtr->xkey.state;
2105 } else if (flags & CROSSING) {
2106 state = eventPtr->xcrossing.state;
2110 if (patPtr->needMods != 0) {
2111 modMask = patPtr->needMods;
2112 if ((modMask & META_MASK) && (dispPtr->metaModMask != 0)) {
2113 modMask = (modMask & ~META_MASK) | dispPtr->metaModMask;
2115 if ((modMask & ALT_MASK) && (dispPtr->altModMask != 0)) {
2116 modMask = (modMask & ~ALT_MASK) | dispPtr->altModMask;
2119 if ((state & META_MASK) && (dispPtr->metaModMask != 0)) {
2120 state = (state & ~META_MASK) | dispPtr->metaModMask;
2122 if ((state & ALT_MASK) && (dispPtr->altModMask != 0)) {
2123 state = (state & ~ALT_MASK) | dispPtr->altModMask;
2126 if ((state & modMask) != modMask) {
2130 if (psPtr->flags & PAT_NEARBY) {
2134 firstPtr = &bindPtr->eventRing[bindPtr->curEvent];
2135 timeDiff = (Time) firstPtr->xkey.time - eventPtr->xkey.time;
2136 if ((firstPtr->xkey.x_root
2137 < (eventPtr->xkey.x_root - NEARBY_PIXELS))
2138 || (firstPtr->xkey.x_root
2139 > (eventPtr->xkey.x_root + NEARBY_PIXELS))
2140 || (firstPtr->xkey.y_root
2141 < (eventPtr->xkey.y_root - NEARBY_PIXELS))
2142 || (firstPtr->xkey.y_root
2143 > (eventPtr->xkey.y_root + NEARBY_PIXELS))
2144 || (timeDiff > NEARBY_MS)) {
2151 if (eventPtr == bindPtr->eventRing) {
2152 eventPtr = &bindPtr->eventRing[EVENT_BUFFER_SIZE-1];
2153 detailPtr = &bindPtr->detailRing[EVENT_BUFFER_SIZE-1];
2164 if (objectPtr != NULL) {
2166 VirtualOwners *voPtr;
2167 PatternTableKey key;
2170 * The sequence matches the physical constraints.
2171 * Is this object interested in any of the virtual events
2172 * that correspond to this sequence?
2175 voPtr = psPtr->voPtr;
2177 memset(&key, 0, sizeof(key));
2178 key.object = *objectPtr;
2179 key.type = VirtualEvent;
2180 key.detail.clientData = 0;
2182 for (iVirt = 0; iVirt < voPtr->numOwners; iVirt++) {
2183 Tcl_HashEntry *hPtr = voPtr->owners[iVirt];
2185 key.detail.name = (Tk_Uid) Tcl_GetHashKey(hPtr->tablePtr,
2187 hPtr = Tcl_FindHashEntry(&bindPtr->patternTable,
2192 * This tag is interested in this virtual event and its
2193 * corresponding physical event is a good match with the
2194 * virtual event's definition.
2197 PatSeq *virtMatchPtr;
2199 virtMatchPtr = (PatSeq *) Tcl_GetHashValue(hPtr);
2200 if ((virtMatchPtr->numPats != 1)
2201 || (virtMatchPtr->nextSeqPtr != NULL)) {
2202 panic("MatchPattern: badly constructed virtual event");
2204 sourcePtr = virtMatchPtr;
2210 * The physical event matches a virtual event's definition, but
2211 * the tag isn't interested in it.
2218 * This sequence matches. If we've already got another match,
2219 * pick whichever is most specific. Detail is most important,
2223 if (bestPtr != NULL) {
2227 if (matchPtr->numPats != bestPtr->numPats) {
2228 if (bestPtr->numPats > matchPtr->numPats) {
2234 for (i = 0, patPtr = matchPtr->pats, patPtr2 = bestPtr->pats;
2235 i < matchPtr->numPats; i++, patPtr++, patPtr2++) {
2236 if (patPtr->detail.clientData != patPtr2->detail.clientData) {
2237 if (patPtr->detail.clientData == 0) {
2243 if (patPtr->needMods != patPtr2->needMods) {
2244 if ((patPtr->needMods & patPtr2->needMods)
2245 == patPtr->needMods) {
2247 } else if ((patPtr->needMods & patPtr2->needMods)
2248 == patPtr2->needMods) {
2254 * Tie goes to current best pattern.
2256 * (1) For virtual vs. virtual, the least recently defined
2257 * virtual wins, because virtuals are examined in order of
2258 * definition. This order is _not_ guaranteed in the
2261 * (2) For virtual vs. physical, the physical wins because all
2262 * the physicals are examined before the virtuals. This order
2263 * is guaranteed in the documentation.
2265 * (3) For physical vs. physical pattern, the most recently
2266 * defined physical wins, because physicals are examined in
2267 * reverse order of definition. This order is guaranteed in
2268 * the documentation.
2275 bestSourcePtr = sourcePtr;
2281 *sourcePtrPtr = bestSourcePtr;
2287 *--------------------------------------------------------------
2291 * Given a command and an event, produce a new command
2292 * by replacing % constructs in the original command
2293 * with information from the X event.
2296 * The new expanded command is appended to the dynamic string
2302 *--------------------------------------------------------------
2306 ExpandPercents(winPtr, before, eventPtr, keySym, dsPtr)
2307 TkWindow *winPtr; /* Window where event occurred: needed to
2308 * get input context. */
2309 CONST char *before; /* Command containing percent expressions
2310 * to be replaced. */
2311 XEvent *eventPtr; /* X event containing information to be
2312 * used in % replacements. */
2313 KeySym keySym; /* KeySym: only relevant for KeyPress and
2314 * KeyRelease events). */
2315 Tcl_DString *dsPtr; /* Dynamic string in which to append new
2318 int spaceNeeded, cvtFlags; /* Used to substitute string as proper Tcl
2320 int number, flags, length;
2324 char numStorage[NUM_SIZE+1];
2326 Tcl_DStringInit(&buf);
2328 if (eventPtr->type < TK_LASTEVENT) {
2329 flags = flagArray[eventPtr->type];
2335 * Find everything up to the next % character and append it
2336 * to the result string.
2339 for (string = before; (*string != 0) && (*string != '%'); string++) {
2340 /* Empty loop body. */
2342 if (string != before) {
2343 Tcl_DStringAppend(dsPtr, before, (int) (string-before));
2351 * There's a percent sequence here. Process it.
2356 switch (before[1]) {
2358 number = eventPtr->xany.serial;
2361 if (flags & CONFIG) {
2362 TkpPrintWindowId(numStorage, eventPtr->xconfigure.above);
2363 string = numStorage;
2367 number = eventPtr->xbutton.button;
2370 if (flags & EXPOSE) {
2371 number = eventPtr->xexpose.count;
2375 if (flags & (CROSSING|FOCUS)) {
2376 if (flags & FOCUS) {
2377 number = eventPtr->xfocus.detail;
2379 number = eventPtr->xcrossing.detail;
2381 string = TkFindStateString(notifyDetail, number);
2383 else if (flags & CONFIGREQ) {
2384 if (eventPtr->xconfigurerequest.value_mask & CWStackMode) {
2385 string = TkFindStateString(configureRequestDetail,
2386 eventPtr->xconfigurerequest.detail);
2393 number = eventPtr->xcrossing.focus;
2396 if (flags & EXPOSE) {
2397 number = eventPtr->xexpose.height;
2398 } else if (flags & (CONFIG)) {
2399 number = eventPtr->xconfigure.height;
2401 else if (flags & CREATE) {
2402 number = eventPtr->xcreatewindow.height;
2403 } else if (flags & CONFIGREQ) {
2404 number = eventPtr->xconfigurerequest.height;
2405 } else if (flags & RESIZEREQ) {
2406 number = eventPtr->xresizerequest.height;
2410 if (flags & CREATE) {
2411 TkpPrintWindowId(numStorage, eventPtr->xcreatewindow.window);
2412 } else if (flags & CONFIGREQ) {
2413 TkpPrintWindowId(numStorage, eventPtr->xconfigurerequest.window);
2414 } else if (flags & MAPREQ) {
2415 TkpPrintWindowId(numStorage, eventPtr->xmaprequest.window);
2417 TkpPrintWindowId(numStorage, eventPtr->xany.window);
2419 string = numStorage;
2422 number = eventPtr->xkey.keycode;
2425 if (flags & CROSSING) {
2426 number = eventPtr->xcrossing.mode;
2427 } else if (flags & FOCUS) {
2428 number = eventPtr->xfocus.mode;
2430 string = TkFindStateString(notifyMode, number);
2433 if (flags & CREATE) {
2434 number = eventPtr->xcreatewindow.override_redirect;
2435 } else if (flags & MAP) {
2436 number = eventPtr->xmap.override_redirect;
2437 } else if (flags & REPARENT) {
2438 number = eventPtr->xreparent.override_redirect;
2439 } else if (flags & CONFIG) {
2440 number = eventPtr->xconfigure.override_redirect;
2445 string = TkFindStateString(circPlace, eventPtr->xcirculate.place);
2446 } else if (flags & CIRCREQ) {
2447 string = TkFindStateString(circPlace, eventPtr->xcirculaterequest.place);
2451 if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
2452 number = eventPtr->xkey.state;
2453 } else if (flags & CROSSING) {
2454 number = eventPtr->xcrossing.state;
2455 } else if (flags & PROP) {
2456 string = TkFindStateString(propNotify,
2457 eventPtr->xproperty.state);
2459 } else if (flags & VISIBILITY) {
2460 string = TkFindStateString(visNotify,
2461 eventPtr->xvisibility.state);
2466 if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
2467 number = (int) eventPtr->xkey.time;
2468 } else if (flags & CROSSING) {
2469 number = (int) eventPtr->xcrossing.time;
2470 } else if (flags & PROP) {
2471 number = (int) eventPtr->xproperty.time;
2475 number = eventPtr->xconfigurerequest.value_mask;
2478 if (flags & EXPOSE) {
2479 number = eventPtr->xexpose.width;
2480 } else if (flags & CONFIG) {
2481 number = eventPtr->xconfigure.width;
2483 else if (flags & CREATE) {
2484 number = eventPtr->xcreatewindow.width;
2485 } else if (flags & CONFIGREQ) {
2486 number = eventPtr->xconfigurerequest.width;
2487 } else if (flags & RESIZEREQ) {
2488 number = eventPtr->xresizerequest.width;
2492 if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
2493 number = eventPtr->xkey.x;
2494 } else if (flags & CROSSING) {
2495 number = eventPtr->xcrossing.x;
2496 } else if (flags & EXPOSE) {
2497 number = eventPtr->xexpose.x;
2498 } else if (flags & (CREATE|CONFIG|GRAVITY)) {
2499 number = eventPtr->xcreatewindow.x;
2500 } else if (flags & REPARENT) {
2501 number = eventPtr->xreparent.x;
2503 else if (flags & CREATE) {
2504 number = eventPtr->xcreatewindow.x;
2505 } else if (flags & CONFIGREQ) {
2506 number = eventPtr->xconfigurerequest.x;
2510 if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
2511 number = eventPtr->xkey.y;
2512 } else if (flags & EXPOSE) {
2513 number = eventPtr->xexpose.y;
2514 } else if (flags & (CREATE|CONFIG|GRAVITY)) {
2515 number = eventPtr->xcreatewindow.y;
2516 } else if (flags & REPARENT) {
2517 number = eventPtr->xreparent.y;
2518 } else if (flags & CROSSING) {
2519 number = eventPtr->xcrossing.y;
2522 else if (flags & CREATE) {
2523 number = eventPtr->xcreatewindow.y;
2524 } else if (flags & CONFIGREQ) {
2525 number = eventPtr->xconfigurerequest.y;
2530 Tcl_DStringFree(&buf);
2531 string = TkpGetString(winPtr, eventPtr, &buf);
2535 if (flags & CREATE) {
2536 number = eventPtr->xcreatewindow.border_width;
2537 } else if (flags & CONFIGREQ) {
2538 number = eventPtr->xconfigurerequest.border_width;
2540 number = eventPtr->xconfigure.border_width;
2545 * This is used only by the MouseWheel event.
2548 number = eventPtr->xkey.keycode;
2551 number = (int) eventPtr->xany.send_event;
2557 name = TkKeysymToString(keySym);
2564 number = (int) keySym;
2568 string = Tk_GetAtomName((Tk_Window) winPtr, eventPtr->xproperty.atom);
2572 TkpPrintWindowId(numStorage, eventPtr->xkey.root);
2573 string = numStorage;
2576 TkpPrintWindowId(numStorage, eventPtr->xkey.subwindow);
2577 string = numStorage;
2580 number = eventPtr->type;
2585 tkwin = Tk_IdToWindow(eventPtr->xany.display,
2586 eventPtr->xany.window);
2587 if (tkwin != NULL) {
2588 string = Tk_PathName(tkwin);
2599 number = eventPtr->xkey.x_root;
2600 tkwin = Tk_IdToWindow(eventPtr->xany.display,
2601 eventPtr->xany.window);
2602 if (tkwin != NULL) {
2603 Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
2613 number = eventPtr->xkey.y_root;
2614 tkwin = Tk_IdToWindow(eventPtr->xany.display,
2615 eventPtr->xany.window);
2616 if (tkwin != NULL) {
2617 Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
2623 numStorage[0] = before[1];
2624 numStorage[1] = '\0';
2625 string = numStorage;
2630 sprintf(numStorage, "%d", number);
2631 string = numStorage;
2634 spaceNeeded = Tcl_ScanElement(string, &cvtFlags);
2635 length = Tcl_DStringLength(dsPtr);
2636 Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
2637 spaceNeeded = Tcl_ConvertElement(string,
2638 Tcl_DStringValue(dsPtr) + length,
2639 cvtFlags | TCL_DONT_USE_BRACES);
2640 Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
2643 Tcl_DStringFree(&buf);
2647 *----------------------------------------------------------------------
2651 * This procedure is invoked whenever the current screen changes
2652 * in an application. It invokes a Tcl procedure named
2653 * "tk::ScreenChanged", passing it the screen name as argument.
2654 * tk::ScreenChanged does things like making the tk::Priv variable
2655 * point to an array for the current display.
2661 * Depends on what tk::ScreenChanged does. If an error occurs
2662 * them bgerror will be invoked.
2664 *----------------------------------------------------------------------
2668 ChangeScreen(interp, dispName, screenIndex)
2669 Tcl_Interp *interp; /* Interpreter in which to invoke
2671 char *dispName; /* Name of new display. */
2672 int screenIndex; /* Index of new screen. */
2676 char screen[TCL_INTEGER_SPACE];
2678 Tcl_DStringInit(&cmd);
2679 Tcl_DStringAppend(&cmd, "tk::ScreenChanged ", 18);
2680 Tcl_DStringAppend(&cmd, dispName, -1);
2681 sprintf(screen, ".%d", screenIndex);
2682 Tcl_DStringAppend(&cmd, screen, -1);
2683 code = Tcl_GlobalEval(interp, Tcl_DStringValue(&cmd));
2684 if (code != TCL_OK) {
2685 Tcl_AddErrorInfo(interp,
2686 "\n (changing screen in event binding)");
2687 Tcl_BackgroundError(interp);
2693 *----------------------------------------------------------------------
2697 * This procedure is invoked to process the "event" Tcl command.
2698 * It is used to define and generate events.
2701 * A standard Tcl result.
2704 * See the user documentation.
2706 *----------------------------------------------------------------------
2710 Tk_EventObjCmd(clientData, interp, objc, objv)
2711 ClientData clientData; /* Main window associated with interpreter. */
2712 Tcl_Interp *interp; /* Current interpreter. */
2713 int objc; /* Number of arguments. */
2714 Tcl_Obj *CONST objv[]; /* Argument objects. */
2718 VirtualEventTable *vetPtr;
2719 TkBindInfo bindInfo;
2720 static CONST char *optionStrings[] = {
2721 "add", "delete", "generate", "info",
2725 EVENT_ADD, EVENT_DELETE, EVENT_GENERATE, EVENT_INFO
2728 tkwin = (Tk_Window) clientData;
2729 bindInfo = ((TkWindow *) tkwin)->mainPtr->bindInfo;
2730 vetPtr = &((BindInfo *) bindInfo)->virtualEventTable;
2733 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
2736 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
2737 &index) != TCL_OK) {
2741 switch ((enum options) index) {
2747 Tcl_WrongNumArgs(interp, 2, objv,
2748 "virtual sequence ?sequence ...?");
2751 name = Tcl_GetStringFromObj(objv[2], NULL);
2752 for (i = 3; i < objc; i++) {
2753 event = Tcl_GetStringFromObj(objv[i], NULL);
2754 if (CreateVirtualEvent(interp, vetPtr, name, event) != TCL_OK) {
2760 case EVENT_DELETE: {
2765 Tcl_WrongNumArgs(interp, 2, objv,
2766 "virtual ?sequence sequence ...?");
2769 name = Tcl_GetStringFromObj(objv[2], NULL);
2771 return DeleteVirtualEvent(interp, vetPtr, name, NULL);
2773 for (i = 3; i < objc; i++) {
2774 event = Tcl_GetStringFromObj(objv[i], NULL);
2775 if (DeleteVirtualEvent(interp, vetPtr, name, event) != TCL_OK) {
2781 case EVENT_GENERATE: {
2783 Tcl_WrongNumArgs(interp, 2, objv, "window event ?options?");
2786 return HandleEventGenerate(interp, tkwin, objc - 2, objv + 2);
2790 GetAllVirtualEvents(interp, vetPtr);
2792 } else if (objc == 3) {
2793 return GetVirtualEvent(interp, vetPtr,
2794 Tcl_GetStringFromObj(objv[2], NULL));
2796 Tcl_WrongNumArgs(interp, 2, objv, "?virtual?");
2805 *---------------------------------------------------------------------------
2807 * InitVirtualEventTable --
2809 * Given storage for a virtual event table, set up the fields to
2810 * prepare a new domain in which virtual events may be defined.
2816 * *vetPtr is now initialized.
2818 *---------------------------------------------------------------------------
2822 InitVirtualEventTable(vetPtr)
2823 VirtualEventTable *vetPtr; /* Pointer to virtual event table. Memory
2824 * is supplied by the caller. */
2826 Tcl_InitHashTable(&vetPtr->patternTable,
2827 sizeof(PatternTableKey) / sizeof(int));
2828 Tcl_InitHashTable(&vetPtr->nameTable, TCL_ONE_WORD_KEYS);
2832 *---------------------------------------------------------------------------
2834 * DeleteVirtualEventTable --
2836 * Delete the contents of a virtual event table. The caller is
2837 * responsible for freeing any memory used by the table itself.
2845 *---------------------------------------------------------------------------
2849 DeleteVirtualEventTable(vetPtr)
2850 VirtualEventTable *vetPtr; /* The virtual event table to delete. */
2852 Tcl_HashEntry *hPtr;
2853 Tcl_HashSearch search;
2854 PatSeq *psPtr, *nextPtr;
2856 hPtr = Tcl_FirstHashEntry(&vetPtr->patternTable, &search);
2857 for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
2858 psPtr = (PatSeq *) Tcl_GetHashValue(hPtr);
2859 for ( ; psPtr != NULL; psPtr = nextPtr) {
2860 nextPtr = psPtr->nextSeqPtr;
2861 ckfree((char *) psPtr->voPtr);
2862 ckfree((char *) psPtr);
2865 Tcl_DeleteHashTable(&vetPtr->patternTable);
2867 hPtr = Tcl_FirstHashEntry(&vetPtr->nameTable, &search);
2868 for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
2869 ckfree((char *) Tcl_GetHashValue(hPtr));
2871 Tcl_DeleteHashTable(&vetPtr->nameTable);
2875 *----------------------------------------------------------------------
2877 * CreateVirtualEvent --
2879 * Add a new definition for a virtual event. If the virtual event
2880 * is already defined, the new definition augments those that
2884 * The return value is TCL_ERROR if an error occured while
2885 * creating the virtual binding. In this case, an error message
2886 * will be left in the interp's result. If all went well then the
2887 * return value is TCL_OK.
2890 * The virtual event may cause future calls to Tk_BindEvent to
2891 * behave differently than they did previously.
2893 *----------------------------------------------------------------------
2897 CreateVirtualEvent(interp, vetPtr, virtString, eventString)
2898 Tcl_Interp *interp; /* Used for error reporting. */
2899 VirtualEventTable *vetPtr;/* Table in which to augment virtual event. */
2900 char *virtString; /* Name of new virtual event. */
2901 char *eventString; /* String describing physical event that
2902 * triggers virtual event. */
2906 Tcl_HashEntry *vhPtr;
2907 unsigned long eventMask;
2908 PhysicalsOwned *poPtr;
2909 VirtualOwners *voPtr;
2912 virtUid = GetVirtualEventUid(interp, virtString);
2913 if (virtUid == NULL) {
2918 * Find/create physical event
2921 psPtr = FindSequence(interp, &vetPtr->patternTable, NULL, eventString,
2923 if (psPtr == NULL) {
2928 * Find/create virtual event.
2931 vhPtr = Tcl_CreateHashEntry(&vetPtr->nameTable, virtUid, &dummy);
2934 * Make virtual event own the physical event.
2937 poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr);
2938 if (poPtr == NULL) {
2939 poPtr = (PhysicalsOwned *) ckalloc(sizeof(PhysicalsOwned));
2940 poPtr->numOwned = 0;
2943 * See if this virtual event is already defined for this physical
2944 * event and just return if it is.
2948 for (i = 0; i < poPtr->numOwned; i++) {
2949 if (poPtr->patSeqs[i] == psPtr) {
2953 poPtr = (PhysicalsOwned *) ckrealloc((char *) poPtr,
2954 sizeof(PhysicalsOwned) + poPtr->numOwned * sizeof(PatSeq *));
2956 Tcl_SetHashValue(vhPtr, (ClientData) poPtr);
2957 poPtr->patSeqs[poPtr->numOwned] = psPtr;
2961 * Make physical event so it can trigger the virtual event.
2964 voPtr = psPtr->voPtr;
2965 if (voPtr == NULL) {
2966 voPtr = (VirtualOwners *) ckalloc(sizeof(VirtualOwners));
2967 voPtr->numOwners = 0;
2969 voPtr = (VirtualOwners *) ckrealloc((char *) voPtr,
2970 sizeof(VirtualOwners)
2971 + voPtr->numOwners * sizeof(Tcl_HashEntry *));
2973 psPtr->voPtr = voPtr;
2974 voPtr->owners[voPtr->numOwners] = vhPtr;
2981 *--------------------------------------------------------------
2983 * DeleteVirtualEvent --
2985 * Remove the definition of a given virtual event. If the
2986 * event string is NULL, all definitions of the virtual event
2987 * will be removed. Otherwise, just the specified definition
2988 * of the virtual event will be removed.
2991 * The result is a standard Tcl return value. If an error
2992 * occurs then the interp's result will contain an error message.
2993 * It is not an error to attempt to delete a virtual event that
2994 * does not exist or a definition that does not exist.
2997 * The virtual event given by virtString may be removed from the
2998 * virtual event table.
3000 *--------------------------------------------------------------
3004 DeleteVirtualEvent(interp, vetPtr, virtString, eventString)
3005 Tcl_Interp *interp; /* Used for error reporting. */
3006 VirtualEventTable *vetPtr;/* Table in which to delete event. */
3007 char *virtString; /* String describing event sequence that
3008 * triggers binding. */
3009 char *eventString; /* The event sequence that should be deleted,
3010 * or NULL to delete all event sequences for
3011 * the entire virtual event. */
3015 Tcl_HashEntry *vhPtr;
3016 PhysicalsOwned *poPtr;
3019 virtUid = GetVirtualEventUid(interp, virtString);
3020 if (virtUid == NULL) {
3024 vhPtr = Tcl_FindHashEntry(&vetPtr->nameTable, virtUid);
3025 if (vhPtr == NULL) {
3028 poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr);
3031 if (eventString != NULL) {
3032 unsigned long eventMask;
3035 * Delete only the specific physical event associated with the
3036 * virtual event. If the physical event doesn't already exist, or
3037 * the virtual event doesn't own that physical event, return w/o
3041 eventPSPtr = FindSequence(interp, &vetPtr->patternTable, NULL,
3042 eventString, 0, 0, &eventMask);
3043 if (eventPSPtr == NULL) {
3046 string = Tcl_GetStringResult(interp);
3047 return (string[0] != '\0') ? TCL_ERROR : TCL_OK;
3051 for (iPhys = poPtr->numOwned; --iPhys >= 0; ) {
3052 PatSeq *psPtr = poPtr->patSeqs[iPhys];
3053 if ((eventPSPtr == NULL) || (psPtr == eventPSPtr)) {
3055 VirtualOwners *voPtr;
3058 * Remove association between this physical event and the given
3059 * virtual event that it triggers.
3062 voPtr = psPtr->voPtr;
3063 for (iVirt = 0; iVirt < voPtr->numOwners; iVirt++) {
3064 if (voPtr->owners[iVirt] == vhPtr) {
3068 if (iVirt == voPtr->numOwners) {
3069 panic("DeleteVirtualEvent: couldn't find owner");
3072 if (voPtr->numOwners == 0) {
3074 * Removed last reference to this physical event, so
3075 * remove it from physical->virtual map.
3077 PatSeq *prevPtr = (PatSeq *) Tcl_GetHashValue(psPtr->hPtr);
3078 if (prevPtr == psPtr) {
3079 if (psPtr->nextSeqPtr == NULL) {
3080 Tcl_DeleteHashEntry(psPtr->hPtr);
3082 Tcl_SetHashValue(psPtr->hPtr,
3086 for ( ; ; prevPtr = prevPtr->nextSeqPtr) {
3087 if (prevPtr == NULL) {
3088 panic("DeleteVirtualEvent couldn't find on hash chain");
3090 if (prevPtr->nextSeqPtr == psPtr) {
3091 prevPtr->nextSeqPtr = psPtr->nextSeqPtr;
3096 ckfree((char *) psPtr->voPtr);
3097 ckfree((char *) psPtr);
3100 * This physical event still triggers some other virtual
3101 * event(s). Consolidate the list of virtual owners for
3102 * this physical event so it no longer triggers the
3103 * given virtual event.
3105 voPtr->owners[iVirt] = voPtr->owners[voPtr->numOwners];
3109 * Now delete the virtual event's reference to the physical
3114 if (eventPSPtr != NULL && poPtr->numOwned != 0) {
3116 * Just deleting this one physical event. Consolidate list
3117 * of owned physical events and return.
3120 poPtr->patSeqs[iPhys] = poPtr->patSeqs[poPtr->numOwned];
3126 if (poPtr->numOwned == 0) {
3128 * All the physical events for this virtual event were deleted,
3129 * either because there was only one associated physical event or
3130 * because the caller was deleting the entire virtual event. Now
3131 * the virtual event itself should be deleted.
3134 ckfree((char *) poPtr);
3135 Tcl_DeleteHashEntry(vhPtr);
3141 *---------------------------------------------------------------------------
3143 * GetVirtualEvent --
3145 * Return the list of physical events that can invoke the
3146 * given virtual event.
3149 * The return value is TCL_OK and the interp's result is filled with the
3150 * string representation of the physical events associated with the
3151 * virtual event; if there are no physical events for the given virtual
3152 * event, the interp's result is filled with and empty string. If the
3153 * virtual event string is improperly formed, then TCL_ERROR is
3154 * returned and an error message is left in the interp's result.
3159 *---------------------------------------------------------------------------
3163 GetVirtualEvent(interp, vetPtr, virtString)
3164 Tcl_Interp *interp; /* Interpreter for reporting. */
3165 VirtualEventTable *vetPtr;/* Table in which to look for event. */
3166 char *virtString; /* String describing virtual event. */
3168 Tcl_HashEntry *vhPtr;
3171 PhysicalsOwned *poPtr;
3174 virtUid = GetVirtualEventUid(interp, virtString);
3175 if (virtUid == NULL) {
3179 vhPtr = Tcl_FindHashEntry(&vetPtr->nameTable, virtUid);
3180 if (vhPtr == NULL) {
3184 Tcl_DStringInit(&ds);
3186 poPtr = (PhysicalsOwned *) Tcl_GetHashValue(vhPtr);
3187 for (iPhys = 0; iPhys < poPtr->numOwned; iPhys++) {
3188 Tcl_DStringSetLength(&ds, 0);
3189 GetPatternString(poPtr->patSeqs[iPhys], &ds);
3190 Tcl_AppendElement(interp, Tcl_DStringValue(&ds));
3192 Tcl_DStringFree(&ds);
3198 *--------------------------------------------------------------
3200 * GetAllVirtualEvents --
3202 * Return a list that contains the names of all the virtual
3206 * There is no return value. The interp's result is modified to
3207 * hold a Tcl list with one entry for each virtual event in
3213 *--------------------------------------------------------------
3217 GetAllVirtualEvents(interp, vetPtr)
3218 Tcl_Interp *interp; /* Interpreter returning result. */
3219 VirtualEventTable *vetPtr;/* Table containing events. */
3221 Tcl_HashEntry *hPtr;
3222 Tcl_HashSearch search;
3225 Tcl_DStringInit(&ds);
3227 hPtr = Tcl_FirstHashEntry(&vetPtr->nameTable, &search);
3228 for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
3229 Tcl_DStringSetLength(&ds, 0);
3230 Tcl_DStringAppend(&ds, "<<", 2);
3231 Tcl_DStringAppend(&ds, Tcl_GetHashKey(hPtr->tablePtr, hPtr), -1);
3232 Tcl_DStringAppend(&ds, ">>", 2);
3233 Tcl_AppendElement(interp, Tcl_DStringValue(&ds));
3236 Tcl_DStringFree(&ds);
3240 *---------------------------------------------------------------------------
3242 * HandleEventGenerate --
3244 * Helper function for the "event generate" command. Generate and
3245 * process an XEvent, constructed from information parsed from the
3246 * event description string and its optional arguments.
3248 * argv[0] contains name of the target window.
3249 * argv[1] contains pattern string for one event (e.g, <Control-v>).
3250 * argv[2..argc-1] contains -field/option pairs for specifying
3251 * additional detail in the generated event.
3253 * Either virtual or physical events can be generated this way.
3254 * The event description string must contain the specification
3255 * for only one event.
3261 * When constructing the event,
3262 * event.xany.serial is filled with the current X serial number.
3263 * event.xany.window is filled with the target window.
3264 * event.xany.display is filled with the target window's display.
3265 * Any other fields in eventPtr which are not specified by the pattern
3266 * string or the optional arguments, are set to 0.
3268 * The event may be handled sychronously or asynchronously, depending
3269 * on the value specified by the optional "-when" option. The
3270 * default setting is synchronous.
3272 *---------------------------------------------------------------------------
3275 HandleEventGenerate(interp, mainWin, objc, objv)
3276 Tcl_Interp *interp; /* Interp for errors return and name lookup. */
3277 Tk_Window mainWin; /* Main window associated with interp. */
3278 int objc; /* Number of arguments. */
3279 Tcl_Obj *CONST objv[]; /* Argument objects. */
3283 char *name, *windowName;
3284 int count, flags, synch, i, number, warp;
3285 Tcl_QueuePosition pos;
3287 Tk_Window tkwin, tkwin2;
3289 unsigned long eventMask;
3290 static CONST char *fieldStrings[] = {
3291 "-when", "-above", "-borderwidth", "-button",
3292 "-count", "-delta", "-detail", "-focus",
3294 "-keycode", "-keysym", "-mode", "-override",
3295 "-place", "-root", "-rootx", "-rooty",
3296 "-sendevent", "-serial", "-state", "-subwindow",
3297 "-time", "-warp", "-width", "-window",
3301 EVENT_WHEN, EVENT_ABOVE, EVENT_BORDER, EVENT_BUTTON,
3302 EVENT_COUNT, EVENT_DELTA, EVENT_DETAIL, EVENT_FOCUS,
3304 EVENT_KEYCODE, EVENT_KEYSYM, EVENT_MODE, EVENT_OVERRIDE,
3305 EVENT_PLACE, EVENT_ROOT, EVENT_ROOTX, EVENT_ROOTY,
3306 EVENT_SEND, EVENT_SERIAL, EVENT_STATE, EVENT_SUBWINDOW,
3307 EVENT_TIME, EVENT_WARP, EVENT_WIDTH, EVENT_WINDOW,
3311 windowName = Tcl_GetStringFromObj(objv[0], NULL);
3312 if (!windowName[0]) {
3314 } else if (NameToWindow(interp, mainWin, objv[0], &tkwin) != TCL_OK) {
3318 mainPtr = (TkWindow *) mainWin;
3320 || (mainPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr)) {
3323 name = Tcl_GetStringFromObj(objv[0], NULL);
3324 Tcl_AppendResult(interp, "window id \"", name,
3325 "\" doesn't exist in this application", (char *) NULL);
3329 name = Tcl_GetStringFromObj(objv[1], NULL);
3333 count = ParseEventDescription(interp, &p, &pat, &eventMask);
3338 Tcl_SetResult(interp, "Double or Triple modifier not allowed",
3343 Tcl_SetResult(interp, "only one event specification allowed",
3348 memset((VOID *) &event, 0, sizeof(event));
3349 event.xany.type = pat.eventType;
3350 event.xany.serial = NextRequest(Tk_Display(tkwin));
3351 event.xany.send_event = False;
3352 if (windowName[0]) {
3353 event.xany.window = Tk_WindowId(tkwin);
3355 event.xany.window = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
3357 event.xany.display = Tk_Display(tkwin);
3359 flags = flagArray[event.xany.type];
3360 if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
3361 event.xkey.state = pat.needMods;
3362 if ((flags & KEY) && (event.xany.type != MouseWheelEvent)) {
3363 TkpSetKeycodeAndState(tkwin, pat.detail.keySym, &event);
3364 } else if (flags & BUTTON) {
3365 event.xbutton.button = pat.detail.button;
3366 } else if (flags & VIRTUAL) {
3367 ((XVirtualEvent *) &event)->name = pat.detail.name;
3370 if (flags & (CREATE|DESTROY|UNMAP|MAP|REPARENT|CONFIG|GRAVITY|CIRC)) {
3371 event.xcreatewindow.window = event.xany.window;
3375 * Process the remaining arguments to fill in additional fields
3381 pos = TCL_QUEUE_TAIL;
3382 for (i = 2; i < objc; i += 2) {
3383 Tcl_Obj *optionPtr, *valuePtr;
3386 optionPtr = objv[i];
3387 valuePtr = objv[i + 1];
3389 if (Tcl_GetIndexFromObj(interp, optionPtr, fieldStrings, "option",
3390 TCL_EXACT, &index) != TCL_OK) {
3395 * This test occurs after Tcl_GetIndexFromObj() so that
3396 * "event generate <Button> -xyz" will return the error message
3397 * that "-xyz" is a bad option, rather than that the value
3398 * for "-xyz" is missing.
3401 Tcl_AppendResult(interp, "value for \"",
3402 Tcl_GetStringFromObj(optionPtr, NULL), "\" missing",
3407 switch ((enum field) index) {
3409 if (Tcl_GetBooleanFromObj(interp, valuePtr, &warp) != TCL_OK) {
3412 if (!(flags & (KEY_BUTTON_MOTION_VIRTUAL))) {
3418 pos = (Tcl_QueuePosition) TkFindStateNumObj(interp, optionPtr,
3419 queuePosition, valuePtr);
3420 if ((int) pos < -1) {
3424 if ((int) pos == -1) {
3430 if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) {
3433 if (flags & CONFIG) {
3434 event.xconfigure.above = Tk_WindowId(tkwin2);
3440 case EVENT_BORDER: {
3441 if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
3444 if (flags & (CREATE|CONFIG)) {
3445 event.xcreatewindow.border_width = number;
3451 case EVENT_BUTTON: {
3452 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
3455 if (flags & BUTTON) {
3456 event.xbutton.button = number;
3463 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
3466 if (flags & EXPOSE) {
3467 event.xexpose.count = number;
3474 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
3477 if ((flags & KEY) && (event.xkey.type == MouseWheelEvent)) {
3478 event.xkey.keycode = number;
3484 case EVENT_DETAIL: {
3485 number = TkFindStateNumObj(interp, optionPtr, notifyDetail,
3490 if (flags & FOCUS) {
3491 event.xfocus.detail = number;
3492 } else if (flags & CROSSING) {
3493 event.xcrossing.detail = number;
3500 if (Tcl_GetBooleanFromObj(interp, valuePtr, &number) != TCL_OK) {
3503 if (flags & CROSSING) {
3504 event.xcrossing.focus = number;
3510 case EVENT_HEIGHT: {
3511 if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
3514 if (flags & EXPOSE) {
3515 event.xexpose.height = number;
3516 } else if (flags & CONFIG) {
3517 event.xconfigure.height = number;
3523 case EVENT_KEYCODE: {
3524 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
3527 if ((flags & KEY) && (event.xkey.type != MouseWheelEvent)) {
3528 event.xkey.keycode = number;
3534 case EVENT_KEYSYM: {
3538 value = Tcl_GetStringFromObj(valuePtr, NULL);
3539 keysym = TkStringToKeysym(value);
3540 if (keysym == NoSymbol) {
3541 Tcl_AppendResult(interp, "unknown keysym \"", value, "\"",
3546 TkpSetKeycodeAndState(tkwin, keysym, &event);
3547 if (event.xkey.keycode == 0) {
3548 Tcl_AppendResult(interp, "no keycode for keysym \"", value,
3549 "\"", (char *) NULL);
3552 if (!(flags & KEY) || (event.xkey.type == MouseWheelEvent)) {
3558 number = TkFindStateNumObj(interp, optionPtr, notifyMode,
3563 if (flags & CROSSING) {
3564 event.xcrossing.mode = number;
3565 } else if (flags & FOCUS) {
3566 event.xfocus.mode = number;
3572 case EVENT_OVERRIDE: {
3573 if (Tcl_GetBooleanFromObj(interp, valuePtr, &number) != TCL_OK) {
3576 if (flags & CREATE) {
3577 event.xcreatewindow.override_redirect = number;
3578 } else if (flags & MAP) {
3579 event.xmap.override_redirect = number;
3580 } else if (flags & REPARENT) {
3581 event.xreparent.override_redirect = number;
3582 } else if (flags & CONFIG) {
3583 event.xconfigure.override_redirect = number;
3590 number = TkFindStateNumObj(interp, optionPtr, circPlace,
3596 event.xcirculate.place = number;
3603 if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) {
3606 if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
3607 event.xkey.root = Tk_WindowId(tkwin2);
3614 if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
3617 if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
3618 event.xkey.x_root = number;
3625 if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
3628 if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
3629 event.xkey.y_root = number;
3638 value = Tcl_GetStringFromObj(valuePtr, NULL);
3639 if (isdigit(UCHAR(value[0]))) {
3641 * Allow arbitrary integer values for the field; they
3642 * are needed by a few of the tests in the Tk test suite.
3645 if (Tcl_GetIntFromObj(interp, valuePtr, &number)
3650 if (Tcl_GetBooleanFromObj(interp, valuePtr, &number)
3655 event.xany.send_event = number;
3658 case EVENT_SERIAL: {
3659 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
3662 event.xany.serial = number;
3666 if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
3667 if (Tcl_GetIntFromObj(interp, valuePtr, &number)
3671 if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) {
3672 event.xkey.state = number;
3674 event.xcrossing.state = number;
3676 } else if (flags & VISIBILITY) {
3677 number = TkFindStateNumObj(interp, optionPtr, visNotify,
3682 event.xvisibility.state = number;
3688 case EVENT_SUBWINDOW: {
3689 if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) {
3692 if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
3693 event.xkey.subwindow = Tk_WindowId(tkwin2);
3700 if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
3703 if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
3704 event.xkey.time = (Time) number;
3705 } else if (flags & PROP) {
3706 event.xproperty.time = (Time) number;
3713 if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number)
3717 if (flags & EXPOSE) {
3718 event.xexpose.width = number;
3719 } else if (flags & (CREATE|CONFIG)) {
3720 event.xcreatewindow.width = number;
3726 case EVENT_WINDOW: {
3727 if (NameToWindow(interp, tkwin, valuePtr, &tkwin2) != TCL_OK) {
3730 if (flags & (CREATE|DESTROY|UNMAP|MAP|REPARENT|CONFIG
3732 event.xcreatewindow.window = Tk_WindowId(tkwin2);
3741 if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number)
3745 Tk_GetRootCoords(tkwin, &rootX, &rootY);
3747 if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
3748 event.xkey.x = number;
3749 event.xkey.x_root = rootX;
3750 } else if (flags & EXPOSE) {
3751 event.xexpose.x = number;
3752 } else if (flags & (CREATE|CONFIG|GRAVITY)) {
3753 event.xcreatewindow.x = number;
3754 } else if (flags & REPARENT) {
3755 event.xreparent.x = number;
3764 if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number)
3768 Tk_GetRootCoords(tkwin, &rootX, &rootY);
3770 if (flags & (KEY_BUTTON_MOTION_VIRTUAL|CROSSING)) {
3771 event.xkey.y = number;
3772 event.xkey.y_root = rootY;
3773 } else if (flags & EXPOSE) {
3774 event.xexpose.y = number;
3775 } else if (flags & (CREATE|CONFIG|GRAVITY)) {
3776 event.xcreatewindow.y = number;
3777 } else if (flags & REPARENT) {
3778 event.xreparent.y = number;
3788 Tcl_AppendResult(interp, name, " event doesn't accept \"",
3789 Tcl_GetStringFromObj(optionPtr, NULL), "\" option", NULL);
3793 Tk_HandleEvent(&event);
3795 Tk_QueueWindowEvent(&event, pos);
3798 * We only allow warping if the window is mapped
3800 if ((warp != 0) && Tk_IsMapped(tkwin)) {
3802 dispPtr = TkGetDisplay(event.xmotion.display);
3803 if (!(dispPtr->flags & TK_DISPLAY_IN_WARP)) {
3804 Tcl_DoWhenIdle(DoWarp, (ClientData) dispPtr);
3805 dispPtr->flags |= TK_DISPLAY_IN_WARP;
3807 dispPtr->warpWindow = event.xany.window;
3808 dispPtr->warpX = event.xkey.x;
3809 dispPtr->warpY = event.xkey.y;
3811 Tcl_ResetResult(interp);
3816 NameToWindow(interp, mainWin, objPtr, tkwinPtr)
3817 Tcl_Interp *interp; /* Interp for error return and name lookup. */
3818 Tk_Window mainWin; /* Main window of application. */
3819 Tcl_Obj *objPtr; /* Contains name or id string of window. */
3820 Tk_Window *tkwinPtr; /* Filled with token for window. */
3826 name = Tcl_GetStringFromObj(objPtr, NULL);
3827 if (name[0] == '.') {
3828 tkwin = Tk_NameToWindow(interp, name, mainWin);
3829 if (tkwin == NULL) {
3835 * Check for the winPtr being valid, even if it looks ok to
3836 * TkpScanWindowId. [Bug #411307]
3839 if ((TkpScanWindowId(NULL, name, &id) != TCL_OK) ||
3840 ((*tkwinPtr = Tk_IdToWindow(Tk_Display(mainWin), id))
3842 Tcl_AppendResult(interp, "bad window name/identifier \"",
3843 name, "\"", (char *) NULL);
3851 *-------------------------------------------------------------------------
3855 * Perform Warping of X pointer. Executed as an idle handler only.
3861 * X Pointer will move to a new location.
3863 *-------------------------------------------------------------------------
3867 ClientData clientData;
3869 TkDisplay *dispPtr = (TkDisplay *) clientData;
3871 XWarpPointer(dispPtr->display, (Window) None, (Window) dispPtr->warpWindow,
3872 0, 0, 0, 0, (int) dispPtr->warpX, (int) dispPtr->warpY);
3873 XForceScreenSaver(dispPtr->display, ScreenSaverReset);
3874 dispPtr->flags &= ~TK_DISPLAY_IN_WARP;
3878 *-------------------------------------------------------------------------
3880 * GetVirtualEventUid --
3882 * Determine if the given string is in the proper format for a
3886 * The return value is NULL if the virtual event string was
3887 * not in the proper format. In this case, an error message
3888 * will be left in the interp's result. Otherwise the return
3889 * value is a Tk_Uid that represents the virtual event.
3894 *-------------------------------------------------------------------------
3897 GetVirtualEventUid(interp, virtString)
3904 length = strlen(virtString);
3906 if (length < 5 || virtString[0] != '<' || virtString[1] != '<' ||
3907 virtString[length - 2] != '>' || virtString[length - 1] != '>') {
3908 Tcl_AppendResult(interp, "virtual event \"", virtString,
3909 "\" is badly formed", (char *) NULL);
3912 virtString[length - 2] = '\0';
3913 uid = Tk_GetUid(virtString + 2);
3914 virtString[length - 2] = '>';
3921 *----------------------------------------------------------------------
3925 * Find the entry in the pattern table that corresponds to a
3926 * particular pattern string, and return a pointer to that
3930 * The return value is normally a pointer to the PatSeq
3931 * in patternTable that corresponds to eventString. If an error
3932 * was found while parsing eventString, or if "create" is 0 and
3933 * no pattern sequence previously existed, then NULL is returned
3934 * and the interp's result contains a message describing the problem.
3935 * If no pattern sequence previously existed for eventString, then
3936 * a new one is created with a NULL command field. In a successful
3937 * return, *maskPtr is filled in with a mask of the event types
3938 * on which the pattern sequence depends.
3941 * A new pattern sequence may be allocated.
3943 *----------------------------------------------------------------------
3947 FindSequence(interp, patternTablePtr, object, eventString, create,
3948 allowVirtual, maskPtr)
3949 Tcl_Interp *interp; /* Interpreter to use for error
3951 Tcl_HashTable *patternTablePtr; /* Table to use for lookup. */
3952 ClientData object; /* For binding table, token for object with
3953 * which binding is associated.
3954 * For virtual event table, NULL. */
3955 CONST char *eventString; /* String description of pattern to
3956 * match on. See user documentation
3958 int create; /* 0 means don't create the entry if
3959 * it doesn't already exist. Non-zero
3961 int allowVirtual; /* 0 means that virtual events are not
3962 * allowed in the sequence. Non-zero
3964 unsigned long *maskPtr; /* *maskPtr is filled in with the event
3965 * types on which this pattern sequence
3969 Pattern pats[EVENT_BUFFER_SIZE];
3970 int numPats, virtualFound;
3974 Tcl_HashEntry *hPtr;
3975 int flags, count, new;
3976 size_t sequenceSize;
3977 unsigned long eventMask;
3978 PatternTableKey key;
3981 *-------------------------------------------------------------
3982 * Step 1: parse the pattern string to produce an array
3983 * of Patterns. The array is generated backwards, so
3984 * that the lowest-indexed pattern corresponds to the last
3985 * event that must occur.
3986 *-------------------------------------------------------------
3994 patPtr = &pats[EVENT_BUFFER_SIZE-1];
3995 for (numPats = 0; numPats < EVENT_BUFFER_SIZE; numPats++, patPtr--) {
3996 while (isspace(UCHAR(*p))) {
4003 count = ParseEventDescription(interp, &p, patPtr, &eventMask);
4008 if (eventMask & VirtualEventMask) {
4009 if (allowVirtual == 0) {
4010 Tcl_SetResult(interp,
4011 "virtual event not allowed in definition of another virtual event",
4019 * Replicate events for DOUBLE, TRIPLE, QUADRUPLE.
4022 while ((count-- > 1) && (numPats < EVENT_BUFFER_SIZE-1)) {
4023 flags |= PAT_NEARBY;
4024 patPtr[-1] = patPtr[0];
4031 *-------------------------------------------------------------
4032 * Step 2: find the sequence in the binding table if it exists,
4033 * and add a new sequence to the table if it doesn't.
4034 *-------------------------------------------------------------
4038 Tcl_SetResult(interp, "no events specified in binding", TCL_STATIC);
4041 if ((numPats > 1) && (virtualFound != 0)) {
4042 Tcl_SetResult(interp, "virtual events may not be composed",
4047 patPtr = &pats[EVENT_BUFFER_SIZE-numPats];
4048 memset(&key, 0, sizeof(key));
4049 key.object = object;
4050 key.type = patPtr->eventType;
4051 key.detail = patPtr->detail;
4052 hPtr = Tcl_CreateHashEntry(patternTablePtr, (char *) &key, &new);
4053 sequenceSize = numPats*sizeof(Pattern);
4055 for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL;
4056 psPtr = psPtr->nextSeqPtr) {
4057 if ((numPats == psPtr->numPats)
4058 && ((flags & PAT_NEARBY) == (psPtr->flags & PAT_NEARBY))
4059 && (memcmp((char *) patPtr, (char *) psPtr->pats,
4060 sequenceSize) == 0)) {
4067 Tcl_DeleteHashEntry(hPtr);
4070 * No binding exists for the sequence, so return an empty error.
4071 * This is a special error that the caller will check for in order
4072 * to silently ignore this case. This is a hack that maintains
4073 * backward compatibility for Tk_GetBinding but the various "bind"
4074 * commands silently ignore missing bindings.
4079 psPtr = (PatSeq *) ckalloc((unsigned) (sizeof(PatSeq)
4080 + (numPats-1)*sizeof(Pattern)));
4081 psPtr->numPats = numPats;
4082 psPtr->eventProc = NULL;
4083 psPtr->freeProc = NULL;
4084 psPtr->clientData = NULL;
4085 psPtr->flags = flags;
4086 psPtr->refCount = 0;
4087 psPtr->nextSeqPtr = (PatSeq *) Tcl_GetHashValue(hPtr);
4089 psPtr->voPtr = NULL;
4090 psPtr->nextObjPtr = NULL;
4091 Tcl_SetHashValue(hPtr, psPtr);
4093 memcpy((VOID *) psPtr->pats, (VOID *) patPtr, sequenceSize);
4096 *maskPtr = eventMask;
4101 *---------------------------------------------------------------------------
4103 * ParseEventDescription --
4105 * Fill Pattern buffer with information about event from
4109 * Leaves error message in interp and returns 0 if there was an
4110 * error due to a badly formed event string. Returns 1 if proper
4111 * event was specified, 2 if Double modifier was used in event
4112 * string, or 3 if Triple was used.
4115 * On exit, eventStringPtr points to rest of event string (after the
4116 * closing '>', so that this procedure can be called repeatedly to
4117 * parse all the events in the entire sequence.
4119 *---------------------------------------------------------------------------
4123 ParseEventDescription(interp, eventStringPtr, patPtr,
4125 Tcl_Interp *interp; /* For error messages. */
4126 CONST char **eventStringPtr;/* On input, holds a pointer to start of
4127 * event string. On exit, gets pointer to
4128 * rest of string after parsed event. */
4129 Pattern *patPtr; /* Filled with the pattern parsed from the
4131 unsigned long *eventMaskPtr;/* Filled with event mask of matched event. */
4135 unsigned long eventMask;
4136 int count, eventFlags;
4137 #define FIELD_SIZE 48
4138 char field[FIELD_SIZE];
4139 Tcl_HashEntry *hPtr;
4142 Tcl_DStringInit(©);
4143 p = Tcl_DStringAppend(©, *eventStringPtr, -1);
4145 patPtr->eventType = -1;
4146 patPtr->needMods = 0;
4147 patPtr->detail.clientData = 0;
4153 * Handle simple ASCII characters.
4159 patPtr->eventType = KeyPress;
4160 eventMask = KeyPressMask;
4163 patPtr->detail.keySym = TkStringToKeysym(string);
4164 if (patPtr->detail.keySym == NoSymbol) {
4165 if (isprint(UCHAR(*p))) {
4166 patPtr->detail.keySym = *p;
4170 sprintf(buf, "bad ASCII character 0x%x", (unsigned char) *p);
4171 Tcl_SetResult(interp, buf, TCL_VOLATILE);
4181 * A fancier event description. This can be either a virtual event
4182 * or a physical event.
4184 * A virtual event description consists of:
4186 * 1. double open angle brackets.
4187 * 2. virtual event name.
4188 * 3. double close angle brackets.
4190 * A physical event description consists of:
4192 * 1. open angle bracket.
4193 * 2. any number of modifiers, each followed by spaces
4195 * 3. an optional event name.
4196 * 4. an option button or keysym name. Either this or
4197 * item 3 *must* be present; if both are present
4198 * then they are separated by spaces or dashes.
4199 * 5. a close angle bracket.
4205 * This is a virtual event: soak up all the characters up to
4209 char *field = p + 1;
4210 p = strchr(field, '>');
4212 Tcl_SetResult(interp, "virtual event \"<<>>\" is badly formed",
4217 if ((p == NULL) || (p[1] != '>')) {
4218 Tcl_SetResult(interp, "missing \">\" in virtual binding",
4224 patPtr->eventType = VirtualEvent;
4225 eventMask = VirtualEventMask;
4226 patPtr->detail.name = Tk_GetUid(field);
4235 p = GetField(p, field, FIELD_SIZE);
4238 * This solves the problem of, e.g., <Control-M> being
4239 * misinterpreted as Control + Meta + missing keysym
4240 * instead of Control + KeyPress + M.
4244 hPtr = Tcl_FindHashEntry(&modTable, field);
4248 modPtr = (ModInfo *) Tcl_GetHashValue(hPtr);
4249 patPtr->needMods |= modPtr->mask;
4250 if (modPtr->flags & (MULT_CLICKS)) {
4251 int i = modPtr->flags & MULT_CLICKS;
4253 while (i >>= 1) count++;
4255 while ((*p == '-') || isspace(UCHAR(*p))) {
4261 hPtr = Tcl_FindHashEntry(&eventTable, field);
4264 eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr);
4266 patPtr->eventType = eiPtr->type;
4267 eventFlags = flagArray[eiPtr->type];
4268 eventMask = eiPtr->eventMask;
4269 while ((*p == '-') || isspace(UCHAR(*p))) {
4272 p = GetField(p, field, FIELD_SIZE);
4274 if (*field != '\0') {
4275 if ((*field >= '1') && (*field <= '5') && (field[1] == '\0')) {
4276 if (eventFlags == 0) {
4277 patPtr->eventType = ButtonPress;
4278 eventMask = ButtonPressMask;
4279 } else if (eventFlags & KEY) {
4281 } else if ((eventFlags & BUTTON) == 0) {
4282 Tcl_AppendResult(interp, "specified button \"", field,
4283 "\" for non-button event", (char *) NULL);
4287 patPtr->detail.button = (*field - '0');
4290 patPtr->detail.keySym = TkStringToKeysym(field);
4291 if (patPtr->detail.keySym == NoSymbol) {
4292 Tcl_AppendResult(interp, "bad event type or keysym \"",
4293 field, "\"", (char *) NULL);
4297 if (eventFlags == 0) {
4298 patPtr->eventType = KeyPress;
4299 eventMask = KeyPressMask;
4300 } else if ((eventFlags & KEY) == 0) {
4301 Tcl_AppendResult(interp, "specified keysym \"", field,
4302 "\" for non-key event", (char *) NULL);
4307 } else if (eventFlags == 0) {
4308 Tcl_SetResult(interp, "no event type or button # or keysym",
4314 while ((*p == '-') || isspace(UCHAR(*p))) {
4318 while (*p != '\0') {
4321 Tcl_SetResult(interp,
4322 "extra characters after detail in binding",
4328 Tcl_SetResult(interp, "missing \">\" in binding", TCL_STATIC);
4335 *eventStringPtr += (p - Tcl_DStringValue(©));
4336 *eventMaskPtr |= eventMask;
4338 Tcl_DStringFree(©);
4343 *----------------------------------------------------------------------
4347 * Used to parse pattern descriptions. Copies up to
4348 * size characters from p to copy, stopping at end of
4349 * string, space, "-", ">", or whenever size is
4353 * The return value is a pointer to the character just
4354 * after the last one copied (usually "-" or space or
4355 * ">", but could be anything if size was exceeded).
4356 * Also places NULL-terminated string (up to size
4357 * character, including NULL), at copy.
4362 *----------------------------------------------------------------------
4366 GetField(p, copy, size)
4367 char *p; /* Pointer to part of pattern. */
4368 char *copy; /* Place to copy field. */
4369 int size; /* Maximum number of characters to
4372 while ((*p != '\0') && !isspace(UCHAR(*p)) && (*p != '>')
4373 && (*p != '-') && (size > 1)) {
4384 *---------------------------------------------------------------------------
4386 * GetPatternString --
4388 * Produce a string version of the given event, for displaying to
4392 * The string is left in dsPtr.
4395 * It is the caller's responsibility to initialize the DString before
4396 * and to free it after calling this procedure.
4398 *---------------------------------------------------------------------------
4401 GetPatternString(psPtr, dsPtr)
4406 char c, buffer[TCL_INTEGER_SPACE];
4407 int patsLeft, needMods;
4412 * The order of the patterns in the sequence is backwards from the order
4413 * in which they must be output.
4416 for (patsLeft = psPtr->numPats, patPtr = &psPtr->pats[psPtr->numPats - 1];
4417 patsLeft > 0; patsLeft--, patPtr--) {
4420 * Check for simple case of an ASCII character.
4423 if ((patPtr->eventType == KeyPress)
4424 && ((psPtr->flags & PAT_NEARBY) == 0)
4425 && (patPtr->needMods == 0)
4426 && (patPtr->detail.keySym < 128)
4427 && isprint(UCHAR(patPtr->detail.keySym))
4428 && (patPtr->detail.keySym != '<')
4429 && (patPtr->detail.keySym != ' ')) {
4431 c = (char) patPtr->detail.keySym;
4432 Tcl_DStringAppend(dsPtr, &c, 1);
4437 * Check for virtual event.
4440 if (patPtr->eventType == VirtualEvent) {
4441 Tcl_DStringAppend(dsPtr, "<<", 2);
4442 Tcl_DStringAppend(dsPtr, patPtr->detail.name, -1);
4443 Tcl_DStringAppend(dsPtr, ">>", 2);
4448 * It's a more general event specification. First check
4449 * for "Double", "Triple", "Quadruple", then modifiers,
4450 * then event type, then keysym or button detail.
4453 Tcl_DStringAppend(dsPtr, "<", 1);
4454 if ((psPtr->flags & PAT_NEARBY) && (patsLeft > 1)
4455 && (memcmp((char *) patPtr, (char *) (patPtr-1),
4456 sizeof(Pattern)) == 0)) {
4459 if ((patsLeft > 1) && (memcmp((char *) patPtr,
4460 (char *) (patPtr-1), sizeof(Pattern)) == 0)) {
4463 if ((patsLeft > 1) && (memcmp((char *) patPtr,
4464 (char *) (patPtr-1), sizeof(Pattern)) == 0)) {
4467 Tcl_DStringAppend(dsPtr, "Quadruple-", 10);
4469 Tcl_DStringAppend(dsPtr, "Triple-", 7);
4472 Tcl_DStringAppend(dsPtr, "Double-", 7);
4475 for (needMods = patPtr->needMods, modPtr = modArray;
4476 needMods != 0; modPtr++) {
4477 if (modPtr->mask & needMods) {
4478 needMods &= ~modPtr->mask;
4479 Tcl_DStringAppend(dsPtr, modPtr->name, -1);
4480 Tcl_DStringAppend(dsPtr, "-", 1);
4483 for (eiPtr = eventArray; eiPtr->name != NULL; eiPtr++) {
4484 if (eiPtr->type == patPtr->eventType) {
4485 Tcl_DStringAppend(dsPtr, eiPtr->name, -1);
4486 if (patPtr->detail.clientData != 0) {
4487 Tcl_DStringAppend(dsPtr, "-", 1);
4493 if (patPtr->detail.clientData != 0) {
4494 if ((patPtr->eventType == KeyPress)
4495 || (patPtr->eventType == KeyRelease)) {
4498 string = TkKeysymToString(patPtr->detail.keySym);
4499 if (string != NULL) {
4500 Tcl_DStringAppend(dsPtr, string, -1);
4503 sprintf(buffer, "%d", patPtr->detail.button);
4504 Tcl_DStringAppend(dsPtr, buffer, -1);
4507 Tcl_DStringAppend(dsPtr, ">", 1);
4512 *---------------------------------------------------------------------------
4516 * The procedure that is invoked by Tk_BindEvent when a Tcl binding
4520 * A standard Tcl result code, the result of globally evaluating the
4521 * percent-substitued binding string.
4524 * Normal side effects due to eval.
4526 *---------------------------------------------------------------------------
4530 FreeTclBinding(clientData)
4531 ClientData clientData;
4533 ckfree((char *) clientData);
4537 *----------------------------------------------------------------------
4539 * TkStringToKeysym --
4541 * This procedure finds the keysym associated with a given keysym
4545 * The return value is the keysym that corresponds to name, or
4546 * NoSymbol if there is no such keysym.
4551 *----------------------------------------------------------------------
4555 TkStringToKeysym(name)
4556 char *name; /* Name of a keysym. */
4558 #ifdef REDO_KEYSYM_LOOKUP
4559 Tcl_HashEntry *hPtr;
4562 hPtr = Tcl_FindHashEntry(&keySymTable, name);
4564 return (KeySym) Tcl_GetHashValue(hPtr);
4566 if (strlen(name) == 1) {
4567 keysym = (KeySym) (unsigned char) name[0];
4568 if (TkKeysymToString(keysym) != NULL) {
4572 #endif /* REDO_KEYSYM_LOOKUP */
4573 return XStringToKeysym(name);
4577 *----------------------------------------------------------------------
4579 * TkKeysymToString --
4581 * This procedure finds the keysym name associated with a given
4585 * The return value is a pointer to a static string containing
4586 * the name of the given keysym, or NULL if there is no known name.
4591 *----------------------------------------------------------------------
4595 TkKeysymToString(keysym)
4598 #ifdef REDO_KEYSYM_LOOKUP
4599 Tcl_HashEntry *hPtr;
4601 hPtr = Tcl_FindHashEntry(&nameTable, (char *)keysym);
4603 return (char *) Tcl_GetHashValue(hPtr);
4605 #endif /* REDO_KEYSYM_LOOKUP */
4606 return XKeysymToString(keysym);
4610 *----------------------------------------------------------------------
4612 * TkCopyAndGlobalEval --
4614 * This procedure makes a copy of a script then calls Tcl_GlobalEval
4615 * to evaluate it. It's used in situations where the execution of
4616 * a command may cause the original command string to be reallocated.
4619 * Returns the result of evaluating script, including both a standard
4620 * Tcl completion code and a string in the interp's result.
4625 *----------------------------------------------------------------------
4629 TkCopyAndGlobalEval(interp, script)
4630 Tcl_Interp *interp; /* Interpreter in which to evaluate
4632 char *script; /* Script to evaluate. */
4637 Tcl_DStringInit(&buffer);
4638 Tcl_DStringAppend(&buffer, script, -1);
4639 code = Tcl_GlobalEval(interp, Tcl_DStringValue(&buffer));
4640 Tcl_DStringFree(&buffer);