~ubuntu-branches/debian/lenny/wacom-tools/lenny

« back to all changes in this revision

Viewing changes to linuxwacom/src/wacomxi/wacomxi.c

  • Committer: Bazaar Package Importer
  • Author(s): Ron Lee
  • Date: 2004-12-10 16:12:07 UTC
  • Revision ID: james.westby@ubuntu.com-20041210161207-cw8urijtjsqvk2e3
Tags: upstream-0.6.6
ImportĀ upstreamĀ versionĀ 0.6.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * wacomxi.c -- Add X11 extended input handling capability for wacomcpl.
 
3
 *
 
4
 * Author               : Ping Cheng
 
5
 * Creation date        : 04/05/2003
 
6
 *
 
7
 * Based on xi.c 1998-99 Patrick Lecoanet --
 
8
 *
 
9
 * This code is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU Library General Public
 
11
 * License as published by the Free Software Foundation; either
 
12
 * version 2 of the License, or (at your option) any later version.
 
13
 *
 
14
 * This code is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
 * Library General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU Library General Public
 
20
 * License along with this code; if not, write to the Free
 
21
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
22
 *
 
23
 */
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <ctype.h>
 
27
#include <stdio.h>
 
28
 
 
29
#include <X11/extensions/XInput.h>
 
30
/*
 
31
 * Included to obtain the number of events used by the xinput
 
32
 * extension.
 
33
 */
 
34
#include <X11/extensions/XIproto.h>
 
35
 
 
36
#include "wacomxi.h"
 
37
 
 
38
/*
 
39
 *----------------------------------------------------------------------
 
40
 *
 
41
 * This code implements tcl commands that give access
 
42
 * to additional input devices manipulation at the tcl level.
 
43
 *
 
44
 * The command 'bindevent' binds tcl scripts to xinput events
 
45
 * occuring in a widget.
 
46
 *
 
47
 *----------------------------------------------------------------------
 
48
 */
 
49
 
 
50
#define CORE_KEYBOARD   1
 
51
#define CORE_POINTER    2
 
52
 
 
53
/*
 
54
 * These constants are used to represent fixed
 
55
 * event types. These types are computed by
 
56
 * mapping event types send by each server. The
 
57
 * mapping is done by a table maintained for
 
58
 * each server.
 
59
 */
 
60
#define KEY_EVENT               1
 
61
#define BUTTON_EVENT            2
 
62
#define MOTION_EVENT            3
 
63
#define FOCUS_EVENT             4
 
64
#define PROXIMITY_EVENT         5
 
65
#define CHANGE_DEVICE_EVENT     6
 
66
#define DEVICE_MAPPING_EVENT    7
 
67
#define DEVICE_STATE_EVENT      8
 
68
 
 
69
/*
 
70
 * These constants must be kept in sync with the
 
71
 * xi_event_names array.
 
72
 */
 
73
#define KEY_PRESS               0
 
74
#define KEY_RELEASE             1
 
75
#define BUTTON_PRESS            2
 
76
#define BUTTON_PRESS_GRAB       3
 
77
#define BUTTON_PRESS_OWNER_GRAB 4
 
78
#define BUTTON_RELEASE          5
 
79
#define MOTION                  6
 
80
#define MOTION_HINT             7
 
81
#define BUTTON_MOTION           8
 
82
#define B1_MOTION               9
 
83
#define B2_MOTION               10
 
84
#define B3_MOTION               11
 
85
#define B4_MOTION               12
 
86
#define B5_MOTION               13
 
87
#define FOCUS_IN                14
 
88
#define FOCUS_OUT               15
 
89
#define PROXIMITY_IN            16
 
90
#define PROXIMITY_OUT           17
 
91
#define DEVICE_STATE            18
 
92
#define DEVICE_MAPPING          19
 
93
#define CHANGE_DEVICE           20
 
94
 
 
95
#define NUM_XI_EVENTS           21
 
96
#define NUM_EVENTS              256     /* Core limit of the protocol */
 
97
 
 
98
#define NUM_SIZE 50
 
99
 
 
100
static Tk_Uid xi_event_names[NUM_XI_EVENTS] = {
 
101
  "KeyPress",
 
102
  "KeyRelease",
 
103
  "ButtonPress",
 
104
  "ButtonPressGrab",
 
105
  "ButtonPressOwnerGrab",
 
106
  "ButtonRelease",
 
107
  "Motion",
 
108
  "MotionHint",
 
109
  "ButtonMotion",
 
110
  "B1Motion",
 
111
  "B2Motion",
 
112
  "B3Motion",
 
113
  "B4Motion",
 
114
  "B5Motion",
 
115
  "FocusIn",
 
116
  "FocusOut",
 
117
  "ProximityIn",
 
118
  "ProximityOut",
 
119
  "DeviceState",
 
120
  "DeviceMapping",
 
121
  "ChangeDevice",
 
122
};
 
123
 
 
124
typedef struct _EventHandlerStruct {
 
125
  Tk_EventProc                  *proc;
 
126
  ClientData                    client_data;
 
127
  int                           type;
 
128
  XID                           device_id;
 
129
  int                           num_classes;
 
130
  int                           classes[3];
 
131
  Tk_Window                     tkwin;
 
132
  struct _EventHandlerStruct    *next;
 
133
} EventHandlerStruct;
 
134
 
 
135
typedef struct _EventScriptRecord {
 
136
  struct _DeviceInfoStruct      *device;
 
137
  Tk_Uid                        event_spec;
 
138
  Tk_Window                     tkwin;
 
139
  Tcl_Interp                    *interp;
 
140
  char                          *script;
 
141
  struct _EventScriptRecord     *next;
 
142
} EventScriptRecord;
 
143
 
 
144
typedef struct _AxeInfo {
 
145
  int   min_value;
 
146
  int   max_value;
 
147
  int   resolution;
 
148
  int   value;
 
149
} AxeInfo;
 
150
 
 
151
typedef struct _DeviceInfoStruct {
 
152
  struct _DisplayInfoStruct *dpy_info;
 
153
  XDevice       *xdev;
 
154
  Tk_Uid        name;
 
155
  XID           id;
 
156
  char          core;           /* If the device is the core keyboard or pointer */
 
157
  unsigned char x_index;        /* index of valuator corresponding to core X */
 
158
  unsigned char y_index;        /* index of valuator corresponding to core Y */
 
159
  int           num_axes;
 
160
  int           num_keys;
 
161
  int           num_buttons;
 
162
  char          focusable;      /* True if the device can be explicitly focused */
 
163
  char          proximity;      /* True if the device can emit proximity events */
 
164
  char          feedback;       /* True if the device has some feedback control */
 
165
  int           mode;           /* ABSOLUTE or RELATIVE */
 
166
  int           history_size;
 
167
  Time          last_motion_time;
 
168
  
 
169
  AxeInfo       *axe_info;
 
170
  int           *valuator_cache; /* Used to store valuators if the device reports
 
171
                                  * more than six axes. The array is allocated
 
172
                                  * dynamically to match the number of axes. */
 
173
  int           event_classes[NUM_XI_EVENTS];
 
174
  int           no_event_class;
 
175
} DeviceInfoStruct;
 
176
 
 
177
typedef struct _DisplayInfoStruct {
 
178
  char          has_xdevices;           /* Non zero if some devices are available
 
179
                                         * (other than core devices). */
 
180
  Display       *display;               /* The display that is described. */
 
181
  DeviceInfoStruct *devices;            /* The device list */
 
182
  int           num_dev;
 
183
  char          event_types[NUM_XI_EVENTS];
 
184
  char          event_atypes[NUM_EVENTS]; /* Mapping from server local event types
 
185
                                           * to absolutes types independant from
 
186
                                           * servers. */
 
187
  int           event_base;             /* The first event type reported by the
 
188
                                         * xinput extension on this server. */
 
189
  Tcl_HashTable per_wins;               /* Records for all handlers per windows on
 
190
                                         * this display. */
 
191
  EventHandlerStruct *other_handlers;   /* The handlers associated with events not
 
192
                                         * reported relative to a window. */
 
193
  EventHandlerStruct *frozen_handlers;  /* The handlers on hold because theirs
 
194
                                         * devices are currently core devices. */
 
195
  struct _DisplayInfoStruct *next;
 
196
} DisplayInfoStruct;
 
197
 
 
198
typedef struct _WindowInfoStruct {
 
199
  EventHandlerStruct    *handlers;
 
200
  EventScriptRecord     *scripts;
 
201
} WindowInfoStruct;
 
202
 
 
203
typedef struct _InProgress {
 
204
  ClientData            next_handler;   /* Next handler in search. */
 
205
  struct _InProgress    *next;          /* Next higher nested search. */
 
206
} InProgress;
 
207
 
 
208
 
 
209
static DisplayInfoStruct *display_infos = NULL;
 
210
static InProgress *pending_handlers = NULL;
 
211
 
 
212
static void InvokeEventScript(ClientData client_data, XEvent *e);
 
213
static WindowInfoStruct *GetWindowInfo(Tk_Window w, int create);
 
214
 
 
215
 
 
216
/*
 
217
 *----------------------------------------------------------------------
 
218
 *
 
219
 * GetDisplayInfo --
 
220
 *      Return all known information known about the display.
 
221
 *      This gets all the needed informations on the available devices
 
222
 *      including their name.
 
223
 *      This has the side effect (on the first call) of gathering from
 
224
 *      the server, all devices that are hooked on the display.
 
225
 *
 
226
 *----------------------------------------------------------------------
 
227
 */
 
228
static DisplayInfoStruct *
 
229
GetDisplayInfo(Display  *dpy)
 
