~chasedouglas/geis/fix-tap

« back to all changes in this revision

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

  • Committer: Stephen M. Webb
  • Date: 2011-01-24 16:51:34 UTC
  • mfrom: (101.1.5 geis2-add-xcb-backend)
  • Revision ID: stephen.webb@canonical.com-20110124165134-p2akyz71taptj6ly
Added XCB back end subproject.

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 Lesser General Public License
 
18
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 
19
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
20
 */
 
21
#include "geis_xcb_backend.h"
 
22
 
 
23
#include "geis_attr.h"
 
24
#include "geis_backend_protected.h"
 
25
#include "geis_class.h"
 
26
#include "geis_event.h"
 
27
#include "geis_logging.h"
 
28
#include "geis_private.h"
 
29
#include "grail_gestures.h"
 
30
#include <grail-types.h>
 
31
#include "xcb_gesture.h"
 
32
#include <X11/X.h>
 
33
#include <X11/Xlib-xcb.h>
 
34
#include <xcb/xcb.h>
 
35
 
 
36
 
 
37
typedef struct _GeisXcbBackend
 
38
{
 
39
  struct _GeisBackend  base;
 
40
  Geis                 geis;
 
41
  Display             *x11_display;
 
42
  xcb_connection_t    *xcb_connection;
 
43
  int                  xcb_fd;
 
44
} *GeisXcbBackend;
 
45
 
 
46
static void _finalize(GeisBackend g);
 
47
static void _fd_callback(int fd, GeisBackendMultiplexorEvent ev, void *ctx);
 
48
static GeisStatus _subscribe(GeisBackend be, GeisSubscription sub);
 
49
static GeisStatus _unsubscribe(GeisBackend be, GeisSubscription sub);
 
50
 
 
51
 
 
52
static struct _GeisBackendVtable be_vtbl = {
 
53
  _finalize,
 
54
  _subscribe,
 
55
  _unsubscribe
 
56
};
 
57
 
 
58
 
 
59
static int
 
60
_verify_xcb_version(xcb_connection_t *xcb_connection)
 
61
{
 
62
  int                                 is_valid_version = 0;
 
63
  xcb_gesture_query_version_cookie_t  version_cookie;
 
64
  xcb_gesture_query_version_reply_t  *version_reply = NULL;
 
65
  xcb_generic_error_t                *error = NULL;
 
66
 
 
67
  version_cookie = xcb_gesture_query_version(xcb_connection,
 
68
                                             XCB_GESTURE_MAJOR_VERSION,
 
69
                                             XCB_GESTURE_MINOR_VERSION);
 
70
  version_reply = xcb_gesture_query_version_reply(xcb_connection,
 
71
                                                  version_cookie,
 
72
                                                  &error);
 
73
  if (!version_reply)
 
74
  {
 
75
    geis_error("failed to receive XCB gesture version reply.");
 
76
    goto final_exit;
 
77
  }
 
78
 
 
79
  if (version_reply->major_version != XCB_GESTURE_MAJOR_VERSION
 
80
   && version_reply->minor_version != XCB_GESTURE_MINOR_VERSION)
 
81
  {
 
82
    geis_error("server supports unrecognized version: %d.%d",
 
83
               version_reply->major_version, version_reply->minor_version);
 
84
  }
 
85
  else
 
86
  {
 
87
    is_valid_version = 1;
 
88
  }
 
89
 
 
90
 free(version_reply);
 
91
final_exit:
 
92
 return is_valid_version;
 
93
}
 
94
 
 
95
 
 
96
void 
 
97
_finalize(GeisBackend g)
 
98
{
 
99
  GeisXcbBackend be = (GeisXcbBackend)g;
 
100
  free(be);
 
101
  geis_debug("XCB back end finalized");
 
102
}
 
103
 
 
104
 
 
105
/**
 
106
 * Dispatches events coming from XCB.
 
107
 */
 
108
static void
 
109
_xcb_dispatch(GeisXcbBackend be)
 
