~fginther/geis/geis-2.2.9.1-precise

« back to all changes in this revision

Viewing changes to libutouch-geis/backend/xcb/geis_xcb_backend.c

  • Committer: Francis Ginther
  • Date: 2012-08-16 13:43:15 UTC
  • mfrom: (49.1.37)
  • Revision ID: francis.ginther@canonical.com-20120816134315-ex9m75nqcv0uryim
* New upstream release.
  - fixes pinch radius and drag delta calculations (lp: #985916)
    (lp: #986215)
  - changes type of geisSubscriptionFlags (lp: #813819)
  - changes direct devices to use window coordinates (lp: #984069)
  - reports device axis extents, if available (lp: #987539)
  - removes XCB back end
  - removes overlapping events when a gesture is accepted (lp: #1001365)
  - avoids trying to start a DBus session if there is none already
    (lp: #997630)
  - detect added devices properly (LP: #1009270)
  - fix crash when accepting a gesture (LP: #1015775)
  - fix result value of geis_subscription_deactivate() (LP: #1021448)
  - upstream project renamed to just 'geis'

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 * @file xcb/geis_xcb_backend.c
3
 
 * @brief Implements the GEIS XCB back end.
4
 
 *
5
 
 * Copyright 2011 Canonical Ltd.
6
 
 *
7
 
 * This library is free software; you can redistribute it and/or modify it under
8
 
 * the terms of the GNU Lesser General Public License as published by the Free
9
 
 * Software Foundation; either version 3 of the License, or (at your option) any
10
 
 * later version.
11
 
 *
12
 
 * This library is distributed in the hope that it will be useful, but WITHOUT
13
 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
 
 * FOR A PARTICULAR PURPOSE.     See the GNU Lesser General Public License for
15
 
 * more details.
16
 
 *
17
 
 * You should have received a copy of the GNU General Public License
18
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 
 */
20
 
#include "geis_config.h"
21
 
#include "geis_xcb_backend.h"
22
 
 
23
 
#include <dlfcn.h>
24
 
#include "geis_attr.h"
25
 
#include "geis_backend_protected.h"
26
 
#include "geis_class.h"
27
 
#include "geis_device.h"
28
 
#include "geis_event.h"
29
 
#include "geis_frame.h"
30
 
#include "geis_filter.h"
31
 
#include "geis_group.h"
32
 
#include "geis_logging.h"
33
 
#include "geis_private.h"
34
 
#include "geis_region.h"
35
 
#include "geis_touch.h"
36
 
#include "geis_xcb_backend_sub_table.h"
37
 
#include "geis_xcb_backend_token.h"
38
 
#include "grail_gestures.h"
39
 
#include <grail.h>
40
 
#include <grail-types.h>
41
 
#include <stdio.h>
42
 
#include <string.h>
43
 
#include "xcb_gesture.h"
44
 
#include <X11/extensions/XI2proto.h>
45
 
#include <X11/extensions/XInput2.h>
46
 
#include <X11/X.h>
47
 
#include <X11/Xlib-xcb.h>
48
 
#include <xcb/xcb.h>
49
 
#ifdef HAVE_XI_2_1
50
 
# include <xorg/xserver-properties.h>
51
 
#endif
52
 
 
53
 
#define MIN_TOUCHES 1
54
 
#define MAX_TOUCHES 5
55
 
#define MAX_NUM_DEVICES 10
56
 
#define MAX_NUM_WINDOWS 10
57
 
 
58
 
#define GRAIL_XCB_BITMASK_LEN 2
59
 
 
60
 
 
61
 
static inline GeisSize
62
 
_min(GeisSize a, GeisSize b)
63
 
{
64
 
  return (a < b) ? a : b;
65
 
}
66
 
 
67
 
 
68
 
static inline GeisSize
69
 
_max(GeisSize a, GeisSize b)
70
 
{
71
 
  return (a > b) ? a : b;
72
 
}
73
 
 
74
 
 
75
 
struct GeisXcbBackend
76
 
{
77
 
  Geis                    geis;
78
 
  Display                *x11_display;
79
 
  xcb_connection_t       *xcb_connection;
80
 
  int                     xcb_fd;
81
 
  int                     grail_is_old_version;
82
 
  GeisXcbBackendSubTable  sub_table;
83
 
  int                     xi_opcode;
84
 
};
85
 
 
86
 
 
87
 
/*
88
 
 * Information required for each xcb-gesture subscription.
89
 
 *
90
 
 * @todo: unhardcode sizes and lengths (and malloc them instead).
91
 
 */
92
 
typedef struct _XcbGestureSub
93
 
{
94
 
  int           num_device_filters;
95
 
  uint16_t      devices[MAX_NUM_DEVICES]; 
96
 
  uint16_t      device_count;
97
 
  int           num_class_filters;
98
 
  uint32_t      mask[GRAIL_XCB_BITMASK_LEN];
99
 
  uint32_t      mask_len;
100
 
  int           num_region_filters;
101
 
  xcb_window_t  windows[MAX_NUM_WINDOWS];
102
 
  int           window_count;
103
 
} *XcbGestureSub;
104
 
 
105
 
static void _construct(void *mem, Geis geis);
106
 
static void _finalize(GeisBackend g);
107
 
static GeisBackendToken _create_token(GeisBackend be, GeisBackendTokenInitState);
108
 
static GeisStatus _gxcb_accept_gesture(GeisBackend, GeisGroup, GeisGestureId);
109
 
static GeisStatus _gxcb_reject_gesture(GeisBackend, GeisGroup, GeisGestureId);
110
 
static void _fd_callback(int fd, GeisBackendMultiplexorActivity ev, void *ctx);
111
 
 
112
 
 
113
 
static struct GeisBackendVtable be_vtbl = {
114
 
  _construct,
115
 
  _finalize,
116
 
  _create_token,
117
 
  _gxcb_accept_gesture,
118
 
  _gxcb_reject_gesture
119
 
};
120
 
 
121
 
 
122
 
/* A handy little table to map grail types to geis gesture classes. */
123
 
static struct GrailTypeToGeisClass
124
 
{
125
 
  GeisInteger      grail_type;
126
 
  GeisGestureClass geis_class;
127
 
} s_grail_type_map[] = {
128
 
  { GRAIL_TYPE_DRAG1, NULL },
129
 
  { GRAIL_TYPE_PINCH1, NULL },
130
 
  { GRAIL_TYPE_ROTATE1, NULL },
131
 
  { GRAIL_TYPE_DRAG2, NULL },
132
 
  { GRAIL_TYPE_PINCH2, NULL },
133
 
  { GRAIL_TYPE_ROTATE2, NULL },
134
 
  { GRAIL_TYPE_DRAG3, NULL },
135
 
  { GRAIL_TYPE_PINCH3, NULL },
136
 
  { GRAIL_TYPE_ROTATE3, NULL },
137
 
  { GRAIL_TYPE_DRAG4, NULL },
138
 
  { GRAIL_TYPE_PINCH4, NULL },
139
 
  { GRAIL_TYPE_ROTATE4, NULL },
140
 
  { GRAIL_TYPE_DRAG5, NULL },
141
 
  { GRAIL_TYPE_PINCH5, NULL },
142
 
  { GRAIL_TYPE_ROTATE5, NULL },
143
 
  { GRAIL_TYPE_TAP1, NULL },
144
 
  { GRAIL_TYPE_TAP2, NULL },
145
 
  { GRAIL_TYPE_TAP3, NULL },
146
 
  { GRAIL_TYPE_TAP4, NULL },
147
 
  { GRAIL_TYPE_TAP5, NULL },
148
 
  { GRAIL_TYPE_EDRAG, NULL },
149
 
  { GRAIL_TYPE_EPINCH, NULL },
150
 
  { GRAIL_TYPE_EROTATE, NULL },
151
 
  { GRAIL_TYPE_MDRAG, NULL },
152
 
  { GRAIL_TYPE_MPINCH, NULL },
153
 
  { GRAIL_TYPE_MROTATE, NULL },
154
 
  { GRAIL_TYPE_TOUCH1, NULL },
155
 
  { GRAIL_TYPE_TOUCH2, NULL },
156
 
  { GRAIL_TYPE_TOUCH3, NULL },
157
 
  { GRAIL_TYPE_TOUCH4, NULL },
158
 
  { GRAIL_TYPE_TOUCH5, NULL },
159
 
  { GRAIL_TYPE_ETOUCH, NULL },
160
 
  { GRAIL_TYPE_MTOUCH, NULL }
161
 
};
162
 
 
163
 
static GeisSize s_grail_type_map_size = sizeof(s_grail_type_map)
164
 
                                      / sizeof(struct GrailTypeToGeisClass);
165
 
 
166
 
static void
167
 
_set_grail_type_class(GeisInteger grail_type, GeisGestureClass geis_class)
168
 
{
169
 
  GeisSize i;
170
 
  for (i = 0; i < s_grail_type_map_size; ++i)
171
 
  {
172
 
    if (s_grail_type_map[i].grail_type == grail_type)
173
 
    { 
174
 
      s_grail_type_map[i].geis_class = geis_class;
175
 
      break;
176
 
    }
177
 
  }
178
 
}
179
 
 
180
 
 
181
 
static GeisGestureClass
182
 
_get_geis_class_from_grail_type(GeisInteger grail_type)
183
 
{
184
 
  GeisSize i;
185
 
  for (i = 0; i < s_grail_type_map_size; ++i)
186
 
  {
187
 
    if (s_grail_type_map[i].grail_type == grail_type)
188
 
    { 
189
 
      return s_grail_type_map[i].geis_class;
190
 
    }
191
 
  }
192
 
  return NULL;
193
 
}
194
 
 
195
 
 
196
 
/*
197
 
 * Makes an attempt to determine the local version of grail.  Pretty useless if
198
 
 * X is remote.
199
 
 */
200
 
static int
201
 
_grail_is_old_version(void)
202
 
{
203
 
  int (*fn)(void);
204
 
  int is_old_version = 1;
205
 
  void* lib = dlopen("libutouch-grail.so.1", RTLD_LAZY | RTLD_LOCAL);
206
 
  if (!lib)
207
 
  {
208
 
    geis_error("can not open libutouch-grail.so.1: %s", dlerror());
209
 
    goto final_exit;
210
 
  }
211
 
 
212
 
  *(void **)(&fn) = dlsym(lib, "grail_get_version");
213
 
  if (fn)
214
 
  {
215
 
    /* Check against magic in a particular version of grail.h */
216
 
    is_old_version = fn() < 0x00011000;
217
 
  }
218
 
 
219
 
  dlclose(lib);
220
 
final_exit:
221
 
  return is_old_version;
222
 
}
223
 
 
224
 
 
225
 
static void
226
 
_report_init_complete(GeisXcbBackend be)
227
 
{
228
 
  geis_post_event(be->geis, geis_event_new(GEIS_EVENT_INIT_COMPLETE));
229
 
}
230
 
 
231
 
 
232
 
#ifdef HAVE_XI_2_1
233
 
static void
234
 
_map_xi2_mode_to_geis_device_attrs(int xi2_mode, GeisDevice geis_device)
235
 
{
236
 
  GeisAttr device_attr;
237
 
  GeisBoolean is_direct = GEIS_FALSE;
238
 
  GeisBoolean is_independent = GEIS_FALSE;
239
 
 
240
 
  if (xi2_mode == XIDirectTouch)
241
 
    is_direct = GEIS_TRUE;
242
 
 
243
 
  device_attr = geis_attr_new(GEIS_DEVICE_ATTRIBUTE_DIRECT_TOUCH,
244
 
                              GEIS_ATTR_TYPE_BOOLEAN,
245
 
                              &is_direct);
246
 
  if (!device_attr)
247
 
  {
248
 
    geis_error("failed to create device attr");
249
 
  }
250
 
  else
251
 
  {
252
 
    geis_device_add_attr(geis_device, device_attr);
253
 
  }
254
 
 
255
 
  if (xi2_mode == XIIndependentPointer)
256
 
    is_independent = GEIS_TRUE;
257
 
 
258
 
  device_attr = geis_attr_new(GEIS_DEVICE_ATTRIBUTE_INDEPENDENT_TOUCH,
259
 
                              GEIS_ATTR_TYPE_BOOLEAN,
260
 
                              &is_independent);
261
 
  if (!device_attr)
262
 
  {
263
 
    geis_error("failed to create device attr");
264
 
  }
265
 
  else
266
 
  {
267
 
    geis_device_add_attr(geis_device, device_attr);
268
 
  }
269
 
}
270
 
#endif
271
 
 
272
 
 
273
 
static GeisBoolean
274
 
_verify_xcb_version(xcb_connection_t *xcb_connection)
275
 
{
276
 
  GeisBoolean                         is_valid_version = GEIS_FALSE;
277
 
  xcb_gesture_query_version_cookie_t  version_cookie;
278
 
  xcb_gesture_query_version_reply_t  *version_reply = NULL;
279
 
  xcb_generic_error_t                *error = NULL;
280
 
 
281
 
  version_cookie = xcb_gesture_query_version(xcb_connection,
282
 
                                             XCB_GESTURE_MAJOR_VERSION,
283
 
                                             XCB_GESTURE_MINOR_VERSION);
284
 
  version_reply = xcb_gesture_query_version_reply(xcb_connection,
285
 
                                                  version_cookie,
286
 
                                                  &error);
287
 
  if (!version_reply)
288
 
  {
289
 
    geis_error("failed to receive XCB gesture version reply.");
290
 
    goto final_exit;
291
 
  }
292
 
 
293
 
  if (version_reply->major_version != XCB_GESTURE_MAJOR_VERSION
294
 
   && version_reply->minor_version != XCB_GESTURE_MINOR_VERSION)
295
 
  {
296
 
    geis_error("server supports unrecognized version: %d.%d",
297
 
               version_reply->major_version, version_reply->minor_version);
298
 
  }
299
 
  else
300
 
  {
301
 
    is_valid_version = GEIS_TRUE;
302
 
  }
303
 
 
304
 
 free(version_reply);
305
 
final_exit:
306
 
 return is_valid_version;
307
 
}
308
 
 
309
 
 
310
 
#ifdef HAVE_XI_2_1
311
 
static void
312
 
_report_xi2_valuator_attrs(GeisDevice geis_device,
313
 
                           XITouchValuatorClassInfo *v,
314
 
                           GeisString min_label,
315
 
                           GeisString max_label,
316
 
                           GeisString res_label)
317
 
{
318
 
  GeisFloat f;
319
 
  GeisAttr device_attr;
320
 
 
321
 
  f = v->min;
322
 
  device_attr = geis_attr_new(min_label, GEIS_ATTR_TYPE_FLOAT, &f);
323
 
  if (!device_attr)
324
 
  {
325
 
    geis_error("failed to create device attr");
326
 
  }
327
 
  else
328
 
  {
329
 
    geis_device_add_attr(geis_device, device_attr);
330
 
  }
331
 
 
332
 
  f = v->max;
333
 
  device_attr = geis_attr_new(max_label, GEIS_ATTR_TYPE_FLOAT, &f);
334
 
  if (!device_attr)
335
 
  {
336
 
    geis_error("failed to create device attr");
337
 
  }
338
 
  else
339
 
  {
340
 
    geis_device_add_attr(geis_device, device_attr);
341
 
  }
342
 
 
343
 
  f = (GeisFloat)v->resolution;
344
 
  device_attr = geis_attr_new(res_label, GEIS_ATTR_TYPE_FLOAT, &f);
345
 
  if (!device_attr)
346
 
  {
347
 
    geis_error("failed to create device attr");
348
 
  }
349
 
  else
350
 
  {
351
 
    geis_device_add_attr(geis_device, device_attr);
352
 
  }
353
 
}
354
 
 
355
 
 
356
 
/*
357
 
 * Reports a new gesture-capable device.
358
 
 */
359
 
static void
360
 
_report_an_xcb_device(GeisXcbBackend be,  XIDeviceInfo *xcb_device)
361
 
{
362
 
  int        filter_attr_index = 0;
363
 
  GeisSize   filter_attr_count = 2;
364
 
  GeisFilterableAttribute filter_attrs = NULL;
365
 
  GeisDevice geis_device;
366
 
  GeisEvent  device_event;
367
 
  int        class_index;
368
 
 
369
 
  geis_device = geis_device_new(xcb_device->name, xcb_device->deviceid);
370
 
  if (!geis_device)
371
 
  {
372
 
    geis_error("failed to create device");
373
 
    goto final_exit;
374
 
  }
375
 
 
376
 
  /* Add attributes to the device. */
377
 
  for (class_index = 0; class_index < xcb_device->num_classes; ++class_index)
378
 
  {
379
 
    XIAnyClassInfo *any = xcb_device->classes[class_index];
380
 
    if (any->type == XITouchClass)
381
 
    {
382
 
      GeisAttr   device_attr;
383
 
      XITouchClassInfo *v = (XITouchClassInfo *)any;
384
 
      filter_attr_count += 3;
385
 
      _map_xi2_mode_to_geis_device_attrs(v->mode, geis_device);
386
 
      geis_debug("touch class for device %d \"%s\": mode %d num_touches %d",
387
 
                 xcb_device->deviceid, xcb_device->name,
388
 
                 v->mode, v->num_touches);
389
 
 
390
 
      device_attr = geis_attr_new(GEIS_DEVICE_ATTRIBUTE_TOUCHES,
391
 
                                  GEIS_ATTR_TYPE_INTEGER,
392
 
                                  &v->num_touches);
393
 
      if (!device_attr)
394
 
      {
395
 
        geis_error("failed to create device attr");
396
 
      }
397
 
      else
398
 
      {
399
 
        geis_device_add_attr(geis_device, device_attr);
400
 
      }
401
 
    }
402
 
    else if (any->type == XITouchValuatorClass)
403
 
    {
404
 
      XITouchValuatorClassInfo *v = (XITouchValuatorClassInfo *)any;
405
 
      char *label = v->label ? XGetAtomName(be->x11_display, v->label) : NULL;
406
 
      if (label && 0 == strcmp(label, AXIS_LABEL_PROP_ABS_MT_POSITION_X))
407
 
      {
408
 
        _report_xi2_valuator_attrs(geis_device,
409
 
                                   v,
410
 
                                   GEIS_DEVICE_ATTRIBUTE_MIN_X,
411
 
                                   GEIS_DEVICE_ATTRIBUTE_MAX_X,
412
 
                                   GEIS_DEVICE_ATTRIBUTE_RES_X);
413
 
      }
414
 
      else if (label && 0 == strcmp(label, AXIS_LABEL_PROP_ABS_MT_POSITION_Y))
415
 
      {
416
 
        _report_xi2_valuator_attrs(geis_device,
417
 
                                   v,
418
 
                                   GEIS_DEVICE_ATTRIBUTE_MIN_Y,
419
 
                                   GEIS_DEVICE_ATTRIBUTE_MAX_Y,
420
 
                                   GEIS_DEVICE_ATTRIBUTE_RES_Y);
421
 
      }
422
 
      else
423
 
      {
424
 
        char min_name[64];
425
 
        char max_name[64];
426
 
        char res_name[64];
427
 
        char *axis_name = label ? label : "";
428
 
        sprintf(min_name, "device %.48s %d minimum", axis_name, v->number);
429
 
        sprintf(max_name, "device %.48s %d maximum", axis_name, v->number);
430
 
        sprintf(res_name, "device %.48s %d resolution", axis_name, v->number);
431
 
        _report_xi2_valuator_attrs(geis_device, v, min_name, max_name, res_name);
432
 
      }
433
 
      if (label)
434
 
        XFree(label);
435
 
    }
436
 
  }
437
 
 
438
 
  /* Register the device for subscriptions. */
439
 
  filter_attrs = calloc(filter_attr_count, sizeof(struct GeisFilterableAttribute));
440
 
  if (!filter_attrs)
441
 
  {
442
 
    geis_debug("error allocating device attr table");
443
 
    goto unroll_device;
444
 
  }
445
 
 
446
 
  geis_filterable_attribute_init(&filter_attrs[filter_attr_index++],
447
 
                     GEIS_DEVICE_ATTRIBUTE_NAME, GEIS_ATTR_TYPE_STRING,
448
 
                     geis_xcb_token_add_device_term, geis_device);
449
 
  geis_filterable_attribute_init(&filter_attrs[filter_attr_index++],
450
 
                     GEIS_DEVICE_ATTRIBUTE_ID, GEIS_ATTR_TYPE_INTEGER,
451
 
                     geis_xcb_token_add_device_term, geis_device);
452
 
  geis_filterable_attribute_init(&filter_attrs[filter_attr_index++],
453
 
                     GEIS_DEVICE_ATTRIBUTE_TOUCHES, GEIS_ATTR_TYPE_INTEGER,
454
 
                     geis_xcb_token_add_device_term, geis_device);
455
 
  geis_filterable_attribute_init(&filter_attrs[filter_attr_index++],
456
 
                     GEIS_DEVICE_ATTRIBUTE_DIRECT_TOUCH, GEIS_ATTR_TYPE_BOOLEAN,
457
 
                     geis_xcb_token_add_device_term, geis_device);
458
 
  geis_filterable_attribute_init(&filter_attrs[filter_attr_index++],
459
 
                     GEIS_DEVICE_ATTRIBUTE_INDEPENDENT_TOUCH, GEIS_ATTR_TYPE_BOOLEAN,
460
 
                     geis_xcb_token_add_device_term, geis_device);
461
 
  geis_register_device(be->geis, geis_device, filter_attr_index, filter_attrs);
462
 
  free(filter_attrs);
463
 
  goto final_exit;
464
 
 
465
 
  geis_event_delete(device_event);
466
 
unroll_device:
467
 
  geis_device_unref(geis_device);
468
 
final_exit:
469
 
  return;
470
 
}
471
 
 
472
 
 
473
 
/*
474
 
 * Enumerates all input devices known to the X server and reports those that may
475
 
 * give gestural input.
476
 
 */
477
 
static void
478
 
_report_xcb_devices(GeisXcbBackend be, int deviceid)
479
 
{
480
 
  int num_devices;
481
 
  XIDeviceInfo *devices = XIQueryDevice(be->x11_display, deviceid, &num_devices);
482
 
  if (devices == NULL)
483
 
  {
484
 
    geis_warning("error retrieving device from XIQueryDevice()");
485
 
    return;
486
 
  }
487
 
 
488
 
  for (int device_index = 0; device_index < num_devices; ++device_index)
489
 
  {
490
 
    int class_index;
491
 
    for (class_index = 0;
492
 
         class_index < devices[device_index].num_classes;
493
 
         ++class_index)
494
 
    {
495
 
      XIAnyClassInfo *any = devices[device_index].classes[class_index];
496
 
      if (any->type == XITouchClass)
497
 
      {
498
 
        _report_an_xcb_device(be, &devices[device_index]);
499
 
        break;
500
 
      }
501
 
    }
502
 
  }
503
 
 
504
 
  XIFreeDeviceInfo(devices);
505
 
}
506
 
#endif
507
 
 
508
 
 
509
 
/*
510
 
 * Generates the events for gesture classes.
511
 
 */
512
 
static void
513
 
_report_grail_classes(GeisXcbBackend be)
514
 
{
515
 
  static struct GeisFilterableAttribute attrs[] = {
516
 
    { GEIS_CLASS_ATTRIBUTE_NAME,      GEIS_ATTR_TYPE_STRING,  geis_xcb_token_add_class_term, NULL },
517
 
    { GEIS_CLASS_ATTRIBUTE_ID,        GEIS_ATTR_TYPE_INTEGER, geis_xcb_token_add_class_term, NULL },
518
 
    { GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_ATTR_TYPE_INTEGER, geis_xcb_token_add_class_term, NULL }
519
 
  };
520
 
  GeisSize attr_count = sizeof(attrs) / sizeof(struct GeisFilterableAttribute);
521
 
 
522
 
  GeisGestureClass drag_class = geis_gesture_class_new(GEIS_GESTURE_DRAG,
523
 
                                                       GRAIL_TYPE_DRAG1);
524
 
  geis_xcb_backend_add_drag_attrs(drag_class);
525
 
  attrs[0].add_term_context = attrs[1].add_term_context = attrs[2].add_term_context = drag_class;
526
 
  geis_register_gesture_class(be->geis, drag_class, attr_count, attrs);
527
 
  _set_grail_type_class(GRAIL_TYPE_DRAG1, drag_class);
528
 
  _set_grail_type_class(GRAIL_TYPE_DRAG2, drag_class);
529
 
  _set_grail_type_class(GRAIL_TYPE_DRAG3, drag_class);
530
 
  _set_grail_type_class(GRAIL_TYPE_DRAG4, drag_class);
531
 
  _set_grail_type_class(GRAIL_TYPE_DRAG5, drag_class);
532
 
  _set_grail_type_class(GRAIL_TYPE_EDRAG, drag_class);
533
 
  _set_grail_type_class(GRAIL_TYPE_MDRAG, drag_class);
534
 
 
535
 
  GeisGestureClass pinch_class = geis_gesture_class_new(GEIS_GESTURE_PINCH,
536
 
                                                        GRAIL_TYPE_PINCH1);
537
 
  geis_xcb_backend_add_pinch_attrs(pinch_class);
538
 
  attrs[0].add_term_context = attrs[1].add_term_context = attrs[2].add_term_context = pinch_class;
539
 
  geis_register_gesture_class(be->geis, pinch_class, attr_count, attrs);
540
 
  _set_grail_type_class(GRAIL_TYPE_PINCH1, pinch_class);
541
 
  _set_grail_type_class(GRAIL_TYPE_PINCH2, pinch_class);
542
 
  _set_grail_type_class(GRAIL_TYPE_PINCH3, pinch_class);
543
 
  _set_grail_type_class(GRAIL_TYPE_PINCH4, pinch_class);
544
 
  _set_grail_type_class(GRAIL_TYPE_PINCH5, pinch_class);
545
 
  _set_grail_type_class(GRAIL_TYPE_EPINCH, pinch_class);
546
 
  _set_grail_type_class(GRAIL_TYPE_MPINCH, pinch_class);
547
 
 
548
 
  GeisGestureClass rotate_class = geis_gesture_class_new(GEIS_GESTURE_ROTATE,
549
 
                                                         GRAIL_TYPE_ROTATE1);
550
 
  geis_xcb_backend_add_rotate_attrs(rotate_class);
551
 
  attrs[0].add_term_context = attrs[1].add_term_context = attrs[2].add_term_context = rotate_class;
552
 
  geis_register_gesture_class(be->geis, rotate_class, attr_count, attrs);
553
 
  _set_grail_type_class(GRAIL_TYPE_ROTATE1, rotate_class);
554
 
  _set_grail_type_class(GRAIL_TYPE_ROTATE2, rotate_class);
555
 
  _set_grail_type_class(GRAIL_TYPE_ROTATE3, rotate_class);
556
 
  _set_grail_type_class(GRAIL_TYPE_ROTATE4, rotate_class);
557
 
  _set_grail_type_class(GRAIL_TYPE_ROTATE5, rotate_class);
558
 
  _set_grail_type_class(GRAIL_TYPE_EROTATE, rotate_class);
559
 
  _set_grail_type_class(GRAIL_TYPE_MROTATE, rotate_class);
560
 
 
561
 
  GeisGestureClass tap_class = geis_gesture_class_new(GEIS_GESTURE_TAP,
562
 
                                                      GRAIL_TYPE_TAP1);
563
 
  geis_xcb_backend_add_tap_attrs(tap_class);
564
 
  attrs[0].add_term_context = attrs[1].add_term_context = attrs[2].add_term_context = tap_class;
565
 
  geis_register_gesture_class(be->geis, tap_class, attr_count, attrs);
566
 
  _set_grail_type_class(GRAIL_TYPE_TAP1, tap_class);
567
 
  _set_grail_type_class(GRAIL_TYPE_TAP2, tap_class);
568
 
  _set_grail_type_class(GRAIL_TYPE_TAP3, tap_class);
569
 
  _set_grail_type_class(GRAIL_TYPE_TAP4, tap_class);
570
 
  _set_grail_type_class(GRAIL_TYPE_TAP5, tap_class);
571
 
 
572
 
  GeisGestureClass touch_class = geis_gesture_class_new(GEIS_GESTURE_TOUCH,
573
 
                                                        GRAIL_TYPE_TOUCH1);
574
 
  attrs[0].add_term_context = attrs[1].add_term_context = attrs[2].add_term_context = touch_class;
575
 
  geis_register_gesture_class(be->geis, touch_class, attr_count, attrs);
576
 
  _set_grail_type_class(GRAIL_TYPE_TOUCH1, touch_class);
577
 
  _set_grail_type_class(GRAIL_TYPE_TOUCH2, touch_class);
578
 
  _set_grail_type_class(GRAIL_TYPE_TOUCH3, touch_class);
579
 
  _set_grail_type_class(GRAIL_TYPE_TOUCH4, touch_class);
580
 
  _set_grail_type_class(GRAIL_TYPE_TOUCH5, touch_class);
581
 
  _set_grail_type_class(GRAIL_TYPE_ETOUCH, touch_class);
582
 
  _set_grail_type_class(GRAIL_TYPE_MTOUCH, touch_class);
583
 
}
584
 
 
585
 
 
586
 
static void
587
 
_report_xcb_regions(GeisXcbBackend be)
588
 
{
589
 
  static struct GeisFilterableAttribute attrs[] = {
590
 
    { GEIS_REGION_ATTRIBUTE_WINDOWID, GEIS_ATTR_TYPE_INTEGER,  geis_xcb_token_add_region_term, NULL },
591
 
  };
592
 
  GeisSize attr_count = sizeof(attrs) / sizeof(struct GeisFilterableAttribute);
593
 
 
594
 
  geis_register_region(be->geis, NULL, attr_count, attrs);
595
 
}
596
 
 
597
 
 
598
 
static void
599
 
_report_xcb_specials(GeisXcbBackend be)
600
 
{
601
 
  static struct GeisFilterableAttribute attrs[] = {
602
 
    { GEIS_GESTURE_TYPE_SYSTEM, GEIS_ATTR_TYPE_BOOLEAN, geis_xcb_token_add_feature_term, NULL },
603
 
    { "GRAB", GEIS_ATTR_TYPE_BOOLEAN, geis_xcb_token_add_feature_term, NULL }
604
 
  };
605
 
  GeisSize attr_count = sizeof(attrs) / sizeof(struct GeisFilterableAttribute);
606
 
 
607
 
  geis_register_special(be->geis, attr_count, attrs);
608
 
}
609
 
 
610
 
#ifdef HAVE_XI_2_1
611
 
static void
612
 
_select_device_events(GeisXcbBackend be)
613
 
{
614
 
  XIEventMask xi_event_mask;
615
 
  int event;
616
 
  int error;
617
 
 
618
 
  XQueryExtension(be->x11_display, "XInputExtension", &be->xi_opcode, &event,
619
 
                  &error);
620
 
 
621
 
  xi_event_mask.deviceid = XIAllDevices;
622
 
  xi_event_mask.mask_len = XIMaskLen(XI_HierarchyChanged);
623
 
  xi_event_mask.mask = calloc(xi_event_mask.mask_len, sizeof(char));
624
 
  XISetMask(xi_event_mask.mask, XI_HierarchyChanged);
625
 
  if (XISelectEvents(be->x11_display, XDefaultRootWindow(be->x11_display),
626
 
                     &xi_event_mask, 1) != Success)
627
 
    geis_warning("failed to select for XI hierarchy change events");
628
 
}
629
 
#endif
630
 
 
631
 
void 
632
 
_construct(void *mem, Geis geis)
633
 
{
634
 
  GeisXcbBackend be = (GeisXcbBackend)mem;
635
 
  be->geis = geis;
636
 
  be->grail_is_old_version = _grail_is_old_version();
637
 
 
638
 
  be->x11_display = XOpenDisplay(NULL);
639
 
  if (!be->x11_display)
640
 
  {
641
 
    geis_error("error opening X server.");
642
 
    geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
643
 
    goto final_exit;
644
 
  }
645
 
 
646
 
  be->xcb_connection = XGetXCBConnection(be->x11_display);
647
 
  if (!be->xcb_connection)
648
 
  {
649
 
    geis_error("error connecting to X server.");
650
 
    geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
651
 
    goto unwind_x11;
652
 
  }
653
 
  if (!_verify_xcb_version(be->xcb_connection))
654
 
  {
655
 
    geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
656
 
    goto unwind_x11;
657
 
  }
658
 
 
659
 
  be->xcb_fd = xcb_get_file_descriptor(be->xcb_connection);
660
 
  geis_multiplex_fd(be->geis, be->xcb_fd, GEIS_BE_MX_READ_AVAILABLE,
661
 
                    _fd_callback, be);
662
 
 
663
 
  be->sub_table = geis_xcb_backend_sub_table_new();
664
 
 
665
 
#ifdef HAVE_XI_2_1
666
 
  _report_xcb_devices(be, XIAllDevices);
667
 
  _select_device_events(be);
668
 
#endif
669
 
  _report_grail_classes(be);
670
 
  _report_xcb_regions(be);
671
 
  _report_xcb_specials(be);
672
 
  _report_init_complete(be);
673
 
 
674
 
  goto final_exit;
675
 
 
676
 
unwind_x11:
677
 
  /* XCB has a bug that causes XCloseDisplay to fire a fatal IO error if the xcb
678
 
   * connection has an error. The best we can do right now is to leave the
679
 
   * connection dangling. */
680
 
  if (!be->xcb_connection || !xcb_connection_has_error(be->xcb_connection))
681
 
    XCloseDisplay(be->x11_display);
682
 
final_exit:
683
 
  return;
684
 
}
685
 
 
686
 
 
687
 
void 
688
 
_finalize(GeisBackend g)
689
 
{
690
 
  GeisXcbBackend be = (GeisXcbBackend)g;
691
 
 
692
 
  geis_xcb_backend_sub_table_delete(be->sub_table);
693
 
 
694
 
  /* XCB has a bug that causes XCloseDisplay to fire a fatal IO error if the xcb
695
 
   * connection has an error. The best we can do right now is to leave the
696
 
   * connection dangling. */
697
 
  if (!be->xcb_connection || !xcb_connection_has_error(be->xcb_connection))
698
 
    XCloseDisplay(be->x11_display);
699
 
 
700
 
  geis_debug("XCB back end finalized");
701
 
}
702
 
 
703
 
 
704
 
GeisBackendToken
705
 
_create_token(GeisBackend gbe, GeisBackendTokenInitState init_state)
706
 
{
707
 
  GeisXcbBackend xbe = (GeisXcbBackend)gbe;
708
 
  GeisBackendToken token = geis_xcb_token_new(gbe, init_state);
709
 
  geis_xcb_token_set_xcb(token, xbe->xcb_connection);
710
 
  return token;
711
 
}
712
 
 
713
 
 
714
 
static void
715
 
_dispatch_gesture(GeisXcbBackend be, xcb_gesture_notify_event_t *grail_event)
716
 
{
717
 
  GeisEvent     geis_event = NULL;
718
 
  GeisGroupSet  groupset = geis_groupset_new();
719
 
  GeisAttr      group_attr = geis_attr_new(GEIS_EVENT_ATTRIBUTE_GROUPSET,
720
 
                                           GEIS_ATTR_TYPE_POINTER,
721
 
                                           groupset);
722
 
  GeisTouchSet  touchset = geis_touchset_new();
723
 
  GeisAttr      touch_attr = geis_attr_new(GEIS_EVENT_ATTRIBUTE_TOUCHSET,
724
 
                                           GEIS_ATTR_TYPE_POINTER,
725
 
                                           touchset);
726
 
 
727
 
  /* Play games with the grail event to get the grail gesture properties. */
728
 
  float        *properties = (float *)(grail_event + 1);
729
 
  GeisSize      num_properties = grail_event->num_props;
730
 
  GeisSize      num_unmapped_properties = num_properties;
731
 
  GeisSize      touch_count;
732
 
 
733
 
  geis_attr_set_destructor(group_attr, (GeisAttrDestructor)geis_groupset_delete);
734
 
  geis_attr_set_destructor(touch_attr, (GeisAttrDestructor)geis_touchset_delete);
735
 
 
736
 
  switch (grail_event->status)
737
 
  {
738
 
    case GRAIL_STATUS_BEGIN:
739
 
      geis_event = geis_event_new(GEIS_EVENT_GESTURE_BEGIN);
740
 
      break;
741
 
    case GRAIL_STATUS_UPDATE:
742
 
      geis_event = geis_event_new(GEIS_EVENT_GESTURE_UPDATE);
743
 
      break;
744
 
    case GRAIL_STATUS_END:
745
 
      geis_event = geis_event_new(GEIS_EVENT_GESTURE_END);
746
 
      break;
747
 
  }
748
 
 
749
 
  GeisGroup group = geis_group_new(1);
750
 
  geis_groupset_insert(groupset, group);
751
 
 
752
 
  GeisFrame frame = geis_frame_new(grail_event->gesture_id);
753
 
  geis_group_insert_frame(group, frame);
754
 
  geis_frame_set_is_class(frame, _get_geis_class_from_grail_type(grail_event->gesture_type));
755
 
 
756
 
  GeisAttr attr = NULL;
757
 
 
758
 
  GeisInteger ival = grail_event->device_id;
759
 
  attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_DEVICE_ID,
760
 
                       GEIS_ATTR_TYPE_INTEGER,
761
 
                       &ival);
762
 
  geis_frame_add_attr(frame, attr);
763
 
 
764
 
  ival = grail_event->time;
765
 
  attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_TIMESTAMP,
766
 
                       GEIS_ATTR_TYPE_INTEGER,
767
 
                       &ival);
768
 
  geis_frame_add_attr(frame, attr);
769
 
 
770
 
  ival = grail_event->root;
771
 
  attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_ROOT_WINDOW_ID,
772
 
                       GEIS_ATTR_TYPE_INTEGER,
773
 
                       &ival);
774
 
  geis_frame_add_attr(frame, attr);
775
 
 
776
 
  ival = grail_event->event;
777
 
  attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_EVENT_WINDOW_ID,
778
 
                       GEIS_ATTR_TYPE_INTEGER,
779
 
                       &ival);
780
 
  geis_frame_add_attr(frame, attr);
781
 
 
782
 
  ival = grail_event->child;
783
 
  attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_CHILD_WINDOW_ID,
784
 
                       GEIS_ATTR_TYPE_INTEGER,
785
 
                       &ival);
786
 
  geis_frame_add_attr(frame, attr);
787
 
 
788
 
  attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_FOCUS_X,
789
 
                       GEIS_ATTR_TYPE_FLOAT,
790
 
                       &grail_event->focus_x);
791
 
  geis_frame_add_attr(frame, attr);
792
 
 
793
 
  attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_FOCUS_Y,
794
 
                       GEIS_ATTR_TYPE_FLOAT,
795
 
                       &grail_event->focus_y);
796
 
  geis_frame_add_attr(frame, attr);
797
 
 
798
 
  num_unmapped_properties = geis_xcb_backend_map_grail_attrs(
799
 
                                   grail_event->gesture_type,
800
 
                                   be->grail_is_old_version ? 1 : 2,
801
 
                                   num_properties, properties, frame);
802
 
 
803
 
  /* any remaining properties are touch properties */
804
 
  touch_count = num_unmapped_properties / 3;
805
 
  properties += num_properties - num_unmapped_properties;
806
 
  attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_TOUCHES,
807
 
                       GEIS_ATTR_TYPE_INTEGER,
808
 
                       &touch_count);
809
 
  geis_frame_add_attr(frame, attr);
810
 
 
811
 
  GeisSize i;
812
 
  for (i = 0; i < touch_count; ++i)
813
 
  {
814
 
    GeisTouch  touch = geis_touch_new(i);
815
 
 
816
 
    if (num_unmapped_properties > 0)
817
 
    {
818
 
      GeisInteger touch_slot = *properties;
819
 
      attr = geis_attr_new(GEIS_TOUCH_ATTRIBUTE_ID,
820
 
                           GEIS_ATTR_TYPE_INTEGER,
821
 
                           &touch_slot);
822
 
      geis_touch_add_attr(touch, attr);
823
 
      ++properties;
824
 
      --num_unmapped_properties;
825
 
    }
826
 
    if (num_unmapped_properties > 0)
827
 
    {
828
 
      attr = geis_attr_new(GEIS_TOUCH_ATTRIBUTE_X,
829
 
                           GEIS_ATTR_TYPE_FLOAT,
830
 
                           properties);
831
 
      geis_touch_add_attr(touch, attr);
832
 
      ++properties;
833
 
      --num_unmapped_properties;
834
 
    }
835
 
    if (num_unmapped_properties > 0)
836
 
    {
837
 
      attr = geis_attr_new(GEIS_TOUCH_ATTRIBUTE_Y,
838
 
                           GEIS_ATTR_TYPE_FLOAT,
839
 
                           properties);
840
 
      geis_touch_add_attr(touch, attr);
841
 
      ++properties;
842
 
      --num_unmapped_properties;
843
 
    }
844
 
    geis_touchset_insert(touchset, touch);
845
 
    geis_frame_add_touchid(frame, geis_touch_id(touch));
846
 
  }
847
 
 
848
 
  geis_event_add_attr(geis_event, group_attr);
849
 
  geis_event_add_attr(geis_event, touch_attr);
850
 
  geis_post_event(be->geis, geis_event);
851
 
}
852
 
 
853
 
#ifdef HAVE_XI_2_1
854
 
static void
855
 
_report_hierarchy_change(GeisXcbBackend be, xcb_ge_event_t *event)
856
 
{
857
 
  xXIHierarchyEvent *he = (xXIHierarchyEvent *)event;
858
 
  xXIHierarchyInfo *info = (xXIHierarchyInfo *)(event + 1);
859
 
  int i;
860
 
 
861
 
  for (i = 0; i < he->num_info; ++i, ++info)
862
 
  {
863
 
    if (info->flags == XISlaveAdded) {
864
 
      _report_xcb_devices(be, info->deviceid);
865
 
    }
866
 
    else if (info->flags == XISlaveRemoved)
867
 
    {
868
 
      GeisDeviceBag bag = geis_devices(be->geis);
869
 
      GeisSize i;
870
 
 
871
 
      for (i = 0; i < geis_device_bag_count(bag); ++i)
872
 
      {
873
 
        GeisDevice device = geis_device_bag_device(bag, i);
874
 
 
875
 
        if (geis_device_id(device) == info->deviceid)
876
 
        {
877
 
          geis_unregister_device(be->geis, device);
878
 
          break;
879
 
        }
880
 
      }
881
 
    }
882
 
  }
883
 
}
884
 
#endif
885
 
 
886
 
/**
887
 
 * Dispatches events coming from XCB.
888
 
 */
889
 
static void
890
 
_xcb_dispatch(GeisXcbBackend be)
891
 
{
892
 
  if (be->xcb_connection)
893
 
  {
894
 
    const xcb_query_extension_reply_t *extension_info;
895
 
    extension_info = xcb_get_extension_data(be->xcb_connection, &xcb_gesture_id);
896
 
 
897
 
    xcb_generic_event_t *event = NULL;
898
 
    while ((event = xcb_poll_for_event(be->xcb_connection)))
899
 
    {
900
 
      xcb_ge_event_t *ge;
901
 
 
902
 
      if (event->response_type != GenericEvent) {
903
 
        geis_warning("received non-generic event type: %d",
904
 
                     event->response_type);
905
 
        goto next_event;
906
 
      }
907
 
 
908
 
      ge = (xcb_ge_event_t *)event;
909
 
 
910
 
      /* an error in the xcb protocol, pad0 is actually the extension opcode */
911
 
      if (ge->pad0 == extension_info->major_opcode)
912
 
      {
913
 
        xcb_gesture_notify_event_t *gesture_event =
914
 
          (xcb_gesture_notify_event_t*)event;
915
 
 
916
 
        if (gesture_event->event_type != XCB_GESTURE_NOTIFY)
917
 
        {
918
 
          geis_warning("received unrecognized gesture event type: %d",
919
 
                       gesture_event->event_type);
920
 
          goto next_event;
921
 
        }
922
 
 
923
 
        _dispatch_gesture(be, gesture_event);
924
 
      }
925
 
#ifdef HAVE_XI_2_1
926
 
      else if (ge->pad0 == be->xi_opcode)
927
 
      {
928
 
        if (ge->event_type == XI_HierarchyChanged)
929
 
          _report_hierarchy_change(be, ge);
930
 
        else
931
 
          geis_warning("received unrecognized XI event type: %d",
932
 
                       ge->event_type);
933
 
      }
934
 
#endif
935
 
      else
936
 
        geis_warning("received unrecognized generic event for extension: %d",
937
 
                     ge->pad0);
938
 
 
939
 
next_event:
940
 
      free(event);
941
 
    }
942
 
  }
943
 
}
944
 
 
945
 
/** @todo implement this */
946
 
void
947
 
_fd_callback(int                             fd GEIS_UNUSED,
948
 
             GeisBackendMultiplexorActivity  ev GEIS_UNUSED,
949
 
             void                           *ctx)
950
 
{
951
 
  GeisXcbBackend be = (GeisXcbBackend)ctx;
952
 
  _xcb_dispatch(be);
953
 
}
954
 
 
955
 
 
956
 
Geis
957
 
geis_xcb_backend_geis(GeisXcbBackend be)
958
 
{
959
 
  return be->geis;
960
 
}
961
 
 
962
 
 
963
 
void
964
 
geis_xcb_backend_add_token(GeisXcbBackend be, XcbBackendToken token)
965
 
{
966
 
  uint16_t dev;
967
 
  int win;
968
 
 
969
 
  for (win = 0; win < geis_xcb_token_window_count(token); ++win)
970
 
  {
971
 
    xcb_window_t window_id = geis_xcb_token_window(token, win);
972
 
    for (dev = 0; dev < geis_xcb_token_device_count(token); ++dev)
973
 
    {
974
 
      uint16_t device_id = geis_xcb_token_device(token, dev);
975
 
      geis_xcb_backend_sub_table_insert(be->sub_table,
976
 
                                        window_id,
977
 
                                        device_id,
978
 
                                        token);
979
 
    }
980
 
  }
981
 
}
982
 
 
983
 
 
984
 
void
985
 
geis_xcb_backend_remove_token(GeisXcbBackend be, XcbBackendToken token)
986
 
{
987
 
  geis_xcb_backend_sub_table_remove_token(be->sub_table, token);
988
 
}
989
 
 
990
 
 
991
 
static void
992
 
_compose_grail_masks(XcbBackendToken  token,
993
 
                     void            *context)
994
 
{
995
 
  uint16_t grail_mask_len = geis_xcb_token_grail_mask_len(token);
996
 
  uint32_t *grail_mask = geis_xcb_token_grail_mask(token);
997
 
  uint32_t *mask = (uint32_t *)context;
998
 
 
999
 
  _grail_mask_or(grail_mask_len, mask, grail_mask);
1000
 
}
1001
 
 
1002
 
 
1003
 
void
1004
 
geis_xcb_backend_select_events(GeisXcbBackend be,
1005
 
                               uint16_t       device_id,
1006
 
                               xcb_window_t   window_id)
1007
 
{
1008
 
  uint16_t grail_mask_len = 2;
1009
 
  uint32_t grail_mask[2];
1010
 
  xcb_generic_error_t  *error;
1011
 
  xcb_void_cookie_t select_cookie;
1012
 
 
1013
 
  _grail_mask_clear(grail_mask_len, grail_mask);
1014
 
  geis_xcb_backend_sub_table_foreach(be->sub_table, window_id, device_id,
1015
 
                                    _compose_grail_masks, grail_mask);
1016
 
 
1017
 
  geis_debug("window_id=0x%08x device_id=%d mask_len=%d mask=0x%08x %08x",
1018
 
             window_id, device_id, grail_mask_len, grail_mask[1], grail_mask[0]);
1019
 
 
1020
 
  select_cookie = xcb_gesture_select_events_checked(be->xcb_connection,
1021
 
                                                    window_id,
1022
 
                                                    device_id,
1023
 
                                                    grail_mask_len,
1024
 
                                                    grail_mask);
1025
 
  error = xcb_request_check(be->xcb_connection, select_cookie);
1026
 
  if (error)
1027
 
  {
1028
 
    geis_error("failed to select events for window 0x%08x", window_id);
1029
 
  }
1030
 
}
1031
 
 
1032
 
 
1033
 
__attribute__((constructor))
1034
 
static void _register_xcb_backend()
1035
 
{
1036
 
  geis_register_backend(GEIS_INIT_UTOUCH_XCB_BACKEND,
1037
 
                        sizeof(struct GeisXcbBackend),
1038
 
                        &be_vtbl);
1039
 
}
1040
 
 
1041
 
/* A dummy routine to force linkage of this module without dlopening it */
1042
 
void
1043
 
geis_include_backend_xcb()
1044
 
{
1045
 
}
1046
 
 
1047
 
 
1048
 
GeisStatus
1049
 
_gxcb_accept_gesture(GeisBackend   be GEIS_UNUSED,
1050
 
                     GeisGroup     group GEIS_UNUSED,
1051
 
                     GeisGestureId gesture_id GEIS_UNUSED)
1052
 
{
1053
 
  return GEIS_STATUS_UNKNOWN_ERROR;
1054
 
}
1055
 
 
1056
 
 
1057
 
GeisStatus
1058
 
_gxcb_reject_gesture(GeisBackend   be GEIS_UNUSED,
1059
 
                     GeisGroup     group GEIS_UNUSED,
1060
 
                     GeisGestureId gesture_id GEIS_UNUSED)
1061
 
{
1062
 
  return GEIS_STATUS_UNKNOWN_ERROR;
1063
 
}
1064