230
{
 
231
    XDeviceInfoPtr      device_list;
 
232
    DisplayInfoStruct   *info;
 
233
    DeviceInfoStruct    *device;
 
234
    int                 i, axe, num_classes;
 
235
    XAnyClassPtr        any;
 
236
    XKeyInfoPtr         k;
 
237
    XButtonInfoPtr      b;
 
238
    XValuatorInfoPtr    v;
 
239
    int                 dummy = 0;
 
240
 
 
241
/*printf("Begin of GetDisplayInfo\n");*/
 
242
  
 
243
    /*
 
244
     * Lookup the display in the already known list.
 
245
     */
 
246
    info = display_infos;
 
247
    while (info) 
 
248
    {
 
249
        if (dpy == info->display) 
 
250
        {
 
251
            /*printf("End of GetDisplayInfo\n");*/
 
252
            return info;
 
253
        }
 
254
        else 
 
255
        {
 
256
            info = info->next;
 
257
        }
 
258
    }
 
259
    /*
 
260
     * Nothing found, make a new entry and fill it with all the available info.
 
261
     */
 
262
    /*
 
263
     * First ask if the server has made the xinput extension available.
 
264
     */
 
265
    info = (DisplayInfoStruct *) ckalloc(sizeof(DisplayInfoStruct));
 
266
    info->next = display_infos;
 
267
    display_infos = info;
 
268
    info->has_xdevices = XQueryExtension(dpy, INAME, &dummy,
 
269
                                       &info->event_base, &dummy);
 
270
    info->display = dpy;
 
271
    Tcl_InitHashTable(&info->per_wins, TCL_ONE_WORD_KEYS);
 
272
    info->other_handlers = NULL;
 
273
    info->frozen_handlers = NULL;
 
274
    /*
 
275
     * Then ask the device list.
 
276
     */
 
277
    if (info->has_xdevices) 
 
278
    {
 
279
        device_list = (XDeviceInfoPtr) XListInputDevices(dpy, &info->num_dev);
 
280
 
 
281
        if (info->num_dev) 
 
282
        {
 
283
            info->devices = (DeviceInfoStruct *) 
 
284
                        ckalloc(info->num_dev * sizeof(DeviceInfoStruct));
 
285
 
 
286
            dummy = 0;
 
287
            for (device = info->devices, i = 0; i < info->num_dev; i++, device++) 
 
288
            {
 
289
                device->dpy_info = info;
 
290
                device->xdev = NULL;
 
291
                device->id = device_list[i].id;
 
292
                device->name = Tk_GetUid(device_list[i].name);
 
293
                device->core = ((device_list[i].use == IsXExtensionDevice) ? 0 :
 
294
                ((device_list[i].use == IsXPointer) ? CORE_POINTER : CORE_KEYBOARD));
 
295
                device->x_index = 0;
 
296
                device->y_index = 1;
 
297
                device->num_axes = 0;
 
298
                device->num_keys = 0;
 
299
                device->num_buttons = 0;
 
300
                device->focusable = 0;
 
301
                device->proximity = 0;
 
302
                device->feedback = 0;
 
303
                /*
 
304
                 * Setup each input class declared by the device.
 
305
                 */
 
306
                if (device_list[i].num_classes > 0) 
 
307
                {
 
308
                    num_classes = device_list[i].num_classes;
 
309
                    any = (XAnyClassPtr) device_list[i].inputclassinfo;
 
310
                    while (num_classes--) 
 
311
                    {
 
312
                        switch (any->class) 
 
313
                        {
 
314
                            case KeyClass:
 
315
                                k = (XKeyInfoPtr) any;
 
316
                                device->num_keys = k->num_keys;
 
317
                                break;
 
318
                            case ButtonClass:
 
319
                                b = (XButtonInfoPtr) any;
 
320
                                device->num_buttons = b->num_buttons;
 
321
                                break;
 
322
                            case ValuatorClass:
 
323
                                v = (XValuatorInfoPtr) any;
 
324
                                device->num_axes = v->num_axes;
 
325
                                device->axe_info = (AxeInfo*) 
 
326
                                        ckalloc(sizeof(AxeInfo)*v->num_axes);
 
327
                                device->history_size = v->motion_buffer;
 
328
                                for (axe = 0; axe < v->num_axes; axe++) 
 
329
                                {
 
330
                                    device->axe_info[axe].min_value = 
 
331
                                                v->axes[axe].min_value;
 
332
                                    device->axe_info[axe].max_value = 
 
333
                                                v->axes[axe].max_value;
 
334
                                    device->axe_info[axe].resolution = 
 
335
                                                v->axes[axe].resolution;
 
336
                                    device->axe_info[axe].value = 0;
 
337
                                }
 
338
                                break;
 
339
                            default:
 
340
                                break;
 
341
                        }
 
342
                        any = (XAnyClassPtr) ((char *) any + any->length);
 
343
                    }
 
344
                }
 
345
            }
 
346
            XFreeDeviceList(device_list);
 
347
        }
 
348
        else 
 
349
        {
 
350
            info->has_xdevices = 0;
 
351
        }
 
352
    }
 
353
    return info;
 
354
}
 
355
 
 
356
/*
 
357
 *----------------------------------------------------------------------
 
358
 *
 
359
 * LookupDeviceById --
 
360
 *      Return a device record from the display and the id of
 
361
 *      the device on the display. This is typically used to
 
362
 *      retrieve a device record from an event.
 
363
 *
 
364
 *----------------------------------------------------------------------
 
365
 */
 
366
static DeviceInfoStruct *
 
367
LookupDeviceById(Display        *dpy,
 
368
                 XID            device_id)
 
369
{
 
370
    DisplayInfoStruct   *info;
 
371
    int                 i;
 
372
  
 
373
    info = GetDisplayInfo(dpy);
 
374
    for (i = 0; i < info->num_dev; i++) 
 
375
    {
 
376
        if (info->devices[i].id == device_id) 
 
377
        {
 
378
            return &info->devices[i];
 
379
        }
 
380
    }
 
381
    return NULL;
 
382
}
 
383
 
 
384
/*
 
385
 *----------------------------------------------------------------------
 
386
 *
 
387
 * UpdateCoreMark --
 
388
 *      Extended event handler bound to ChangeDevice events.
 
389
 *
 
390
 *      It's purpose is to maintain the core bits (CORE_POINTER,
 
391
 *      CORE_KEYBOARD) in the device structs when the core devices
 
392
 *      change.
 
393
 *      This also implies that all handlers registered for the new
 
394
 *      core device are put on hold and all handlers put on hold for
 
395
 *      the previous core device are revived.
 
396
 *
 
397
 *----------------------------------------------------------------------
 
398
 */
 
399
static void
 
400
UpdateCoreMark(ClientData       client_data,
 
401
               XEvent           *e)
 
402
{
 
403
    XChangeDeviceNotifyEvent    *cdne = (XChangeDeviceNotifyEvent *) e;
 
404
    DeviceInfoStruct            *device, *old_device = NULL;
 
405
    DisplayInfoStruct           *info;
 
406
    int                         i, event_atype;
 
407
    EventHandlerStruct          *handlers, *h_prev, *h_next;
 
408
    Tcl_HashEntry               *entry;
 
409
    Tcl_HashSearch              search;
 
410
    WindowInfoStruct            *pw;
 
411
  
 
412
/*printf("UpdateCoreMark: type=%d, win=0x%X\n", e->type, (int)e->xany.window);*/
 
413
 
 
414
    device = LookupDeviceById(cdne->display, cdne->deviceid);
 
415
    info = device->dpy_info;
 
416
    for (i = 0; i < info->num_dev; i++) 
 
417
    {
 
418
        if ((info->devices[i].core == CORE_POINTER) &&
 
419
                (cdne->request == NewPointer)) 
 
420
        {
 
421
            old_device = &info->devices[i];
 
422
            old_device->core = 0;
 
423
/*printf("old pointer is %s\n", old_device->name);*/
 
424
            break;
 
425
        }
 
426
        else if ((info->devices[i].core == CORE_KEYBOARD) &&
 
427
                (cdne->request == NewKeyboard)) 
 
428
        {
 
429
            old_device = &info->devices[i];
 
430
            old_device->core = 0;
 
431
            break;
 
432
        }
 
433
    }
 
434
    if (cdne->request == NewKeyboard) 
 
435
    {
 
436
        device->core = CORE_KEYBOARD;
 
437
    }
 
438
    else if (cdne->request == NewPointer) 
 
439
    {
 
440
        device->core = CORE_POINTER;
 
441
/*printf("new pointer is %s\n", device->name);*/
 
442
    }
 
443
  
 
444
    /*
 
445
     * Try to unfreeze all handlers associated with the previous
 
446
     * core device.
 
447
     */
 
448
    for (handlers = info->frozen_handlers, h_prev = NULL; handlers != NULL;
 
449
       handlers = h_next) 
 
450
    {
 
451
        h_next = handlers->next;
 
452
        if (handlers->device_id == old_device->id) 
 
453
        {
 
454
            if (handlers == info->frozen_handlers) 
 
455
            {
 
456
                info->frozen_handlers = handlers->next;
 
457
            }
 
458
            else 
 
459
            {
 
460
                h_prev->next = handlers->next;
 
461
            }
 
462
            event_atype = info->event_atypes[handlers->type];
 
463
            if ((event_atype == CHANGE_DEVICE_EVENT) ||
 
464
                        (event_atype == DEVICE_MAPPING_EVENT) ||
 
465
                        (event_atype == DEVICE_STATE_EVENT)) 
 
466
            {
 
467
                handlers->next = info->other_handlers;
 
468
                info->other_handlers = handlers;
 
469
            }
 
470
            else 
 
471
            {
 
472
                WindowInfoStruct *pw = GetWindowInfo(handlers->tkwin, 0);       
 
473
                handlers->next = pw->handlers;
 
474
                pw->handlers = handlers;
 
475
            }
 
476
        }
 
477
        else 
 
478
        {
 
479
            h_prev = handlers;
 
480
        }
 
481
    }
 
482
    /*
 
483
     * Then try to freeze all handlers associated with the new
 
484
     * core device. First traverse the other_handlers list and
 
485
     * then all the per window handlers.
 
486
     */
 
487
    for (handlers = info->other_handlers, h_prev = NULL; 
 
488
                handlers != NULL; handlers = h_next) 
 
489
    {
 
490
        h_next = handlers->next;
 
491
        if (handlers->device_id == device->id) 
 
492
        {
 
493
            if (handlers == info->other_handlers) 
 
494
            {
 
495
                info->other_handlers = handlers->next;
 
496
            }
 
497
            else 
 
498
            {
 
499
                h_prev->next = handlers->next;
 
500
            }
 
501
            handlers->next = info->frozen_handlers;
 
502
            info->frozen_handlers = handlers;
 
503
        }
 
504
        else 
 
505
        {
 
506
            h_prev = handlers;
 
507
        }
 
508
    }
 
509
    entry = Tcl_FirstHashEntry(&info->per_wins, &search);
 
510
    while (entry) 
 
511
    {
 
512
        pw = (WindowInfoStruct *) Tcl_GetHashValue(entry);
 
513
        for (handlers = pw->handlers, h_prev = NULL; 
 
514
                        handlers != NULL; handlers = h_next) 
 
515
        {
 
516
            h_next = handlers->next;
 
517
            if (handlers->device_id == device->id) 
 
518
            {
 
519
                if (handlers == pw->handlers) 
 
520
                {
 
521
                    pw->handlers = handlers->next;
 
522
                }
 
523
                else 
 
524
                {
 
525
                    h_prev->next = handlers->next;
 
526
                }
 
527
                handlers->next = info->frozen_handlers;
 
528
                info->frozen_handlers = handlers;
 
529
            }
 
530
            else 
 
531
            {
 
532
                h_prev = handlers;
 
533
            }
 
534
        }
 
535
        entry = Tcl_NextHashEntry(&search);
 
536
    }
 
537
}
 