110
{
 
111
  geis_debug("begins");
 
112
  if (be->xcb_connection)
 
113
  {
 
114
    const xcb_query_extension_reply_t *extension_info;
 
115
    extension_info = xcb_get_extension_data(be->xcb_connection, &xcb_gesture_id);
 
116
    xcb_generic_event_t *event = NULL;
 
117
 
 
118
    while ((event = xcb_poll_for_event(be->xcb_connection)))
 
119
    {
 
120
      xcb_gesture_notify_event_t *gesture_event = NULL;
 
121
      if (event->response_type != GenericEvent) {
 
122
        geis_warning("received non-generic event type: %d",
 
123
                     event->response_type);
 
124
        continue;
 
125
      }
 
126
 
 
127
      gesture_event = (xcb_gesture_notify_event_t*)event;
 
128
      if (gesture_event->extension != extension_info->major_opcode)
 
129
      {
 
130
        geis_warning("received non-gesture extension event: %d",
 
131
                     gesture_event->extension);
 
132
        continue;
 
133
      }
 
134
 
 
135
      if (gesture_event->event_type != XCB_GESTURE_NOTIFY)
 
136
      {
 
137
        geis_warning("received unrecognized gesture event type: %d",
 
138
                     gesture_event->event_type);
 
139
        continue;
 
140
      }
 
141
    }
 
142
  }
 
143
  geis_debug("ends");
 
144
}
 
145
 
 
146
/** @todo implement this */
 
147
void
 
148
_fd_callback(int                          fd __attribute__((unused)),
 
149
             GeisBackendMultiplexorEvent  ev __attribute__((unused)),
 
150
             void                        *ctx)
 
151
{
 
152
  geis_debug("begins");
 
153
  GeisXcbBackend be = (GeisXcbBackend)ctx;
 
154
  _xcb_dispatch(be);
 
155
  geis_debug("ends");
 
156
}
 
157
 
 
158
 
 
159
/** @todo implement this */
 
160
static GeisStatus 
 
161
_subscribe(GeisBackend be, GeisSubscription sub)
 
162
{
 
163
  geis_debug("begins");
 
164
  GeisStatus status = GEIS_STATUS_NOT_SUPPORTED;
 
165
  geis_debug("ends");
 
166
  return status;
 
167
}
 
168
 
 
169
 
 
170
/** @todo implement this */
 
171
static GeisStatus 
 
172
_unsubscribe(GeisBackend be, GeisSubscription sub)
 
173
{
 
174
  geis_debug("begins");
 
175
  GeisStatus status = GEIS_STATUS_NOT_SUPPORTED;
 
176
  geis_debug("ends");
 
177
  return status;
 
178
}
 
179
 
 
180
 
 
181
/** @todo implement this */
 
182
static void
 
183
_report_xcb_devices(GeisXcbBackend be)
 
184
{
 
185
}
 
186
 
 
187
 
 
188
/*
 
189
 * Generates the events for gesture classes.
 
190
 */
 
191
static void
 
192
_report_grail_classes(GeisXcbBackend be)
 
