OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkBind.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.