538
 
 
539
/*
 
540
 *----------------------------------------------------------------------
 
541
 *
 
542
 * GetDeviceInfo --
 
543
 *      Get the device descriptor for the device named 'name' on
 
544
 *      the given window's display. The device is opened as needed.
 
545
 *      If no such device exists on the display the function returns
 
546
 *      NULL.
 
547
 *
 
548
 *----------------------------------------------------------------------
 
549
 */
 
550
static DeviceInfoStruct *
 
551
GetDeviceInfo(Tk_Window tkwin,  /* Used to get the display */
 
552
              Tk_Uid    name)
 
553
{
 
554
    Display             *dpy = Tk_Display(tkwin);
 
555
    DisplayInfoStruct   *info;
 
556
    DeviceInfoStruct    *device = NULL;
 
557
    XInputClassInfo     *classes;
 
558
    int                 i, dummy;
 
559
 
 
560
    info = GetDisplayInfo(dpy);
 
561
/*printf("display_info=0x%X, display=0x%X\n", info, dpy);*/
 
562
    for (i = 0; i < info->num_dev; i++) 
 
563
    {
 
564
        if (info->devices[i].name == name) 
 
565
        {
 
566
            device = &info->devices[i];
 
567
        }
 
568
    }
 
569
    if (device) 
 
570
    {
 
571
        /*
 
572
         * Open the xdevice if not already done and not currently
 
573
         * a core device.
 
574
         */
 
575
/*printf("device=%s(0x%X), id=%d\n", device->name, device, (int)device->id);*/
 
576
        if (!device->xdev && !device->core) 
 
577
        {
 
578
            dummy = 0;
 
579
            device->xdev = XOpenDevice(dpy, device->id);
 
580
            if (device->xdev) 
 
581
            {
 
582
                /*
 
583
                 * Process all declared input classes. This code finalizes
 
584
                 * the work done when getting the device list for the display.
 
585
                 * Some input classes are not reported until the device is open.
 
586
                 */
 
587
                for (i = 0, classes = device->xdev->classes; 
 
588
                        i < device->xdev->num_classes; i++, classes++) 
 
589
                {
 
590
                    switch (classes->input_class) 
 
591
                    {
 
592
                        case ButtonClass:
 
593
                            DeviceButtonRelease(device->xdev, 
 
594
                                info->event_types[BUTTON_RELEASE],
 
595
                                device->event_classes[BUTTON_RELEASE]);
 
596
                            DeviceButtonPress(device->xdev, 
 
597
                                info->event_types[BUTTON_PRESS],
 
598
                                device->event_classes[BUTTON_PRESS]);
 
599
                            info->event_atypes[(int)info->
 
600
                                event_types[BUTTON_RELEASE]] = BUTTON_EVENT;
 
601
                            info->event_atypes[(int)info->
 
602
                                event_types[BUTTON_PRESS]] = BUTTON_EVENT;
 
603
                            break;
 
604
                        case KeyClass:
 
605
                            DeviceKeyRelease(device->xdev, 
 
606
                                info->event_types[KEY_RELEASE],
 
607
                                device->event_classes[KEY_RELEASE]);
 
608
                            DeviceKeyPress(device->xdev, 
 
609
                                info->event_types[KEY_PRESS],
 
610
                                device->event_classes[KEY_PRESS]);
 
611
                            info->event_atypes[(int)info->
 
612
                                event_types[KEY_RELEASE]] = KEY_EVENT;
 
613
                            info->event_atypes[(int)info->
 
614
                                event_types[KEY_PRESS]] = KEY_EVENT;
 
615
                            break;
 
616
                        case ValuatorClass:
 
617
                            DeviceMotionNotify(device->xdev, 
 
618
                                info->event_types[MOTION],
 
619
                                device->event_classes[MOTION]);
 
620
                            DevicePointerMotionHint(device->xdev, dummy,
 
621
                                device->event_classes[MOTION_HINT]);
 
622
                            info->event_types[MOTION_HINT] = 
 
623
                                info->event_types[MOTION];
 
624
                            info->event_atypes[(int)info->
 
625
                                event_types[MOTION]] = MOTION_EVENT;
 
626
                            break;
 
627
                        case FocusClass:
 
628
                            device->focusable = 1;
 
629
                            DeviceFocusIn(device->xdev, 
 
630
                                info->event_types[FOCUS_IN],
 
631
                                device->event_classes[FOCUS_IN]);
 
632
                            DeviceFocusOut(device->xdev, 
 
633
                                info->event_types[FOCUS_OUT],
 
634
                                device->event_classes[FOCUS_OUT]);
 
635
                            info->event_atypes[(int)info->
 
636
                                event_types[FOCUS_IN]] = FOCUS_EVENT;
 
637
                            info->event_atypes[(int)info->
 
638
                                event_types[FOCUS_OUT]] = FOCUS_EVENT;
 
639
                            break;
 
640
                        case ProximityClass:
 
641
                            device->proximity = 1;
 
642
                            ProximityIn(device->xdev, 
 
643
                                info->event_types[PROXIMITY_IN],
 
644
                                device->event_classes[PROXIMITY_IN]);
 
645
                            ProximityOut(device->xdev, 
 
646
                                info->event_types[PROXIMITY_OUT],
 
647
                                device->event_classes[PROXIMITY_OUT]);
 
648
                            info->event_atypes[(int)info->
 
649
                                event_types[PROXIMITY_OUT]] = PROXIMITY_EVENT;
 
650
                            info->event_atypes[(int)info->
 
651
                                event_types[PROXIMITY_IN]] = PROXIMITY_EVENT;
 
652
                            break;
 
653
                        case FeedbackClass:
 
654
                            device->feedback = 1;
 
655
                            break;
 
656
                    }
 
657
                }
 
658
                /*
 
659
                 * If the device can report both valuators and buttons, it is
 
660
                 * possible to ask for these events. The event type is Motion.
 
661
                 */
 
662
                if (device->num_buttons && device->num_axes) 
 
663
                {
 
664
                    DeviceButtonMotion(device->xdev, dummy,
 
665
                        device->event_classes[BUTTON_MOTION]);
 
666
                    info->event_types[BUTTON_MOTION] = 
 
667
                        info->event_types[MOTION];
 
668
                    DeviceButton1Motion(device->xdev, dummy,
 
669
                        device->event_classes[B1_MOTION]);
 
670
                    info->event_types[B1_MOTION] = 
 
671
                        info->event_types[MOTION];
 
672
                    DeviceButton2Motion(device->xdev, dummy,
 
673
                        device->event_classes[B2_MOTION]);
 
674
                    info->event_types[B2_MOTION] = 
 
675
                        info->event_types[MOTION];
 
676
                    DeviceButton3Motion(device->xdev, dummy,
 
677
                        device->event_classes[B3_MOTION]);
 
678
                    info->event_types[B3_MOTION] = 
 
679
                        info->event_types[MOTION];
 
680
                    DeviceButton4Motion(device->xdev, dummy,
 
681
                        device->event_classes[B4_MOTION]);
 
682
                    info->event_types[B4_MOTION] = 
 
683
                        info->event_types[MOTION];
 
684
                    DeviceButton5Motion(device->xdev, dummy,
 
685
                        device->event_classes[B5_MOTION]);
 
686
                    info->event_types[B5_MOTION] = 
 
687
                        info->event_types[MOTION];
 
688
                }
 
689
                /*
 
690
                 * Setup the no-event class for this device.
 
691
                 */
 
692
                NoExtensionEvent(device->xdev, dummy, device->no_event_class);
 
693
                /*
 
694
                 * Setup the ChangeDevice, DeviceMapping and DeviceState
 
695
                 * classes and types.
 
696
                 */
 
697
                ChangeDeviceNotify(device->xdev, 
 
698
                        info->event_types[CHANGE_DEVICE],
 
699
                        device->event_classes[CHANGE_DEVICE]);
 
700
                info->event_atypes[(int)info->
 
701
                        event_types[CHANGE_DEVICE]] = CHANGE_DEVICE_EVENT;
 
702
                DeviceMappingNotify(device->xdev, 
 
703
                        info->event_types[DEVICE_MAPPING],
 
704
                        device->event_classes[DEVICE_MAPPING]);
 
705
                info->event_atypes[(int)info->
 
706
                        event_types[DEVICE_MAPPING]] = DEVICE_MAPPING_EVENT;
 
707
                DeviceStateNotify(device->xdev, 
 
708
                        info->event_types[DEVICE_STATE],
 
709
                        device->event_classes[DEVICE_STATE]);
 
710
                info->event_atypes[(int)info->
 
711
                        event_types[DEVICE_STATE]] = DEVICE_STATE_EVENT;
 
712
                /*
 
713
                 * If the device has more than six valuators, allocate an
 
714
                 * array big enough to hold all the valuators of the device.
 
715
                 */
 
716
                if (device->num_axes) 
 
717
                {
 
718
                    device->valuator_cache = (int *) 
 
719
                        ckalloc(device->num_axes*sizeof(int));
 
720
                }
 
721
                else 
 
722
                {
 
723
                    device->valuator_cache = NULL;
 
724
                }
 
725
                /*
 
726
                 * Create an event handler on ChangeDevice 
 
727
                 * to update the core field.
 
728
                 */
 
729
                Tk_CreateXiEventHandler(tkwin, 
 
730
                        xi_event_names[CHANGE_DEVICE], 
 
731
                        device->name,
 
732
                        UpdateCoreMark, NULL);
 
733
            }
 
734
        }
 
735
        if (!device->xdev || device->core) 
 
736
        {
 
737
            /*
 
738
             * Open failed or access denied, return NULL to inform the caller.
 
739
             */
 
740
            device = NULL;
 
741
        }
 
742
    }
 
743
/*printf("End of GetDeviceInfo\n");*/
 
744
 
 
745
  return device;
 
746
}
 
