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