2
* @file xcb/geis_xcb_backend.c
3
* @brief Implements the GEIS XCB back end.
5
* Copyright 2011 Canonical Ltd.
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
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
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/>.
20
#include "geis_config.h"
21
#include "geis_xcb_backend.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"
40
#include <grail-types.h>
43
#include "xcb_gesture.h"
44
#include <X11/extensions/XI2proto.h>
45
#include <X11/extensions/XInput2.h>
47
#include <X11/Xlib-xcb.h>
50
# include <xorg/xserver-properties.h>
55
#define MAX_NUM_DEVICES 10
56
#define MAX_NUM_WINDOWS 10
58
#define GRAIL_XCB_BITMASK_LEN 2
61
static inline GeisSize
62
_min(GeisSize a, GeisSize b)
64
return (a < b) ? a : b;
68
static inline GeisSize
69
_max(GeisSize a, GeisSize b)
71
return (a > b) ? a : b;
79
xcb_connection_t *xcb_connection;
81
int grail_is_old_version;
82
GeisXcbBackendSubTable sub_table;
88
* Information required for each xcb-gesture subscription.
90
* @todo: unhardcode sizes and lengths (and malloc them instead).
92
typedef struct _XcbGestureSub
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];
100
int num_region_filters;
101
xcb_window_t windows[MAX_NUM_WINDOWS];
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);
113
static struct GeisBackendVtable be_vtbl = {
117
_gxcb_accept_gesture,
122
/* A handy little table to map grail types to geis gesture classes. */
123
static struct GrailTypeToGeisClass
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 }
163
static GeisSize s_grail_type_map_size = sizeof(s_grail_type_map)
164
/ sizeof(struct GrailTypeToGeisClass);
167
_set_grail_type_class(GeisInteger grail_type, GeisGestureClass geis_class)
170
for (i = 0; i < s_grail_type_map_size; ++i)
172
if (s_grail_type_map[i].grail_type == grail_type)
174
s_grail_type_map[i].geis_class = geis_class;
181
static GeisGestureClass
182
_get_geis_class_from_grail_type(GeisInteger grail_type)
185
for (i = 0; i < s_grail_type_map_size; ++i)
187
if (s_grail_type_map[i].grail_type == grail_type)
189
return s_grail_type_map[i].geis_class;
197
* Makes an attempt to determine the local version of grail. Pretty useless if
201
_grail_is_old_version(void)
204
int is_old_version = 1;
205
void* lib = dlopen("libutouch-grail.so.1", RTLD_LAZY | RTLD_LOCAL);
208
geis_error("can not open libutouch-grail.so.1: %s", dlerror());
212
*(void **)(&fn) = dlsym(lib, "grail_get_version");
215
/* Check against magic in a particular version of grail.h */
216
is_old_version = fn() < 0x00011000;
221
return is_old_version;
226
_report_init_complete(GeisXcbBackend be)
228
geis_post_event(be->geis, geis_event_new(GEIS_EVENT_INIT_COMPLETE));
234
_map_xi2_mode_to_geis_device_attrs(int xi2_mode, GeisDevice geis_device)
236
GeisAttr device_attr;
237
GeisBoolean is_direct = GEIS_FALSE;
238
GeisBoolean is_independent = GEIS_FALSE;
240
if (xi2_mode == XIDirectTouch)
241
is_direct = GEIS_TRUE;
243
device_attr = geis_attr_new(GEIS_DEVICE_ATTRIBUTE_DIRECT_TOUCH,
244
GEIS_ATTR_TYPE_BOOLEAN,
248
geis_error("failed to create device attr");
252
geis_device_add_attr(geis_device, device_attr);
255
if (xi2_mode == XIIndependentPointer)
256
is_independent = GEIS_TRUE;
258
device_attr = geis_attr_new(GEIS_DEVICE_ATTRIBUTE_INDEPENDENT_TOUCH,
259
GEIS_ATTR_TYPE_BOOLEAN,
263
geis_error("failed to create device attr");
267
geis_device_add_attr(geis_device, device_attr);
274
_verify_xcb_version(xcb_connection_t *xcb_connection)
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;
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,
289
geis_error("failed to receive XCB gesture version reply.");
293
if (version_reply->major_version != XCB_GESTURE_MAJOR_VERSION
294
&& version_reply->minor_version != XCB_GESTURE_MINOR_VERSION)
296
geis_error("server supports unrecognized version: %d.%d",
297
version_reply->major_version, version_reply->minor_version);
301
is_valid_version = GEIS_TRUE;
306
return is_valid_version;
312
_report_xi2_valuator_attrs(GeisDevice geis_device,
313
XITouchValuatorClassInfo *v,
314
GeisString min_label,
315
GeisString max_label,
316
GeisString res_label)
319
GeisAttr device_attr;
322
device_attr = geis_attr_new(min_label, GEIS_ATTR_TYPE_FLOAT, &f);
325
geis_error("failed to create device attr");
329
geis_device_add_attr(geis_device, device_attr);
333
device_attr = geis_attr_new(max_label, GEIS_ATTR_TYPE_FLOAT, &f);
336
geis_error("failed to create device attr");
340
geis_device_add_attr(geis_device, device_attr);
343
f = (GeisFloat)v->resolution;
344
device_attr = geis_attr_new(res_label, GEIS_ATTR_TYPE_FLOAT, &f);
347
geis_error("failed to create device attr");
351
geis_device_add_attr(geis_device, device_attr);
357
* Reports a new gesture-capable device.
360
_report_an_xcb_device(GeisXcbBackend be, XIDeviceInfo *xcb_device)
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;
369
geis_device = geis_device_new(xcb_device->name, xcb_device->deviceid);
372
geis_error("failed to create device");
376
/* Add attributes to the device. */
377
for (class_index = 0; class_index < xcb_device->num_classes; ++class_index)
379
XIAnyClassInfo *any = xcb_device->classes[class_index];
380
if (any->type == XITouchClass)
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);
390
device_attr = geis_attr_new(GEIS_DEVICE_ATTRIBUTE_TOUCHES,
391
GEIS_ATTR_TYPE_INTEGER,
395
geis_error("failed to create device attr");
399
geis_device_add_attr(geis_device, device_attr);
402
else if (any->type == XITouchValuatorClass)
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))
408
_report_xi2_valuator_attrs(geis_device,
410
GEIS_DEVICE_ATTRIBUTE_MIN_X,
411
GEIS_DEVICE_ATTRIBUTE_MAX_X,
412
GEIS_DEVICE_ATTRIBUTE_RES_X);
414
else if (label && 0 == strcmp(label, AXIS_LABEL_PROP_ABS_MT_POSITION_Y))
416
_report_xi2_valuator_attrs(geis_device,
418
GEIS_DEVICE_ATTRIBUTE_MIN_Y,
419
GEIS_DEVICE_ATTRIBUTE_MAX_Y,
420
GEIS_DEVICE_ATTRIBUTE_RES_Y);
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);
438
/* Register the device for subscriptions. */
439
filter_attrs = calloc(filter_attr_count, sizeof(struct GeisFilterableAttribute));
442
geis_debug("error allocating device attr table");
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);
465
geis_event_delete(device_event);
467
geis_device_unref(geis_device);
474
* Enumerates all input devices known to the X server and reports those that may
475
* give gestural input.
478
_report_xcb_devices(GeisXcbBackend be, int deviceid)
481
XIDeviceInfo *devices = XIQueryDevice(be->x11_display, deviceid, &num_devices);
484
geis_warning("error retrieving device from XIQueryDevice()");
488
for (int device_index = 0; device_index < num_devices; ++device_index)
491
for (class_index = 0;
492
class_index < devices[device_index].num_classes;
495
XIAnyClassInfo *any = devices[device_index].classes[class_index];
496
if (any->type == XITouchClass)
498
_report_an_xcb_device(be, &devices[device_index]);
504
XIFreeDeviceInfo(devices);
510
* Generates the events for gesture classes.
513
_report_grail_classes(GeisXcbBackend be)
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 }
520
GeisSize attr_count = sizeof(attrs) / sizeof(struct GeisFilterableAttribute);
522
GeisGestureClass drag_class = geis_gesture_class_new(GEIS_GESTURE_DRAG,
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);
535
GeisGestureClass pinch_class = geis_gesture_class_new(GEIS_GESTURE_PINCH,
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);
548
GeisGestureClass rotate_class = geis_gesture_class_new(GEIS_GESTURE_ROTATE,
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);
561
GeisGestureClass tap_class = geis_gesture_class_new(GEIS_GESTURE_TAP,
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);
572
GeisGestureClass touch_class = geis_gesture_class_new(GEIS_GESTURE_TOUCH,
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);
587
_report_xcb_regions(GeisXcbBackend be)
589
static struct GeisFilterableAttribute attrs[] = {
590
{ GEIS_REGION_ATTRIBUTE_WINDOWID, GEIS_ATTR_TYPE_INTEGER, geis_xcb_token_add_region_term, NULL },
592
GeisSize attr_count = sizeof(attrs) / sizeof(struct GeisFilterableAttribute);
594
geis_register_region(be->geis, NULL, attr_count, attrs);
599
_report_xcb_specials(GeisXcbBackend be)
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 }
605
GeisSize attr_count = sizeof(attrs) / sizeof(struct GeisFilterableAttribute);
607
geis_register_special(be->geis, attr_count, attrs);
612
_select_device_events(GeisXcbBackend be)
614
XIEventMask xi_event_mask;
618
XQueryExtension(be->x11_display, "XInputExtension", &be->xi_opcode, &event,
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");
632
_construct(void *mem, Geis geis)
634
GeisXcbBackend be = (GeisXcbBackend)mem;
636
be->grail_is_old_version = _grail_is_old_version();
638
be->x11_display = XOpenDisplay(NULL);
639
if (!be->x11_display)
641
geis_error("error opening X server.");
642
geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
646
be->xcb_connection = XGetXCBConnection(be->x11_display);
647
if (!be->xcb_connection)
649
geis_error("error connecting to X server.");
650
geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
653
if (!_verify_xcb_version(be->xcb_connection))
655
geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
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,
663
be->sub_table = geis_xcb_backend_sub_table_new();
666
_report_xcb_devices(be, XIAllDevices);
667
_select_device_events(be);
669
_report_grail_classes(be);
670
_report_xcb_regions(be);
671
_report_xcb_specials(be);
672
_report_init_complete(be);
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);
688
_finalize(GeisBackend g)
690
GeisXcbBackend be = (GeisXcbBackend)g;
692
geis_xcb_backend_sub_table_delete(be->sub_table);
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);
700
geis_debug("XCB back end finalized");
705
_create_token(GeisBackend gbe, GeisBackendTokenInitState init_state)
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);
715
_dispatch_gesture(GeisXcbBackend be, xcb_gesture_notify_event_t *grail_event)
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,
722
GeisTouchSet touchset = geis_touchset_new();
723
GeisAttr touch_attr = geis_attr_new(GEIS_EVENT_ATTRIBUTE_TOUCHSET,
724
GEIS_ATTR_TYPE_POINTER,
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;
733
geis_attr_set_destructor(group_attr, (GeisAttrDestructor)geis_groupset_delete);
734
geis_attr_set_destructor(touch_attr, (GeisAttrDestructor)geis_touchset_delete);
736
switch (grail_event->status)
738
case GRAIL_STATUS_BEGIN:
739
geis_event = geis_event_new(GEIS_EVENT_GESTURE_BEGIN);
741
case GRAIL_STATUS_UPDATE:
742
geis_event = geis_event_new(GEIS_EVENT_GESTURE_UPDATE);
744
case GRAIL_STATUS_END:
745
geis_event = geis_event_new(GEIS_EVENT_GESTURE_END);
749
GeisGroup group = geis_group_new(1);
750
geis_groupset_insert(groupset, group);
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));
756
GeisAttr attr = NULL;
758
GeisInteger ival = grail_event->device_id;
759
attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_DEVICE_ID,
760
GEIS_ATTR_TYPE_INTEGER,
762
geis_frame_add_attr(frame, attr);
764
ival = grail_event->time;
765
attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_TIMESTAMP,
766
GEIS_ATTR_TYPE_INTEGER,
768
geis_frame_add_attr(frame, attr);
770
ival = grail_event->root;
771
attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_ROOT_WINDOW_ID,
772
GEIS_ATTR_TYPE_INTEGER,
774
geis_frame_add_attr(frame, attr);
776
ival = grail_event->event;
777
attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_EVENT_WINDOW_ID,
778
GEIS_ATTR_TYPE_INTEGER,
780
geis_frame_add_attr(frame, attr);
782
ival = grail_event->child;
783
attr = geis_attr_new(GEIS_GESTURE_ATTRIBUTE_CHILD_WINDOW_ID,
784
GEIS_ATTR_TYPE_INTEGER,
786
geis_frame_add_attr(frame, attr);
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);
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);
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);
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,
809
geis_frame_add_attr(frame, attr);
812
for (i = 0; i < touch_count; ++i)
814
GeisTouch touch = geis_touch_new(i);
816
if (num_unmapped_properties > 0)
818
GeisInteger touch_slot = *properties;
819
attr = geis_attr_new(GEIS_TOUCH_ATTRIBUTE_ID,
820
GEIS_ATTR_TYPE_INTEGER,
822
geis_touch_add_attr(touch, attr);
824
--num_unmapped_properties;
826
if (num_unmapped_properties > 0)
828
attr = geis_attr_new(GEIS_TOUCH_ATTRIBUTE_X,
829
GEIS_ATTR_TYPE_FLOAT,
831
geis_touch_add_attr(touch, attr);
833
--num_unmapped_properties;
835
if (num_unmapped_properties > 0)
837
attr = geis_attr_new(GEIS_TOUCH_ATTRIBUTE_Y,
838
GEIS_ATTR_TYPE_FLOAT,
840
geis_touch_add_attr(touch, attr);
842
--num_unmapped_properties;
844
geis_touchset_insert(touchset, touch);
845
geis_frame_add_touchid(frame, geis_touch_id(touch));
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);
855
_report_hierarchy_change(GeisXcbBackend be, xcb_ge_event_t *event)
857
xXIHierarchyEvent *he = (xXIHierarchyEvent *)event;
858
xXIHierarchyInfo *info = (xXIHierarchyInfo *)(event + 1);
861
for (i = 0; i < he->num_info; ++i, ++info)
863
if (info->flags == XISlaveAdded) {
864
_report_xcb_devices(be, info->deviceid);
866
else if (info->flags == XISlaveRemoved)
868
GeisDeviceBag bag = geis_devices(be->geis);
871
for (i = 0; i < geis_device_bag_count(bag); ++i)
873
GeisDevice device = geis_device_bag_device(bag, i);
875
if (geis_device_id(device) == info->deviceid)
877
geis_unregister_device(be->geis, device);
887
* Dispatches events coming from XCB.
890
_xcb_dispatch(GeisXcbBackend be)
892
if (be->xcb_connection)
894
const xcb_query_extension_reply_t *extension_info;
895
extension_info = xcb_get_extension_data(be->xcb_connection, &xcb_gesture_id);
897
xcb_generic_event_t *event = NULL;
898
while ((event = xcb_poll_for_event(be->xcb_connection)))
902
if (event->response_type != GenericEvent) {
903
geis_warning("received non-generic event type: %d",
904
event->response_type);
908
ge = (xcb_ge_event_t *)event;
910
/* an error in the xcb protocol, pad0 is actually the extension opcode */
911
if (ge->pad0 == extension_info->major_opcode)
913
xcb_gesture_notify_event_t *gesture_event =
914
(xcb_gesture_notify_event_t*)event;
916
if (gesture_event->event_type != XCB_GESTURE_NOTIFY)
918
geis_warning("received unrecognized gesture event type: %d",
919
gesture_event->event_type);
923
_dispatch_gesture(be, gesture_event);
926
else if (ge->pad0 == be->xi_opcode)
928
if (ge->event_type == XI_HierarchyChanged)
929
_report_hierarchy_change(be, ge);
931
geis_warning("received unrecognized XI event type: %d",
936
geis_warning("received unrecognized generic event for extension: %d",
945
/** @todo implement this */
947
_fd_callback(int fd GEIS_UNUSED,
948
GeisBackendMultiplexorActivity ev GEIS_UNUSED,
951
GeisXcbBackend be = (GeisXcbBackend)ctx;
957
geis_xcb_backend_geis(GeisXcbBackend be)
964
geis_xcb_backend_add_token(GeisXcbBackend be, XcbBackendToken token)
969
for (win = 0; win < geis_xcb_token_window_count(token); ++win)
971
xcb_window_t window_id = geis_xcb_token_window(token, win);
972
for (dev = 0; dev < geis_xcb_token_device_count(token); ++dev)
974
uint16_t device_id = geis_xcb_token_device(token, dev);
975
geis_xcb_backend_sub_table_insert(be->sub_table,
985
geis_xcb_backend_remove_token(GeisXcbBackend be, XcbBackendToken token)
987
geis_xcb_backend_sub_table_remove_token(be->sub_table, token);
992
_compose_grail_masks(XcbBackendToken token,
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;
999
_grail_mask_or(grail_mask_len, mask, grail_mask);
1004
geis_xcb_backend_select_events(GeisXcbBackend be,
1006
xcb_window_t window_id)
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;
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);
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]);
1020
select_cookie = xcb_gesture_select_events_checked(be->xcb_connection,
1025
error = xcb_request_check(be->xcb_connection, select_cookie);
1028
geis_error("failed to select events for window 0x%08x", window_id);
1033
__attribute__((constructor))
1034
static void _register_xcb_backend()
1036
geis_register_backend(GEIS_INIT_UTOUCH_XCB_BACKEND,
1037
sizeof(struct GeisXcbBackend),
1041
/* A dummy routine to force linkage of this module without dlopening it */
1043
geis_include_backend_xcb()
1049
_gxcb_accept_gesture(GeisBackend be GEIS_UNUSED,
1050
GeisGroup group GEIS_UNUSED,
1051
GeisGestureId gesture_id GEIS_UNUSED)
1053
return GEIS_STATUS_UNKNOWN_ERROR;
1058
_gxcb_reject_gesture(GeisBackend be GEIS_UNUSED,
1059
GeisGroup group GEIS_UNUSED,
1060
GeisGestureId gesture_id GEIS_UNUSED)
1062
return GEIS_STATUS_UNKNOWN_ERROR;