747
 
 
748
/*
 
749
 *----------------------------------------------------------------------
 
750
 *
 
751
 * GetEventIndex --
 
752
 *      Given an event spec uid, the function return the corresponding
 
753
 *      event index, needed to retrieve the type and class values.
 
754
 *      If the string does not describe a valid event, the function
 
755
 *      return -1.
 
756
 *
 
757
 *----------------------------------------------------------------------
 
758
 */
 
759
static int
 
760
GetEventIndex(Tk_Uid    event_spec)
 
761
{
 
762
    int         i;
 
763
 
 
764
    for (i = 0; i < NUM_XI_EVENTS; i++) 
 
765
    {
 
766
        if (xi_event_names[i] == event_spec) 
 
767
        {
 
768
            return i;
 
769
        }
 
770
    }
 
771
    return -1;
 
772
}
 
773
 
 
774
/*
 
775
 *----------------------------------------------------------------------
 
776
 *
 
777
 * DestroyPerWindow --
 
778
 *      Called when a window is destroyed to cleanup the event handlers
 
779
 *      that remain registered.
 
780
 *      No care is taken to prevent a race with Tk_DispatchXiEvent
 
781
 *      since DestroyPerWindow is also triggered as an event handler
 
782
 *      and thus should not be active at the same time. This is unfor-
 
783
 *      tunately a _FALSE_ guess, DestroyNotify is generated internally
 
784
 *      and processed as soon as the destroy command is emitted.
 
785
 *
 
786
 *----------------------------------------------------------------------
 
787
 */
 
788
static void
 
789
DestroyPerWindow(ClientData     client_data,
 
790
                 XEvent         *e)
 
791
{
 
792
    Tk_Window           w = (Tk_Window) client_data;
 
793
    DisplayInfoStruct   *info;
 
794
    EventScriptRecord   *escripts, *es_next;
 
795
    EventHandlerStruct  *handlers, *h_next, *h_prev;
 
796
    WindowInfoStruct    *pw;
 
797
    Tcl_HashEntry       *he;
 
798
    InProgress          *ip;
 
799
  
 
800
    if (e->type == DestroyNotify) 
 
801
    {
 
802
/*printf("Begin of DestroyPerWindow\n");*/
 
803
        info = GetDisplayInfo(e->xany.display);
 
804
        he = Tcl_FindHashEntry(&info->per_wins, (char *) w);
 
805
        if (he) 
 
806
        {
 
807
            pw = (WindowInfoStruct *) Tcl_GetHashValue(he);
 
808
            for (handlers = pw->handlers; handlers != NULL; handlers = h_next)
 
809
            {
 
810
                h_next = handlers->next;
 
811
                /*
 
812
                 * Need to see if Tk_DispatchXiEvent is not about to
 
813
                 * fire this handler. If it is, just abort the whole
 
814
                 * dispatch thread, the window is gone.
 
815
                 */
 
816
                for (ip = pending_handlers; ip != NULL; ip = ip->next) 
 
817
                {
 
818
                    if (ip->next_handler == (ClientData) handlers) 
 
819
                    {
 
820
                        ip->next_handler = NULL;
 
821
                    }
 
822
                }
 
823
                ckfree((char *) handlers);
 
824
            }
 
825
            for (escripts = pw->scripts; escripts != NULL; escripts = es_next) 
 
826
            {
 
827
                es_next = escripts->next;
 
828
                ckfree(escripts->script);
 
829
                ckfree((char *) escripts);
 
830
            }
 
831
            ckfree((char *) pw);
 
832
            Tcl_DeleteHashEntry(he);
 
833
        }
 
834
        /*
 
835
         * Scan through the 'special events' handlers.
 
836
         */
 
837
        for (handlers = info->other_handlers, h_prev = NULL; 
 
838
                handlers != NULL; handlers = h_next) 
 
839
        {
 
840
            h_next = handlers->next;
 
841
            if (handlers->tkwin == w) 
 
842
            {
 
843
                if (handlers == info->other_handlers) 
 
844
                {
 
845
                    info->other_handlers = h_next;
 
846
                }
 
847
                else 
 
848
                {
 
849
                    h_prev->next = h_next;
 
850
                }
 
851
                /*
 
852
                 * Need to see if Tk_DispatchXiEvent is not about to
 
853
                 * fire this handler. If it is, point it to the next.
 
854
                 */
 
855
                for (ip = pending_handlers; ip != NULL; ip = ip->next) 
 
856
                {
 
857
                    if (ip->next_handler == (ClientData) handlers) 
 
858
                    {
 
859
                        ip->next_handler = h_next;
 
860
                    }
 
861
                }       
 
862
                ckfree((char *) handlers);
 
863
            }
 
864
            else 
 
865
            {
 
866
                h_prev = handlers;
 
867
            }
 
868
        }
 
869
        /*
 
870
         * Scan through the frozen handlers.
 
871
         */
 
872
        for (handlers = info->frozen_handlers, h_prev = NULL; 
 
873
                handlers != NULL; handlers = h_next) 
 
874
        {
 
875
            h_next = handlers->next;
 
876
            if (handlers->tkwin == w) 
 
877
            {
 
878
                if (handlers == info->frozen_handlers) 
 
879
                {
 
880
                    info->frozen_handlers = handlers->next;
 
881
                }
 
882
                else 
 
883
                {
 
884
                    h_prev->next = handlers->next;
 
885
                }
 
886
                ckfree((char *) handlers);
 
887
            }
 
888
            else 
 
889
            {
 
890
                h_prev = handlers;
 
891
            }
 
892
        }
 
893
/*printf("End of DestroyPerWindow\n");*/
 
894
    }
 
895
}
 
896
 
 
897
/*
 
898
 *----------------------------------------------------------------------
 
899
 *
 
900
 * GetWindowInfo --
 
901
 *      Return the handlers registered for the window.
 
902
 *
 
903
 *----------------------------------------------------------------------
 
904
 */
 
905
static WindowInfoStruct *
 
906
GetWindowInfo(Tk_Window w,
 
907
              int       create)
 
908
{
 
909
    DisplayInfoStruct   *info = GetDisplayInfo(Tk_Display(w));
 
910
    Tcl_HashEntry       *he;
 
911
    WindowInfoStruct    *pw;
 
912
    int                 new;
 
913
  
 
914
/*printf("Begin of GetWindowInfo\n");*/
 
915
  
 
916
    he = Tcl_FindHashEntry(&info->per_wins, (char *) w);
 
917
    if (he == NULL) 
 
918
    {
 
919
        if (create) 
 
920
        {
 
921
            pw = (WindowInfoStruct *) ckalloc(sizeof(WindowInfoStruct));
 
922
            pw->handlers = NULL;
 
923
            pw->scripts = NULL;
 
924
            he = Tcl_CreateHashEntry(&info->per_wins, (char *) w, &new);
 
925
            Tcl_SetHashValue(he, pw);
 
926
            Tk_CreateEventHandler(w, StructureNotifyMask, DestroyPerWindow, w);
 
927
        }
 
928
        else 
 
929
        {
 
930
            pw = NULL;
 
931
        }
 
932
/*printf("End of GetWindowInfo\n");*/
 
933
        return pw;
 
934
    }
 
935
 
 
936
/*printf("End of GetWindowInfo\n");*/
 
937
    return (WindowInfoStruct *) Tcl_GetHashValue(he);
 
938
}
 
939
 
 
940
/*
 
941
 *----------------------------------------------------------------------
 
942
 *
 
943
 * SelectEvents --
 
944
 *      Traverse all event handlers for a given window and collect
 
945
 *      all classes needed for correct event selection. With this,
 
946
 *      select the requested events on the window. This may also
 
947
 *      unselect as needed all events from a device.
 
948
 *
 
949
 *----------------------------------------------------------------------
 
950
 */
 
951
static void
 
952
SelectEvents(Tk_Window  w,
 
953
             int        no_event_class)
 
954
{
 
955
    DisplayInfoStruct   *info = GetDisplayInfo(Tk_Display(w));
 
956
    WindowInfoStruct    *pw = GetWindowInfo(w, 0);
 
957
    EventHandlerStruct  *handlers;
 
958
    int                 i, count = 0;
 
959
    int                 *classes;
 
960
  
 
961
/*printf("Begin SelectEvents\n");*/
 
962
    if (no_event_class >= 0) 
 
963
    {
 
964
        count++;
 
965
    }
 
966
    if (pw) 
 
967
    {
 
968
        for (handlers = pw->handlers; handlers; handlers = handlers->next) 
 
969
        {
 
970
            count += handlers->num_classes;
 
971
        }
 
972
    }
 
973
    for (handlers = info->other_handlers; handlers; handlers = handlers->next) 
 
974
    {
 
975
        if (handlers->tkwin == w) 
 
976
        {
 
977
            count += handlers->num_classes;
 
978
        }
 
979
    }
 
980
 
 
981
    if (count == 0) return;
 
982
 
 
983
    classes = (int *) alloca(count * sizeof(int));
 
984
    count = 0;
 
985
    if (no_event_class >= 0) 
 
986
    {
 
987
        classes[count] = no_event_class;
 
988
        count++;
 
989
    }
 
990
    if (pw) 
 
991
    {
 
992
        for (handlers = pw->handlers; handlers; handlers = handlers->next) 
 
993
        {
 
994
            for (i = 0; i < handlers->num_classes; i++, count++) 
 
995
            {
 
996
                classes[count] = handlers->classes[i];
 
997
            }
 
998
        }
 
999
    }
 
1000
    for (handlers = info->other_handlers; handlers; handlers = handlers->next) 
 
1001
    {
 
1002
        if (handlers->tkwin == w) 
 
1003
        {
 
1004
            for (i = 0; i < handlers->num_classes; i++, count++) 
 
1005
            {
 
1006
                classes[count] = handlers->classes[i];
 
1007
            }
 
1008
        }
 
1009
    }
 
1010
 
 
1011
    XSelectExtensionEvent(Tk_Display(w), Tk_WindowId(w),
 
1012
                        (XEventClass *) classes, count);
 
1013
}
 