193
{
 
194
  GeisGestureClass drag_class = geis_gesture_class_new(GEIS_GESTURE_DRAG,
 
195
                                                       GRAIL_TYPE_DRAG1);
 
196
  geis_xcb_backend_add_drag_attrs(drag_class);
 
197
  GeisEvent event_drag = geis_event_new(GEIS_EVENT_CLASS_AVAILABLE);
 
198
  GeisAttr  attr_drag = geis_attr_new(GEIS_EVENT_ATTRIBUTE_CLASS,
 
199
                                      GEIS_ATTR_TYPE_POINTER,
 
200
                                      drag_class);
 
201
  geis_event_add_attr(event_drag, attr_drag);
 
202
  geis_post_event(be->geis, event_drag);
 
203
 
 
204
  GeisGestureClass pinch_class = geis_gesture_class_new(GEIS_GESTURE_DRAG,
 
205
                                                        GRAIL_TYPE_PINCH1);
 
206
  geis_xcb_backend_add_pinch_attrs(pinch_class);
 
207
  GeisEvent event_pinch = geis_event_new(GEIS_EVENT_CLASS_AVAILABLE);
 
208
  GeisAttr  attr_pinch = geis_attr_new(GEIS_EVENT_ATTRIBUTE_CLASS,
 
209
                                      GEIS_ATTR_TYPE_POINTER,
 
210
                                      pinch_class);
 
211
  geis_event_add_attr(event_pinch, attr_pinch);
 
212
  geis_post_event(be->geis, event_pinch);
 
213
 
 
214
  GeisGestureClass rotate_class = geis_gesture_class_new(GEIS_GESTURE_DRAG,
 
215
                                                         GRAIL_TYPE_ROTATE1);
 
216
  geis_xcb_backend_add_rotate_attrs(rotate_class);
 
217
  GeisEvent event_rotate = geis_event_new(GEIS_EVENT_CLASS_AVAILABLE);
 
218
  GeisAttr  attr_rotate = geis_attr_new(GEIS_EVENT_ATTRIBUTE_CLASS,
 
219
                                      GEIS_ATTR_TYPE_POINTER,
 
220
                                      rotate_class);
 
221
  geis_event_add_attr(event_rotate, attr_rotate);
 
222
  geis_post_event(be->geis, event_rotate);
 
223
 
 
224
  GeisGestureClass tap_class = geis_gesture_class_new(GEIS_GESTURE_DRAG,
 
225
                                                      GRAIL_TYPE_TAP1);
 
226
  geis_xcb_backend_add_tap_attrs(tap_class);
 
227
  GeisEvent event_tap = geis_event_new(GEIS_EVENT_CLASS_AVAILABLE);
 
228
  GeisAttr  attr_tap = geis_attr_new(GEIS_EVENT_ATTRIBUTE_CLASS,
 
229
                                      GEIS_ATTR_TYPE_POINTER,
 
230
                                      tap_class);
 
231
  geis_event_add_attr(event_tap, attr_tap);
 
232
  geis_post_event(be->geis, event_tap);
 
233
}
 
234
 
 
235
 
 
236
GeisBackend
 
237
geis_xcb_backend_new(Geis geis,
 
238
                     GeisBoolean track_devices,
 
239
                     GeisBoolean track_classes)
 
240
{
 
241
  geis_debug("begins");
 
242
  GeisXcbBackend be = calloc(1, sizeof(struct _GeisXcbBackend));
 
243
  if (!be)
 
244
  {
 
245
    geis_error("failed to allocate GEIS XCB back end");
 
246
    goto final_exit;
 
247
  }
 
248
 
 
249
  geis_backend_init_base(&be->base, &be_vtbl, "GEIS2 XCB");
 
250
  be->geis = geis;
 
251
 
 
252
  be->x11_display = XOpenDisplay(NULL);
 
253
  if (!be->x11_display)
 
254
  {
 
255
    geis_error("error opening X server.");
 
256
    goto unwind_be;
 
257
  }
 
258
 
 
259
  be->xcb_connection = XGetXCBConnection(be->x11_display);
 
260
  if (!be->xcb_connection)
 
261
  {
 
262
    geis_error("error connecting to X server.");
 
263
    goto unwind_x11;
 
264
  }
 
265
  if (!_verify_xcb_version(be->xcb_connection))
 
266
  {
 
267
    goto unwind_x11;
 
268
  }
 
269
 
 
270
  be->xcb_fd = xcb_get_file_descriptor(be->xcb_connection);
 
271
  geis_multiplex_fd(be->geis, be->xcb_fd, _fd_callback, be);
 
272
 
 
273
  if (track_devices)
 
274
  {
 
275
    _report_xcb_devices(be);
 
276
  }
 
277
 
 
278
  if (track_classes)
 
279
  {
 
280
    _report_grail_classes(be);
 
281
  }
 
282
 
 
283
  goto final_exit;
 
284
 
 
285
unwind_x11:
 
286
  XCloseDisplay(be->x11_display);
 
287
unwind_be:
 
288
  free(be);
 
289
final_exit:
 
290
  geis_debug("ends");
 
291
  return &be->base;
 
292
}
 
293
 
 
294
 
 
295