1014
 
 
1015
/*
 
1016
 *----------------------------------------------------------------------
 
1017
 *
 
1018
 * Tk_CreateXiEventHandler --
 
1019
 *      Public function provided to declare an event handler for
 
1020
 *      an event from a device on a window. The client can pass a
 
1021
 *      procedure to be called and a data pointer that will be passed
 
1022
 *      back to the procedure.
 
1023
 *
 
1024
 *      If it is not possible to bind the event the function return
 
1025
 *      0 else it returns 1.
 
1026
 *
 
1027
 *----------------------------------------------------------------------
 
1028
 */
 
1029
int
 
1030
Tk_CreateXiEventHandler(Tk_Window       w,
 
1031
                        Tk_Uid          event_spec,
 
1032
                        Tk_Uid          device_spec,
 
1033
                        Tk_EventProc    *proc,
 
1034
                        ClientData      client_data)
 
1035
{
 
1036
    int                 found, no_window;
 
1037
    int                 event_index, event_type, event_atype;
 
1038
    WindowInfoStruct    *pw;
 
1039
    EventHandlerStruct  *handlers, **handlers_head;
 
1040
    DeviceInfoStruct    *device;
 
1041
    DisplayInfoStruct   *info;
 
1042
  
 
1043
/*printf("Begin Tk_CreateXiEventHandler\n");*/
 
1044
  
 
1045
    device = GetDeviceInfo(w, device_spec);
 
1046
    info = device->dpy_info;
 
1047
    event_index = GetEventIndex(event_spec);
 
1048
 
 
1049
    if (event_index < 0) return 0;
 
1050
 
 
1051
    event_type = info->event_types[event_index];
 
1052
    event_atype = info->event_atypes[event_type];
 
1053
    if (((event_atype == KEY_EVENT) && !device->num_keys) ||
 
1054
      ((event_atype == BUTTON_EVENT) && !device->num_buttons) ||
 
1055
      ((event_atype == MOTION_EVENT) && !device->num_axes) ||
 
1056
      ((event_atype == FOCUS_EVENT) && !device->focusable) ||
 
1057
      ((event_atype == PROXIMITY_EVENT) && !device->proximity)) 
 
1058
    {
 
1059
        return 0;
 
1060
    }
 
1061
 
 
1062
    /*
 
1063
     * Special case for events that do not report a window.
 
1064
     */
 
1065
    no_window = ((event_atype == CHANGE_DEVICE_EVENT) ||
 
1066
               (event_atype == DEVICE_MAPPING_EVENT) ||
 
1067
               (event_atype == DEVICE_STATE_EVENT));
 
1068
  
 
1069
    if (no_window) 
 
1070
    {
 
1071
        handlers_head = &info->other_handlers;
 
1072
    }
 
1073
    else 
 
1074
    {
 
1075
        pw = GetWindowInfo(w, 1);
 
1076
        handlers_head = &pw->handlers;
 
1077
    }
 
1078
  
 
1079
    /*
 
1080
     * Lookup if the proc is already installed with the same
 
1081
     * client_data for the same event and device.
 
1082
     */
 
1083
    found = 0;
 
1084
    for (handlers = *handlers_head ; handlers; handlers = handlers->next) 
 
1085
    {
 
1086
        if ((handlers->proc == proc) && 
 
1087
                (handlers->client_data == client_data) &&
 
1088
                (handlers->type == event_type) && 
 
1089
                (handlers->device_id == device->id)) 
 
1090
        {
 
1091
            found = 1;
 
1092
            break;
 
1093
        }
 
1094
    }
 
1095
  
 
1096
    if (!found) 
 
1097
    {
 
1098
        handlers = (EventHandlerStruct *) ckalloc(sizeof(EventHandlerStruct));
 
1099
        handlers->next = *handlers_head;
 
1100
        *handlers_head = handlers;
 
1101
        handlers->proc = proc;
 
1102
        handlers->client_data = client_data;
 
1103
        handlers->type = event_type;
 
1104
        handlers->device_id = device->id;
 
1105
        handlers->tkwin = w;
 
1106
    
 
1107
        if ((event_index == BUTTON_PRESS_GRAB) ||
 
1108
                (event_index == BUTTON_PRESS_OWNER_GRAB)) 
 
1109
        {
 
1110
            handlers->num_classes = 2;
 
1111
            handlers->classes[0] = device->event_classes[BUTTON_PRESS];
 
1112
            handlers->classes[1] = device->event_classes[BUTTON_PRESS_GRAB];
 
1113
            if (event_index == BUTTON_PRESS_OWNER_GRAB) 
 
1114
            {
 
1115
                handlers->num_classes++;
 
1116
                handlers->classes[2] = 
 
1117
                        device->event_classes[BUTTON_PRESS_OWNER_GRAB]; 
 
1118
            }
 
1119
        }
 
1120
        else if (event_index == MOTION_HINT) 
 
1121
        {
 
1122
            handlers->num_classes = 2;
 
1123
            handlers->classes[0] = device->event_classes[MOTION];
 
1124
            handlers->classes[1] = device->event_classes[MOTION_HINT];
 
1125
        }
 
1126
        else 
 
1127
        {
 
1128
            handlers->num_classes = 1;
 
1129
            handlers->classes[0] = device->event_classes[event_index];
 
1130
        }
 
1131
    }
 
1132
 
 
1133
    /*
 
1134
     * Now we need to check if the widget window is created and
 
1135
     * if it is, select the right events.
 
1136
     */
 
1137
    if (Tk_WindowId(w)) 
 
1138
    {
 
1139
        SelectEvents(w, -1);
 
1140
    }
 
1141
 
 
1142
/*printf("End Tk_CreateXiEventHandler\n");*/
 
1143
    return 1;
 
1144
}
 
1145
 
 
1146
/*
 
1147
 *----------------------------------------------------------------------
 
1148
 *
 
1149
 * Tk_DeleteXiEventHandler --
 
1150
 *      Public function provided to suppress an event handler for
 
1151
 *      an event from a device on a window. The client pass a
 
1152
 *      procedure and a data pointer to be matched. Only the handler
 
1153
 *      matching all criteria will be removed.
 
1154
 *
 
1155
 *----------------------------------------------------------------------
 
1156
 */
 
1157
void
 
1158
Tk_DeleteXiEventHandler(Tk_Window       w,
 
1159
                        Tk_Uid          event_spec,
 
1160
                        Tk_Uid          device_spec,
 
1161
                        Tk_EventProc    *proc,
 
1162
                        ClientData      client_data)
 
1163
{
 
1164
    WindowInfoStruct    *pw;
 
1165
    int                 event_index, event_type, event_atype;
 
1166
    DeviceInfoStruct    *device;
 
1167
    EventHandlerStruct  *handlers, *prev, *next;
 
1168
    EventHandlerStruct  **handlers_head;
 
1169
    InProgress          *ip;
 
1170
    int                 no_window;
 
1171
    int                 device_in_use = 0;
 
1172
  
 
1173
/*printf("Begin Tk_DeleteXiEventHandler\n");*/
 
1174
    device = GetDeviceInfo(w, device_spec);
 
1175
    event_index = GetEventIndex(event_spec);
 
1176
    event_type = device->dpy_info->event_types[event_index];
 
1177
    event_atype = device->dpy_info->event_atypes[event_type];
 
1178
 
 
1179
    /*
 
1180
     * Special case for events that do not report a window.
 
1181
     */
 
1182
    no_window = ((event_atype == CHANGE_DEVICE_EVENT) ||
 
1183
               (event_atype == DEVICE_MAPPING_EVENT) ||
 
1184
               (event_atype == DEVICE_STATE_EVENT));
 
1185
 
 
1186
    if (no_window) 
 
1187
    {
 
1188
        handlers_head = &device->dpy_info->other_handlers;
 
1189
    }
 
1190
    else 
 
1191
    {
 
1192
        pw = GetWindowInfo(w, 0);
 
1193
 
 
1194
        if ( !pw ) return;
 
1195
 
 
1196
        handlers_head = &pw->handlers;
 
1197
    }
 
1198
  
 
1199
    for (handlers = *handlers_head, prev = NULL;
 
1200
                 handlers != NULL; handlers = next) 
 
1201
    {
 
1202
        if ((handlers->proc == proc) && 
 
1203
                (handlers->client_data == client_data) &&
 
1204
                (handlers->type == event_type) && 
 
1205
                (handlers->device_id == device->id)) 
 
1206
        {
 
1207
            /* Ok, found the handler we are looking for, but we need
 
1208
             * to check if Tk_DispatchXiEvent is not about to
 
1209
             * process the handler. If it is, skip to the next.
 
1210
             */
 
1211
            next = handlers->next;
 
1212
 
 
1213
            for (ip = pending_handlers; ip != NULL; ip = ip->next) 
 
1214
            {
 
1215
                if (ip->next_handler == (ClientData) handlers) 
 
1216
                {
 
1217
                    ip->next_handler = (ClientData) next;
 
1218
                }
 
1219
            }
 
1220
            /*
 
1221
             * Unlink and free the handler.
 
1222
             */
 
1223
            if (handlers == *handlers_head) 
 
1224
            {
 
1225
                *handlers_head = next;
 
1226
            }
 
1227
            else 
 
1228
            {
 
1229
                prev->next = next;
 
1230
            }
 
1231
            ckfree((char *) handlers);
 
1232
        }
 
1233
        else 
 
1234
        {
 
1235
            prev = handlers;
 
1236
            /*
 
1237
             * Record if the device will be still in use after the
 
1238
             * removal of this handler.
 
1239
             */
 
1240
            next = handlers->next;
 
1241
            device_in_use = device_in_use || (handlers->device_id == device->id);
 
1242
        }
 
1243
    }
 
1244
    /*
 
1245
     * Now we need to check if the widget window is created and
 
1246
     * if it is, select the right events.
 
1247
     */
 
1248
/*printf("device in use %s, %d, no_event=%d\n", device->name, device_in_use,
 
1249
         device->no_event_class);*/
 
1250
    if (Tk_WindowId(w)) 
 
1251
    {
 
1252
        SelectEvents(w, device_in_use ? -1 : device->no_event_class);
 
1253
    }
 
1254
/*printf("End Tk_DeleteXiEventHandler\n");*/
 
1255
}
 
1256
 
 
1257
/*
 
1258
 *----------------------------------------------------------------------
 
1259
 *
 
1260
 * WacomxiGenericEventHandler --
 
1261
 *      The generic event handler that is used to hook this extension
 
1262
 *      in Tk event machinery.
 
1263
 *      If checks if the event is from the xinput extension and
 
1264
 *      dispatchs it using Tk_DispatchXiEvent on the appropriate
 
1265
 *      window.
 
1266
 *
 
1267
 *----------------------------------------------------------------------
 
1268
 */
 
1269
static int
 
1270
WacomxiGenericEventHandler(ClientData   client_data,
 
1271
                      XEvent            *event)
 
1272
{
 
1273
    DisplayInfoStruct   *info;
 
1274
  
 
1275
    info = GetDisplayInfo(event->xany.display);
 
1276
    if ((event->type >= info->event_base) &&
 
1277
                (event->type < (info->event_base+IEVENTS))) 
 
1278
    {
 
1279
        return Tk_DispatchXiEvent(event);
 
1280
    }
 
1281
 
 
1282
    /* Not able to dispatch return and let the standard system have a try.
 
1283
     */
 
1284
    return 0;
 
1285
}
 
1286
 
 
1287
/*
 
1288
 *----------------------------------------------------------------------
 
1289
 *
 
1290
 * Tk_DispatchXiEvent --
 
1291
 *      Public function provided to dispatch an xinput event to a
 
1292
 *      window. The event must be an xinput event.
 
1293
 *
 
1294
 *----------------------------------------------------------------------
 
1295
 */
 
1296
int
 
1297
Tk_DispatchXiEvent(XEvent       *e)
 
1298
{
 
1299
    WindowInfoStruct    *pw;
 
1300
    Tk_Window           tkwin;
 
1301
    InProgress          ip;
 
1302
    EventHandlerStruct  *handlers;
 
1303
    DisplayInfoStruct   *info;
 
1304
    int                 hit = 0;
 
1305
  
 
1306
/*printf("Begin Tk_DispatchXiEvent : %d\n", e->type);*/
 
1307
 
 
1308
    /*
 
1309
     * Special case needed for ChangeDeviceEvent, DeviceMappingEvent
 
1310
     * and DeviceStateEvent because the window is not reported.
 
1311
     */
 
1312
    if (e->xany.window) 
 
1313
    {
 
1314
        tkwin = Tk_IdToWindow(e->xany.display, e->xany.window);
 
1315
 
 
1316
        if ( !tkwin ) return hit;
 
1317
 
 
1318
        pw = GetWindowInfo(tkwin, 0);
 
1319
 
 
1320
        if ( !pw ) return hit;
 
1321
 
 
1322
        handlers = pw->handlers;
 
1323
    }
 
1324
    else 
 
1325
    {
 
1326
        info = GetDisplayInfo(e->xany.display);
 
1327
        handlers = info->other_handlers;
 
1328
    }
 
1329
  
 
1330
    ip.next_handler = NULL;
 
1331
    ip.next = pending_handlers;
 
1332
    pending_handlers = &ip;
 
1333
    for ( ; handlers != NULL; ) 
 
1334
    {
 
1335
        if ((handlers->type == e->type) &&
 
1336
                (handlers->device_id == ((XDeviceKeyEvent *) e)->deviceid)) 
 
1337
        {
 
1338
            hit = 1;
 
1339
            ip.next_handler = (ClientData) handlers->next;
 
1340
            (*(handlers->proc))(handlers->client_data, e);
 
1341
            handlers = (EventHandlerStruct *) ip.next_handler;
 
1342
        }
 
1343
        else 
 
1344
        {
 
1345
            handlers = handlers->next; 
 
1346
        }
 
1347
    }
 
1348
    pending_handlers = pending_handlers->next;
 
1349
 
 
1350
/*printf("End Tk_DispatchXiEvent\n");*/
 
1351
    return hit;
 
1352
}
 
1353
 
 
1354
 
 
1355
/*
 
1356
 *----------------------------------------------------------------------
 
1357
 *
 
1358
 * RemoveEventScript --
 
1359
 *      Delete a script associated with and event from a device. The
 
1360
 *      server is asked to stop reporting this event in the window.
 
1361
 *
 
1362
 *----------------------------------------------------------------------
 
1363
 */
 
1364
static void
 
1365
RemoveEventScript(Tcl_Interp    *interp,
 
1366
                  Tk_Window     tkwin,
 
1367
                  DeviceInfoStruct *device,
 
1368
                  Tk_Uid        event_spec)
 
1369
{
 
1370
    WindowInfoStruct    *pw = GetWindowInfo(tkwin, 0);
 
1371
    EventScriptRecord   *escripts, *prev_escript;
 
1372
 
 
1373
/*printf("Begin RemoveEventScript\n");
 
1374
printf("for %s\n", event_spec);*/
 
1375
    /*
 
1376
     * No window info. The window has probably been destroyed.
 
1377
     */
 
1378
    if ( !pw ) return;
 
1379
 
 
1380
    for (escripts = pw->scripts, prev_escript = NULL; 
 
1381
                escripts != NULL; 
 
1382
                prev_escript = escripts, escripts = escripts->next) 
 
1383
    {
 
1384
        if ((escripts->device == device) &&
 
1385
                (escripts->event_spec == event_spec) &&
 
1386
                (escripts->interp == interp)) 
 
1387
        {
 
1388
            /*
 
1389
             * Ok, found the script we are looking for.
 
1390
             * Unlink the script from the list.
 
1391
             */
 
1392
            if (escripts == pw->scripts) 
 
1393
            {
 
1394
                pw->scripts = escripts->next;
 
1395
            }
 
1396
            else 
 
1397
            {
 
1398
                prev_escript->next = escripts->next;
 
1399
            }
 
1400
            Tk_DeleteXiEventHandler(tkwin, event_spec, device->name,
 
1401
                        InvokeEventScript, (ClientData) escripts);
 
1402
            ckfree(escripts->script);
 
1403
            ckfree((char *) escripts);
 
1404
            break;
 
1405
        }
 
1406
    }
 
1407
/*printf("End RemoveEventScript\n");*/
 
1408
}
 
1409
 
 
1410
/*
 
1411
 *----------------------------------------------------------------------
 
1412
 *
 
1413
 * ExpandPercents --
 
1414
 *      Do the actual work of expanding the percents in a script. The
 
1415
 *      code is an adaptation of the function of the same name in
 
1416
 *      tkBind.c                To be completed
 
1417
 *
 
1418
 *----------------------------------------------------------------------
 
1419
 */
 
1420
 
 
1421
static void
 
1422
ExpandPercents(Tk_Window        tkwin,
 
1423
               DeviceInfoStruct *device,
 
1424
               XEvent           *e,
 
1425
               char             event_atype,
 
1426
               char             *script,
 
1427
               Tcl_DString      *exp_script)
 
1428
{
 
1429
    char                *scan;
 
1430
    char                num_buffer[NUM_SIZE];
 
1431
    int                 space_needed, cvt_flags;
 
1432
    unsigned long       number;
 
1433
    int                 length, i, x, y, width, height;
 
1434
    int                 k_b_v_p_flag = 0, k_b_flag = 0;
 
1435
    unsigned int        device_state = 0;
 
1436
    int                 axes_count = 0, *axis_data = NULL;
 
1437
  
 
1438
/*printf("Begin ExpandPercents\n");*/
 
1439
    if ((event_atype == KEY_EVENT) || (event_atype == BUTTON_EVENT)) 
 
1440
    {
 
1441
        k_b_flag = k_b_v_p_flag = 1;
 
1442
        device_state = ((XDeviceKeyEvent *) e)->device_state;
 
1443
        axes_count = ((XDeviceKeyEvent *) e)->axes_count;
 
1444
        axis_data = ((XDeviceKeyEvent *) e)->axis_data;
 
1445
    }
 
1446
    else if (event_atype == MOTION_EVENT) 
 
1447
    {
 
1448
        k_b_v_p_flag = 1;
 
1449
        device_state = ((XDeviceMotionEvent *) e)->device_state;
 
1450
        axes_count = ((XDeviceMotionEvent *) e)->axes_count;
 
1451
        axis_data = ((XDeviceMotionEvent *) e)->axis_data;
 
1452
    }
 
1453
    else if (event_atype == PROXIMITY_EVENT) 
 
1454
    {
 
1455
        k_b_v_p_flag = 1;
 
1456
        device_state = ((XProximityNotifyEvent *) e)->device_state;
 
1457
        axes_count = ((XProximityNotifyEvent *) e)->axes_count;
 
1458
        axis_data = ((XProximityNotifyEvent *) e)->axis_data;
 
1459
    }
 
1460
 
 
1461
    while (1) 
 
1462
    {
 
1463
        /*
 
1464
         * Find everything up to the next % character and append it
 
1465
         * to the result string.
 
1466
         */
 
1467
        for (scan = script; (*scan != 0) && (*scan != '%'); scan++) 
 
1468
        {
 
1469
            /* Empty loop body. */
 
1470
        }
 
1471
        if (scan != script) 
 
1472
        {
 
1473
            Tcl_DStringAppend(exp_script, script, scan-script);
 
1474
            script = scan;
 
1475
        }
 
1476
        if (*script == 0) 
 
1477
        {
 
1478
            break;
 
1479
        }
 
1480
        /*
 
1481
         * Script is on a percent sequence. Process it.
 
1482
         */
 
1483
        number = 0;
 
1484
        scan = "??";
 
1485
        switch (script[1]) 
 
1486
        {
 
1487
            case '#':
 
1488
                number = e->xany.serial;
 
1489
                goto do_unsigned_number;
 
1490
            case '0': 
 
1491
            case '1': 
 
1492
            case '2': 
 
1493
            case '3': 
 
1494
            case '4':
 
1495
            case '5': 
 
1496
            case '6':
 
1497
            case '7':
 
1498
            case '8':
 
1499
            case '9':
 
1500
                if (k_b_v_p_flag) 
 
1501
                {
 
1502
                    int index = script[1]-'0';
 
1503
 
 
1504
                    if (index < axes_count) 
 
1505
                    {
 
1506
                        if (axes_count > 6) 
 
1507
                        {
 
1508
                            number = device->valuator_cache[index];
 
1509
                        }
 
1510
                        else 
 
1511
                        {
 
1512
                            number = axis_data[index];
 
1513
                        }
 
1514
                    }
 
1515
                }
 
1516
                goto do_number;
 
1517
            case  '*':
 
1518
                if (event_atype == MOTION_EVENT) 
 
1519
                {
 
1520
                    DeviceInfoStruct    *devices = device->dpy_info->devices;
 
1521
                    int                 num_devices = device->dpy_info->num_dev;
 
1522
        
 
1523
                    /*
 
1524
                     * Go through all known devices and look for a device
 
1525
                     * id equal to the valuator value. If not found return
 
1526
                     * the valuator value as an integer.
 
1527
                     */
 
1528
                    for (i = 0; i < num_devices; i++) 
 
1529
                    {
 
1530
                        if (devices[i].id == axis_data[0]) 
 
1531
                        {
 
1532
                            scan = (char *)devices[i].name;
 
1533
                            goto do_string;
 
1534
                        }
 
1535
                    }
 
1536
                    number = axis_data[0];
 
1537
                }
 
1538
                goto do_number;
 
1539
            case 'b':
 
1540
                if (event_atype == BUTTON_EVENT) 
 
1541
                {
 
1542
                    number = ((XDeviceButtonEvent *) e)->button;
 
1543
                }
 
1544
                goto do_unsigned_number;
 
1545
            case 'h':
 
1546
                if (event_atype == MOTION_EVENT) 
 
1547
                {
 
1548
                    number = ((XDeviceMotionEvent *) e)->is_hint;
 
1549
                }
 
1550
                goto do_unsigned_number;
 
1551
            case 'k':
 
1552
                if (event_atype == KEY_EVENT) 
 
1553
                {
 
1554
                    number = ((XDeviceKeyEvent *) e)->keycode;
 
1555
                }
 
1556
                goto do_unsigned_number;
 
1557
            case 's':
 
1558
                if (k_b_v_p_flag) 
 
1559
                {
 
1560
                    number = ((XDeviceButtonEvent *) e)->state;
 
1561
                }
 
1562
                goto do_unsigned_number;
 
1563
            case 't':
 
1564
                if (k_b_v_p_flag) 
 
1565
                {
 
1566
                    number = ((XDeviceButtonEvent *) e)->time;
 
1567
                }
 
1568
                else if (event_atype == FOCUS_EVENT) 
 
1569
                {
 
1570
                    number = ((XDeviceFocusChangeEvent *) e)->time;
 
1571
                }
 
1572
                else 
 
1573
                {
 
1574
                    /* The other 3 event types: 
 
1575
                     * Mapping, State & Change are compatible. 
 
1576
                     */
 
1577
                    number = ((XChangeDeviceNotifyEvent *) e)->time;
 
1578
                }
 
1579
                goto do_unsigned_number;
 
1580
            case 'x':
 
1581
                if (k_b_v_p_flag) 
 
1582
                {
 
1583
                    number = ((XDeviceButtonEvent *) e)->x;
 
1584
                }
 
1585
                goto do_unsigned_number;
 
1586
            case 'y':
 
1587
                if (k_b_v_p_flag) 
 
1588
                {
 
1589
                    number = ((XDeviceButtonEvent *) e)->y;
 
1590
                }
 
1591
                goto do_unsigned_number;
 
1592
            case 'C':
 
1593
                if (event_atype == CHANGE_DEVICE_EVENT) 
 
1594
                {
 
1595
                    XChangeDeviceNotifyEvent *cdne = (XChangeDeviceNotifyEvent *) e;
 
1596
                    if (cdne->request == NewKeyboard) 
 
1597
                    {
 
1598
                        scan = "NewKeyboard";
 
1599
                    }
 
1600
                    else if (cdne->request == NewPointer) 
 
1601
                    {
 
1602
                        scan = "NewPointer";
 
1603
                    }
 
1604
                }
 
1605
                goto do_string;
 
1606
            case 'D':
 
1607
                scan = (char *)device->name;
 
1608
                goto do_string;
 
1609
            case 'E':
 
1610
                number = e->xany.send_event;
 
1611
                goto do_unsigned_number;
 
1612
            case 'S':
 
1613
                if (k_b_v_p_flag) 
 
1614
                {
 
1615
                    number = device_state;
 
1616
                }
 
1617
                goto do_unsigned_number;
 
1618
            case 'T':
 
1619
                for (i = 0; i < NUM_XI_EVENTS; i++) 
 
1620
                {
 
1621
                    if (device->dpy_info->event_types[i] == e->type) 
 
1622
                    {
 
1623
                        scan = (char *)xi_event_names[i];
 
1624
                        break;
 
1625
                    }
 
1626
                }
 
1627
                goto do_string;
 
1628
            case 'W':
 
1629
                if (tkwin != NULL) 
 
1630
                {
 
1631
                    scan = Tk_PathName(tkwin);
 
1632
                }
 
1633
                goto do_string;
 
1634
            case 'X':
 
1635
                if (k_b_v_p_flag) 
 
1636
                {
 
1637
                    number = ((XDeviceButtonEvent *) e)->x_root;
 
1638
                    if (tkwin != NULL)
 
1639
                    {
 
1640
                        Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
 
1641
                        number -= x;
 
1642
                    }
 
1643
                }
 
1644
                goto do_unsigned_number;
 
1645
            case 'Y':
 
1646
                if (k_b_v_p_flag) 
 
1647
                {
 
1648
                    number = ((XDeviceButtonEvent *) e)->y_root;
 
1649
                    if (tkwin != NULL) 
 
1650
                    {
 
1651
                        Tk_GetVRootGeometry(tkwin, &x, &y, &width, &height);
 
1652
                        number -= y;
 
1653
                    }
 
1654
                }
 
1655
                goto do_unsigned_number;
 
1656
            default:
 
1657
                num_buffer[0] = script[1];
 
1658
                num_buffer[1] = '\0';
 
1659
                scan = num_buffer;
 
1660
                goto do_string; 
 
1661
        }
 
1662
 
 
1663
        do_unsigned_number:
 
1664
            sprintf(num_buffer, "%lu", number);
 
1665
            scan = num_buffer;
 
1666
            goto do_string;
 
1667
    
 
1668
        do_number:
 
1669
            sprintf(num_buffer, "%ld", number);
 
1670
            scan = num_buffer;
 
1671
    
 
1672
        do_string:
 
1673
            space_needed = Tcl_ScanElement(scan, &cvt_flags);
 
1674
            length = Tcl_DStringLength(exp_script);
 
1675
            Tcl_DStringSetLength(exp_script, length + space_needed);
 
1676
            space_needed = Tcl_ConvertElement(scan,
 
1677
                        Tcl_DStringValue(exp_script) + length,
 
1678
                        cvt_flags | TCL_DONT_USE_BRACES);
 
1679
            Tcl_DStringSetLength(exp_script, length + space_needed);
 
1680
            script += 2;
 
1681
    }
 
1682
/*printf("End ExpandPercents\n");*/
 
1683
}
 
1684
 
 
1685
/*
 
1686
 *----------------------------------------------------------------------
 
1687
 *
 
1688
 * InvokeEventScript --
 
1689
 *      Invoke a script that has been registered for an event form an
 
1690
 *      input device. Any % occuring in the script will be replaced by
 
1691
 *      a string depending on the characters following the percent.
 
1692
 *      The recognized % sequences are:
 
1693
 *
 
1694
 *              %#      The number of the last request processed by the
 
1695
 *                      server.
 
1696
 *              %0-9    The value of valuator n (0-9).
 
1697
 *              %*      The name of the device (as encoded in a valuator
 
1698
 *                      by the switch virtual device).
 
1699
 *              %b      The button number for events related to buttons.
 
1700
 *              %h      The motion hint field from the event.
 
1701
 *              %k      The keycode for events related to keys.
 
1702
 *              %s      The state field from the event (the core that is).
 
1703
 *              %t      The time field from the event.
 
1704
 *              %x      The x coord of the core pointer.
 
1705
 *              %y      The y coord of the core pointer.
 
1706
 *              %C      The name of the core device that changed (only
 
1707
 *                      for DeviceChange events).
 
1708
 *              %D      The device name that has emitted the event.
 
1709
 *              %E      The send_event field from the event.
 
1710
 *              %S      The device state field from the event.
 
1711
 *              %T      The type field from the event, as an event name.
 
1712
 *              %W      The window receiving the event.
 
1713
 *              %X      The root window x coord of the core pointer.
 
1714
 *              %Y      The root window y coord of the core pointer.
 
1715
 *
 
1716
 *      An unrecognized sequence is replaced by the sequence with
 
1717
 *      the leading percent removed.
 
1718
 *
 
1719
 *----------------------------------------------------------------------
 
1720
 */
 
1721
static void
 
1722
InvokeEventScript(ClientData    client_data,
 
1723
                  XEvent        *e)
 
1724
{
 
1725
    EventScriptRecord   *escripts = (EventScriptRecord *) client_data;
 
1726
    DeviceInfoStruct    *device;
 
1727
    Tcl_Interp          *interp = escripts->interp;
 
1728
    int                 result;
 
1729
    char                event_atype;
 
1730
    Tcl_DString         exp_script;
 
1731
    int                 i, try_to_merge = 0;
 
1732
    int                 first_axis = 0, axes_count = 0;
 
1733
    int                 *axis_data = NULL;
 
1734
  
 
1735
    device = LookupDeviceById(((XDeviceKeyEvent *) e)->display,
 
1736
                            ((XDeviceKeyEvent *) e)->deviceid);
 
1737
    event_atype = device->dpy_info->event_atypes[e->type];
 
1738
    /*
 
1739
     * If the event is a key, button, motion or proximity event,
 
1740
     * try to merge events emitted to report more than 6 valuators.
 
1741
     * It is assumed that an event train can't be mixed with another
 
1742
     * from the same device.
 
1743
     */
 
1744
    if ((event_atype == BUTTON_EVENT) || (event_atype == KEY_EVENT)) 
 
1745
    {
 
1746
        first_axis = ((XDeviceKeyEvent *) e)->first_axis;
 
1747
        axes_count = ((XDeviceKeyEvent *) e)->axes_count;
 
1748
        axis_data = ((XDeviceKeyEvent *) e)->axis_data;
 
1749
        try_to_merge = 1;
 
1750
    }
 
1751
    else if (event_atype == MOTION_EVENT) 
 
1752
    {
 
1753
        first_axis = ((XDeviceMotionEvent *) e)->first_axis;
 
1754
        axes_count = ((XDeviceMotionEvent *) e)->axes_count;
 
1755
        axis_data = ((XDeviceMotionEvent *) e)->axis_data;
 
1756
        try_to_merge = 1;
 
1757
    }
 
1758
    else if (event_atype == PROXIMITY_EVENT) 
 
1759
    {
 
1760
        first_axis = ((XProximityNotifyEvent *) e)->first_axis;
 
1761
        axes_count = ((XProximityNotifyEvent *) e)->axes_count;
 
1762
        axis_data = ((XProximityNotifyEvent *) e)->axis_data;
 
1763
        try_to_merge = 1;
 
1764
    }
 
1765
  
 
1766
    if (try_to_merge) 
 
1767
    {
 
1768
        if (axes_count > 6) 
 
1769
        {
 
1770
            /*
 
1771
             * Cache the axes reported in this event.
 
1772
             */
 
1773
            for (i = first_axis; i < axes_count; i++) 
 
1774
            {
 
1775
                device->valuator_cache[i] = axis_data[i-first_axis];
 
1776
            }
 
1777
            /*
 
1778
             * If this isn't the last event, wait for the others.
 
1779
             */
 
1780
            if (axes_count > (first_axis+6)) return;
 
1781
        }
 
1782
    }
 
1783
  
 
1784
    Tcl_Preserve((ClientData) interp);
 
1785
    Tcl_DStringInit(&exp_script);
 
1786
    ExpandPercents(escripts->tkwin, device, e, event_atype,
 
1787
                 escripts->script, &exp_script);
 
1788
    /*
 
1789
     * Get the content of the escript before triggering
 
1790
     * the script. It may destroy the binding before returning
 
1791
     * and we might still need the info in case of error.
 
1792
     */
 
1793
    result = Tcl_GlobalEval(interp, Tcl_DStringValue(&exp_script));
 
1794
    Tcl_DStringFree(&exp_script);
 
1795
    if (result != TCL_OK) 
 
1796
    {
 
1797
        Tcl_BackgroundError(interp);
 
1798
    }
 
1799
    Tcl_Release((ClientData) interp);
 
1800
/*printf("End InvokeEventScript\n");*/
 
1801
}
 
1802
 
 
1803
/*
 
1804
 *----------------------------------------------------------------------
 
1805
 *
 
1806
 * AddEventScript --
 
1807
 *      Register a script to be invoked when an event is received in a
 
1808
 *      window from a device. The server is asked to report the event
 
1809
 *      on the window.
 
1810
 *
 
1811
 *      If it is not possible to bind the event the function return
 
1812
 *      0 else it returns 1.
 
1813
 *
 
1814
 *----------------------------------------------------------------------
 
1815
 */
 
1816
static int
 
1817
AddEventScript(Tcl_Interp       *interp,
 
1818
               Tk_Window        tkwin,
 
1819
               DeviceInfoStruct *device,
 
1820
               Tk_Uid           event_spec,
 
1821
               char             *script)
 
1822
{
 
1823
    WindowInfoStruct  *pw = GetWindowInfo(tkwin, 1);
 
1824
    EventScriptRecord *escripts = NULL;
 
1825
 
 
1826
/*printf("Begin of AddEventScript\n");*/
 
1827
  
 
1828
    /*
 
1829
     * Try to see if a script is already registered with the
 
1830
     * same combination of device, event and interp.
 
1831
     */
 
1832
    for (escripts = pw->scripts; escripts != NULL; escripts = escripts->next) 
 
1833
    {
 
1834
        if ((escripts->device == device) &&
 
1835
                (escripts->event_spec == event_spec) &&
 
1836
                (escripts->interp == interp)) 
 
1837
        {
 
1838
            ckfree(escripts->script);
 
1839
            escripts->script = NULL;
 
1840
            break;
 
1841
        }
 
1842
    }
 
1843
    /*
 
1844
     * The event/device combo has no script already registered. Create
 
1845
     * a new record and register with the server. The InvokeEventScript
 
1846
     * function will be called with the script record as parameter when
 
1847
     * an event of this type/device will be received on the window.
 
1848
     */
 
1849
    if (escripts == NULL) 
 
1850
    {
 
1851
        escripts = (EventScriptRecord *) ckalloc(sizeof(EventScriptRecord));
 
1852
        escripts->device = device;
 
1853
        escripts->tkwin = tkwin;
 
1854
        escripts->event_spec = event_spec;
 
1855
        escripts->interp = interp;
 
1856
        if (!Tk_CreateXiEventHandler(tkwin, event_spec, device->name,
 
1857
                        InvokeEventScript, (ClientData) escripts)) 
 
1858
        {
 
1859
            ckfree((char *) escripts);
 
1860
            return 0;
 
1861
        }
 
1862
        escripts->next = pw->scripts;
 
1863
        pw->scripts = escripts;
 
1864
    }
 
1865
    /*
 
1866
     * Setup the script in the record.
 
1867
     */
 
1868
    escripts->script = ckalloc(strlen(script) + 1);
 
1869
    strcpy(escripts->script, script);
 
1870
 
 
1871
    return 1;
 
1872
}
 
1873
 
 
1874
/*
 
1875
 *----------------------------------------------------------------------
 
1876
 *
 
1877
 * WacomxiBindEventCmd --
 
1878
 *      Implements the 'bindevent' tcl command.
 
1879
 *
 
1880
 *----------------------------------------------------------------------
 
1881
 */
 
1882
static int
 
1883
WacomxiBindEventCmd(ClientData  clientData,
 
1884
               Tcl_Interp       *interp,
 
1885
               int              argc,
 
1886
               char             **argv)
 
1887
{
 
1888
    Tk_Window           mainwin = (Tk_Window) clientData;
 
1889
    Tk_Window           tkwin;
 
1890
    DeviceInfoStruct    *device;
 
1891
    int                 len;
 
1892
    Tk_Uid              event_spec;
 
1893
  
 
1894
    if ((argc != 4) && (argc != 5)) 
 
1895
    {
 
1896
        Tcl_AppendResult(interp, "wrong # of arguments, should be \"",
 
1897
                     argv[0], "win device event ?script?\"", (char *) NULL);
 
1898
        return TCL_ERROR;
 
1899
    }
 
1900
    tkwin = Tk_NameToWindow(interp, argv[1], mainwin);
 
1901
 
 
1902
    if ( !tkwin ) return TCL_ERROR;
 
1903
 
 
1904
    device = GetDeviceInfo(tkwin, Tk_GetUid(argv[2]));
 
1905
    if (!device) 
 
1906
    {
 
1907
        Tcl_AppendResult(interp, "unknown device \"", argv[2],
 
1908
                     "\" or it is currently a core device", (char *) NULL);
 
1909
        return TCL_ERROR;    
 
1910
    }
 
1911
 
 
1912
    len = strlen(argv[3]);
 
1913
    if ((argv[3][0] != '<') || (argv[3][len-1] != '>')) 
 
1914
    {
 
1915
        Tcl_AppendResult(interp,
 
1916
                     "invalid event specification, should perhaps be <",
 
1917
                     argv[3], ">", (char *) NULL);
 
1918
        return TCL_ERROR;
 
1919
    }
 
1920
    argv[3][len-1] = 0;
 
1921
    event_spec = Tk_GetUid(&argv[3][1]);
 
1922
    argv[3][len-1] = '>';
 
1923
  
 
1924
    /*
 
1925
     * Asked to return the script associated with the widget/event.
 
1926
     * Lookup the scripts associated with window and in this list
 
1927
     * the script associated with the given event.
 
1928
     */
 
1929
    if (argc == 4) 
 
1930
    {
 
1931
        WindowInfoStruct  *pw = GetWindowInfo(tkwin, 1);
 
1932
        EventScriptRecord *escripts;
 
1933
    
 
1934
        for (escripts = pw->scripts; escripts != NULL; escripts = escripts->next) 
 
1935
        {
 
1936
            if ((escripts->device == device) &&
 
1937
                        (escripts->event_spec == event_spec) &&
 
1938
                        (escripts->interp == interp)) 
 
1939
            {
 
1940
                Tcl_SetResult(interp, (char *)escripts->script, TCL_STATIC);
 
1941
                break;
 
1942
            }
 
1943
        }
 
1944
        return TCL_OK;
 
1945
    }
 
1946
    /*
 
1947
     * The script is the empty string, remove the event binding.
 
1948
     */
 
1949
    if (!argv[4][0]) 
 
1950
    {
 
1951
        RemoveEventScript(interp, tkwin, device, event_spec);
 
1952
        return TCL_OK;
 
1953
    }
 
1954
    /*
 
1955
     * Add or override the event binding if the event can be
 
1956
     * reported by the device. Else report an error.
 
1957
     */
 
1958
    if (!AddEventScript(interp, tkwin, device, event_spec, argv[4])) 
 
1959
    {
 
1960
        Tcl_AppendResult(interp, "Event \"", argv[3],
 
1961
                     "\" can't be reported by device \"", argv[2],
 
1962
                     "\"", (char *) NULL);
 
1963
        return TCL_ERROR;
 
1964
    }
 
1965
/*printf("Added event %s \n", argv[3] );*/
 
1966
  
 
1967
    return TCL_OK;
 
1968
}
 
1969
 
 
1970
 
 
1971
int
 
1972
Libwacomxi_Init(Tcl_Interp      *interp)
 
1973
{
 
1974
    static int  setup_done = 0;
 
1975
    int         i;
 
1976
  
 
1977
    if (!Tk_MainWindow(interp)) {
 
1978
        Tcl_AppendResult(interp, 
 
1979
                        "... Xinput package need Tk to run.",
 
1980
                        (char *) NULL);
 
1981
        return TCL_ERROR;
 
1982
    }
 
1983
 
 
1984
    if (!setup_done) {
 
1985
        setup_done = 1;
 
1986
        Tk_CreateGenericHandler(WacomxiGenericEventHandler, NULL);
 
1987
    }
 
1988
 
 
1989
    Tcl_CreateCommand(interp, 
 
1990
                        "wacomxi::bindevent", 
 
1991
                        (Tcl_CmdProc *)WacomxiBindEventCmd,
 
1992
                        (ClientData) Tk_MainWindow(interp),
 
1993
                        (Tcl_CmdDeleteProc *) NULL); 
 
1994
 
 
1995
    /*
 
1996
     * Convert events names into uids for speed and ease of use.
 
1997
     */
 
1998
    for (i = 0; i < NUM_XI_EVENTS; i++) 
 
1999
    {
 
2000
        xi_event_names[i] = Tk_GetUid(xi_event_names[i]);
 
2001
    }
 
2002
 
 
2003
    return Tcl_PkgProvide(interp, "LIBWACOMXI", "1.0");
 
2004
}