~ubuntu-branches/ubuntu/precise/libgrip/precise-proposed

« back to all changes in this revision

Viewing changes to .pc/0002-window_mapped_cb.patch/src/gripgesturemanager.c

  • Committer: Bazaar Package Importer
  • Author(s): Chase Douglas
  • Date: 2011-10-11 16:37:09 UTC
  • Revision ID: james.westby@ubuntu.com-20111011163709-4s55voyt9qmb6gn3
Tags: 0.3.2-0ubuntu3.1
Fix crash (detected in eog) due to incorrect widget registrations
when a window is mapped (LP: #827958).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2010, 2011 Canonical, Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of either or both of the following licenses:
 
6
 *
 
7
 * 1) the GNU Lesser General Public License version 3, as published by the
 
8
 * Free Software Foundation; and/or
 
9
 * 2) the GNU Lesser General Public License version 2.1, as published by
 
10
 * the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful, but
 
13
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
14
 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
 
15
 * PURPOSE.  See the applicable version of the GNU Lesser General Public
 
16
 * License for more details.
 
17
 *
 
18
 * You should have received a copy of both the GNU Lesser General Public
 
19
 * License version 3 and version 2.1 along with this program.  If not, see
 
20
 * <http://www.gnu.org/licenses/>
 
21
 *
 
22
 * Authors:
 
23
 *    Cody Russell <crussell@canonical.com>
 
24
 */
 
25
 
 
26
#include "gripgesturemanager.h"
 
27
 
 
28
#include <gdk/gdkx.h>
 
29
#include <geis/geis.h>
 
30
#include "gripinputdevice.h"
 
31
 
 
32
typedef struct _GripGestureRegistration GripGestureRegistration;
 
33
typedef struct _GripGestureBinding      GripGestureBinding;
 
34
typedef struct _GripRegistrationRequest GripRegistrationRequest;
 
35
 
 
36
typedef GPtrArray GripDevices;
 
37
 
 
38
struct Registrations {
 
39
  GripGestureRegistration *touchscreen;
 
40
  GripGestureRegistration *touchpad;
 
41
  GripGestureRegistration *independent;
 
42
};
 
43
 
 
44
struct _GripGestureManagerPrivate
 
45
{
 
46
  GHashTable  *registered_windows;
 
47
  GList       *requests;
 
48
  GripDevices *devices;
 
49
};
 
50
 
 
51
/*
 
52
 * GripGestureBinding:
 
53
 * @type:
 
54
 * @widget:
 
55
 * @touches:
 
56
 * @callback:
 
57
 * @data:
 
58
 * @destroy:
 
59
 *
 
60
 * The mapping between a GEIS subscription and a GTK widget.  Sort of.
 
61
 */
 
62
struct _GripGestureBinding
 
63
{
 
64
  GripGestureType      type;
 
65
  GtkWidget           *widget;
 
66
  guint                touches;
 
67
  GripGestureCallback  callback;
 
68
  gpointer             data;
 
69
  GDestroyNotify       destroy;
 
70
};
 
71
 
 
72
/*
 
73
 * GripGestureRegistration:
 
74
 * @window: the GTK window
 
75
 * @bindings: a list of #GripGestureBinding
 
76
 * @gesture_list: a list the names of GEIS gestures beging subscribed to 
 
77
 * @instance:
 
78
 * @iochannel:
 
79
 *
 
80
 * A collection of all gesture subscriptions for all widgets contained within a
 
81
 * top-level GTK window.
 
82
 */
 
83
struct _GripGestureRegistration
 
84
{
 
85
  GtkWindow         *window;
 
86
  GList             *bindings;
 
87
  GPtrArray         *gesture_list;
 
88
  GeisInstance       instance;
 
89
  GIOChannel        *iochannel;
 
90
  int                iochannel_id;
 
91
};
 
92
 
 
93
struct _GripRegistrationRequest
 
94
{
 
95
  GripGestureManager *manager;
 
96
  GtkWidget          *widget;
 
97
  GripGestureType     gesture_type;
 
98
  GripDeviceType      device_type;
 
99
  gint                touch_points;
 
100
  GripGestureCallback callback;
 
101
  gpointer            user_data;
 
102
  GDestroyNotify      destroy;
 
103
};
 
104
 
 
105
static const gchar *geis_gesture_types[] = {
 
106
  GEIS_GESTURE_TYPE_DRAG1,
 
107
  GEIS_GESTURE_TYPE_DRAG2,
 
108
  GEIS_GESTURE_TYPE_DRAG3,
 
109
  GEIS_GESTURE_TYPE_DRAG4,
 
110
  GEIS_GESTURE_TYPE_DRAG5,
 
111
  GEIS_GESTURE_TYPE_PINCH1,
 
112
  GEIS_GESTURE_TYPE_PINCH2,
 
113
  GEIS_GESTURE_TYPE_PINCH3,
 
114
  GEIS_GESTURE_TYPE_PINCH4,
 
115
  GEIS_GESTURE_TYPE_PINCH5,
 
116
  GEIS_GESTURE_TYPE_ROTATE1,
 
117
  GEIS_GESTURE_TYPE_ROTATE2,
 
118
  GEIS_GESTURE_TYPE_ROTATE3,
 
119
  GEIS_GESTURE_TYPE_ROTATE4,
 
120
  GEIS_GESTURE_TYPE_ROTATE5,
 
121
  GEIS_GESTURE_TYPE_TAP1,
 
122
  GEIS_GESTURE_TYPE_TAP2,
 
123
  GEIS_GESTURE_TYPE_TAP3,
 
124
  GEIS_GESTURE_TYPE_TAP4,
 
125
  GEIS_GESTURE_TYPE_TAP5,
 
126
};
 
127
 
 
128
enum {
 
129
  DEVICE_AVAILABLE,
 
130
  DEVICE_UNAVAILABLE,
 
131
  SIGNAL_LAST
 
132
};
 
133
 
 
134
static guint signals[SIGNAL_LAST];
 
135
 
 
136
static void gesture_added (void              *cookie,
 
137
                           GeisGestureType    gesture_type,
 
138
                           GeisGestureId      gesture_id,
 
139
                           GeisSize           attr_count,
 
140
                           GeisGestureAttr   *attrs);
 
141
 
 
142
static void gesture_removed (void              *cookie,
 
143
                             GeisGestureType    gesture_type,
 
144
                             GeisGestureId      gesture_id,
 
145
                             GeisSize           attr_count,
 
146
                             GeisGestureAttr   *attrs);
 
147
 
 
148
static void gesture_start (void              *cookie,
 
149
                           GeisGestureType    gesture_type,
 
150
                           GeisGestureId      gesture_id,
 
151
                           GeisSize           attr_count,
 
152
                           GeisGestureAttr   *attrs);
 
153
 
 
154
static void gesture_update (void              *cookie,
 
155
                            GeisGestureType    gesture_type,
 
156
                            GeisGestureId      gesture_id,
 
157
                            GeisSize           attr_count,
 
158
                            GeisGestureAttr   *attrs);
 
159
 
 
160
static void gesture_finish (void              *cookie,
 
161
                            GeisGestureType    gesture_type,
 
162
                            GeisGestureId      gesture_id,
 
163
                            GeisSize           attr_count,
 
164
                            GeisGestureAttr   *attrs);
 
165
 
 
166
static void window_mapped_cb (GtkWidget       *widget,
 
167
                              GdkEvent        *event,
 
168
                              gpointer         user_data);
 
169
 
 
170
static GeisGestureFuncs gesture_funcs = {
 
171
  gesture_added,
 
172
  gesture_removed,
 
173
  gesture_start,
 
174
  gesture_update,
 
175
  gesture_finish
 
176
};
 
177
 
 
178
 
 
179
static void
 
180
device_added (void *cookie, GeisInputDeviceId id G_GNUC_UNUSED, void *attrs)
 
181
{
 
182
  GripGestureManager *gesture_manager = (GripGestureManager *) cookie;
 
183
  GripInputDevice *input_device = g_object_new (GRIP_TYPE_INPUT_DEVICE,
 
184
                                                "device-attrs", attrs,
 
185
                                                NULL);
 
186
 
 
187
  g_ptr_array_add(gesture_manager->priv->devices, input_device);
 
188
  g_signal_emit (gesture_manager, signals[DEVICE_AVAILABLE], 0, input_device);
 
189
}
 
190
 
 
191
 
 
192
static void
 
193
device_removed (void *cookie, GeisInputDeviceId id, void *attrs G_GNUC_UNUSED)
 
194
{
 
195
  guint i;
 
196
  GripGestureManager *gesture_manager = (GripGestureManager *) cookie;
 
197
  GripDevices *devices = gesture_manager->priv->devices;
 
198
 
 
199
  for (i = 0; i < devices->len; ++i)
 
200
  {
 
201
    GripInputDevice *input_device = g_ptr_array_index (devices, i);
 
202
    if (id == grip_input_device_get_id (input_device))
 
203
    {
 
204
      g_signal_emit (gesture_manager, signals[DEVICE_UNAVAILABLE], 0,
 
205
                     input_device);
 
206
      g_ptr_array_remove_index (devices, i);
 
207
      break;
 
208
    }
 
209
  }
 
210
}
 
211
 
 
212
 
 
213
static GeisInputFuncs input_funcs = {
 
214
  device_added,
 
215
  NULL,
 
216
  device_removed,
 
217
};
 
218
 
 
219
 
 
220
static void
 
221
grip_get_devices (GripGestureManager *gesture_manager)
 
222
{
 
223
  GeisXcbWinInfo xcb_win_info = {
 
224
    .display_name = NULL,
 
225
    .screenp = NULL,
 
226
    .window_id = 0,
 
227
  };
 
228
  GeisWinInfo win_info = {
 
229
    GEIS_XCB_FULL_WINDOW,
 
230
    &xcb_win_info,
 
231
  };
 
232
  GeisInstance instance;
 
233
  GeisStatus status;
 
234
 
 
235
  status = geis_init (&win_info, &instance);
 
236
  if (status != GEIS_STATUS_SUCCESS)
 
237
  {
 
238
    g_warning ("failed to determine device types\n");
 
239
    return;
 
240
  }
 
241
 
 
242
  status = geis_input_devices (instance, &input_funcs, gesture_manager);
 
243
  if (status != GEIS_STATUS_SUCCESS)
 
244
  {
 
245
    g_warning ("failed to determine device types\n");
 
246
    return;
 
247
  }
 
248
 
 
249
  status = geis_event_dispatch (instance);
 
250
  if (status != GEIS_STATUS_SUCCESS)
 
251
  {
 
252
    g_warning ("failed to determine device types\n");
 
253
    return;
 
254
  }
 
255
 
 
256
  geis_finish (instance);
 
257
}
 
258
 
 
259
G_DEFINE_TYPE (GripGestureManager, grip_gesture_manager, G_TYPE_OBJECT)
 
260
 
 
261
#define GRIP_GESTURE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GRIP_TYPE_GESTURE_MANAGER, GripGestureManagerPrivate))
 
262
 
 
263
static void
 
264
grip_gesture_manager_dispose (GObject *object G_GNUC_UNUSED)
 
265
{
 
266
}
 
267
 
 
268
 
 
269
static void
 
270
free_registration(GripGestureRegistration *reg)
 
271
{
 
272
  GList *tmp = NULL;
 
273
 
 
274
  if (!reg)
 
275
    return;
 
276
 
 
277
  geis_unsubscribe (reg->instance,
 
278
      (GeisGestureType*)reg->gesture_list->pdata);
 
279
 
 
280
  /* We don't need to free the values in the GPtrArray. */
 
281
  g_ptr_array_free (reg->gesture_list, TRUE);
 
282
 
 
283
  for (tmp = reg->bindings; tmp != NULL; tmp = tmp->next)
 
284
    {
 
285
      g_free (tmp->data);
 
286
    }
 
287
 
 
288
  g_list_free (reg->bindings);
 
289
}
 
290
 
 
291
/* Helper function needed to make things work with GTK. */
 
292
 
 
293
static void
 
294
free_registration_adapter (gpointer key G_GNUC_UNUSED,
 
295
                           gpointer value,
 
296
                           gpointer user_data G_GNUC_UNUSED)
 
297
{
 
298
  struct Registrations *regs = (struct Registrations *)value;
 
299
  free_registration(regs->touchscreen);
 
300
  free_registration(regs->touchpad);
 
301
  free_registration(regs->independent);
 
302
}
 
303
 
 
304
static void
 
305
grip_gesture_manager_finalize (GObject *object)
 
306
{
 
307
  GripGestureManagerPrivate *priv = GRIP_GESTURE_MANAGER_GET_PRIVATE (object);
 
308
 
 
309
  if (priv->registered_windows != NULL)
 
310
    {
 
311
      g_hash_table_foreach (priv->registered_windows,
 
312
                            free_registration_adapter,
 
313
                            NULL);
 
314
 
 
315
      g_hash_table_unref (priv->registered_windows);
 
316
      priv->registered_windows = NULL;
 
317
 
 
318
      g_ptr_array_foreach (priv->devices, (GFunc) g_object_unref, NULL);
 
319
      g_ptr_array_unref (priv->devices);
 
320
    }
 
321
}
 
322
 
 
323
static GObject *
 
324
grip_gesture_manager_constructor (GType                  type,
 
325
                                  guint                  n_params,
 
326
                                  GObjectConstructParam *params)
 
327
{
 
328
  static GObject *self = NULL;
 
329
  
 
330
  if (self == NULL)
 
331
  {
 
332
    self = G_OBJECT_CLASS (grip_gesture_manager_parent_class)->
 
333
                              constructor (type, n_params, params);
 
334
    g_object_add_weak_pointer (self, (gpointer) &self);
 
335
    grip_get_devices (GRIP_GESTURE_MANAGER (self));
 
336
  }
 
337
 
 
338
  return g_object_ref (self);
 
339
}
 
340
 
 
341
static void
 
342
grip_gesture_manager_class_init (GripGestureManagerClass *class)
 
343
{
 
344
  GObjectClass     *gobject_class;
 
345
 
 
346
  gobject_class = G_OBJECT_CLASS (class);
 
347
 
 
348
  grip_gesture_manager_parent_class = g_type_class_peek_parent (class);
 
349
 
 
350
  g_type_class_add_private (gobject_class, sizeof (GripGestureManagerPrivate));
 
351
 
 
352
  gobject_class->constructor = grip_gesture_manager_constructor;
 
353
  gobject_class->dispose     = grip_gesture_manager_dispose;
 
354
  gobject_class->finalize    = grip_gesture_manager_finalize;
 
355
 
 
356
  /**
 
357
   * GripGestureManager::device-available:
 
358
   * @gesture_manager: the #GripGestureManager sending the signal
 
359
   * @input_device: the new #GripInputDevice just added.
 
360
   *
 
361
   * Signals the availability of a new gesture-capable input device.
 
362
   */
 
363
  signals[DEVICE_AVAILABLE] = g_signal_new ("device-available",
 
364
                                            GRIP_TYPE_GESTURE_MANAGER,
 
365
                                            G_SIGNAL_RUN_LAST,
 
366
                                            0,
 
367
                                            NULL, NULL,
 
368
                                            g_cclosure_marshal_VOID__OBJECT,
 
369
                                            G_TYPE_NONE,
 
370
                                            1,
 
371
                                            GRIP_TYPE_INPUT_DEVICE);
 
372
 
 
373
  /**
 
374
   * GripGestureManager::device-unavailable:
 
375
   * @gesture_manager: the #GripGestureManager sending the signal
 
376
   * @input_device: the new #GripInputDevice just added.
 
377
   *
 
378
   * Signals the unavailability of a gesture-capable input device.
 
379
   */
 
380
  signals[DEVICE_UNAVAILABLE] = g_signal_new ("device-unavailable",
 
381
                                              GRIP_TYPE_GESTURE_MANAGER,
 
382
                                              G_SIGNAL_RUN_LAST,
 
383
                                              0,
 
384
                                              NULL, NULL,
 
385
                                              g_cclosure_marshal_VOID__OBJECT,
 
386
                                              G_TYPE_NONE,
 
387
                                              1,
 
388
                                              GRIP_TYPE_INPUT_DEVICE);
 
389
 
 
390
}
 
391
 
 
392
 
 
393
/*
 
394
 * device_id_to_input_device:
 
395
 * @gesture_manager: the #GripGestureManager
 
396
 * @device_id: the device ID
 
397
 *
 
398
 * Finds a known #GripInputDevice given a GEIS device identifier.
 
399
 *
 
400
 * Returns: a pointer to a #GripInputDevice or %NULL if not found.
 
401
 */
 
402
static GripInputDevice *
 
403
device_id_to_input_device (GripGestureManager *gesture_manager,
 
404
                           GeisInputDeviceId   device_id)
 
405
{
 
406
  guint j;
 
407
  GripInputDevice *input_device = NULL;
 
408
 
 
409
  for (j = 0; j < gesture_manager->priv->devices->len; ++j)
 
410
  {
 
411
    GripInputDevice *device;
 
412
 
 
413
    device = g_ptr_array_index (gesture_manager->priv->devices, j);
 
414
    if (grip_input_device_get_id (device) == device_id)
 
415
    {
 
416
      input_device = device;
 
417
      break;
 
418
    }
 
419
  }
 
420
  return input_device;
 
421
}
 
422
 
 
423
/*
 
424
 * registration_for_input_device:
 
425
 * @registrations: A collection of #GripGestureRegistration
 
426
 * @input_device: A pointer to a #GripInputDevice
 
427
 *
 
428
 * Determines which #GripGestureRegistration to use dependeng on properties of
 
429
 * the #GripInputDevice.
 
430
 *
 
431
 * Returns: a pointer to a #GripGestureRegistration or %NULL if not found.
 
432
 */
 
433
static GripGestureRegistration *
 
434
registration_for_input_device (struct Registrations *registrations,
 
435
                               GripInputDevice      *input_device)
 
436
{
 
437
  GripDeviceType device_type = grip_get_device_type(input_device);
 
438
  if (device_type == GRIP_DEVICE_TOUCHSCREEN)
 
439
  {
 
440
    return registrations->touchscreen;
 
441
  }
 
442
  else if (GRIP_DEVICE_TOUCHPAD)
 
443
  {
 
444
    return registrations->touchpad;
 
445
  }
 
446
  else if (GRIP_DEVICE_INDEPENDENT)
 
447
  {
 
448
    return registrations->independent;
 
449
  }
 
450
  return NULL;
 
451
}
 
452
 
 
453
 
 
454
static gint
 
455
pinch_gesture_handle_properties (GripEventGesturePinch *event,
 
456
                                 GeisSize               attr_count,
 
457
                                 GeisGestureAttr       *attrs)
 
458
{
 
459
  guint i = 0;
 
460
  gint touches = 0;
 
461
 
 
462
  for (i = 0; i < attr_count; ++i)
 
463
    {
 
464
      if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TOUCHES) == 0 &&
 
465
          attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
 
466
        {
 
467
          touches = attrs[i].integer_val;
 
468
        }
 
469
      if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TIMESTAMP) == 0 &&
 
470
          attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
 
471
        {
 
472
          event->timestamp = attrs[i].integer_val;
 
473
        }
 
474
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_X) == 0 &&
 
475
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
476
        {
 
477
          event->focus_x = attrs[i].float_val;
 
478
        }
 
479
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_Y) == 0 &&
 
480
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
481
        {
 
482
          event->focus_y = attrs[i].float_val;
 
483
        }
 
484
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_RADIUS_DELTA) == 0 &&
 
485
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
486
        {
 
487
          event->radius_delta = attrs[i].float_val;
 
488
        }
 
489
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_RADIAL_VELOCITY) == 0 &&
 
490
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
491
        {
 
492
          event->radial_velocity = attrs[i].float_val;
 
493
        }
 
494
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_RADIUS) == 0 &&
 
495
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
496
        {
 
497
          event->radius = attrs[i].float_val;
 
498
        }
 
499
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_X) == 0 &&
 
500
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
501
        {
 
502
          event->position_x = attrs[i].float_val;
 
503
        }
 
504
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_Y) == 0 &&
 
505
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
506
        {
 
507
          event->position_y = attrs[i].float_val;
 
508
        }
 
509
    }
 
510
 
 
511
  return touches;
 
512
}
 
513
 
 
514
static gint
 
515
drag_gesture_handle_properties (GripEventGestureDrag *event,
 
516
                                GeisSize              attr_count,
 
517
                                GeisGestureAttr      *attrs)
 
518
{
 
519
  guint i;
 
520
  gint touches = 0;
 
521
 
 
522
  for (i = 0; i < attr_count; ++i)
 
523
    {
 
524
      if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TOUCHES) == 0 &&
 
525
          attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
 
526
        {
 
527
          touches = attrs[i].integer_val;
 
528
        }
 
529
      if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TIMESTAMP) == 0 &&
 
530
          attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
 
531
        {
 
532
          event->timestamp = attrs[i].integer_val;
 
533
        }
 
534
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_X) == 0 &&
 
535
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
536
        {
 
537
          event->focus_x = attrs[i].float_val;
 
538
        }
 
539
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_Y) == 0 &&
 
540
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
541
        {
 
542
          event->focus_y = attrs[i].float_val;
 
543
        }
 
544
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_DELTA_X) == 0 &&
 
545
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
546
        {
 
547
          event->delta_x = attrs[i].float_val;
 
548
        }
 
549
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_DELTA_Y) == 0 &&
 
550
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
551
        {
 
552
          event->delta_y = attrs[i].float_val;
 
553
        }
 
554
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_VELOCITY_X) == 0 &&
 
555
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
556
        {
 
557
          event->velocity_x = attrs[i].float_val;
 
558
        }
 
559
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_VELOCITY_Y) == 0 &&
 
560
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
561
        {
 
562
          event->velocity_y = attrs[i].float_val;
 
563
        }
 
564
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_X) == 0 &&
 
565
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
566
        {
 
567
          event->position_x = attrs[i].float_val;
 
568
        }
 
569
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_Y) == 0 &&
 
570
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
571
        {
 
572
          event->position_y = attrs[i].float_val;
 
573
        }
 
574
    }
 
575
 
 
576
  return touches;
 
577
}
 
578
 
 
579
static gint
 
580
rotate_gesture_handle_properties (GripEventGestureRotate *event,
 
581
                                  GeisSize                attr_count,
 
582
                                  GeisGestureAttr        *attrs)
 
583
{
 
584
  guint i;
 
585
  gint touches = 0;
 
586
 
 
587
  for (i = 0; i < attr_count; ++i)
 
588
    {
 
589
      if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TOUCHES) == 0 &&
 
590
          attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
 
591
        {
 
592
          touches = attrs[i].integer_val;
 
593
        }
 
594
      if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TIMESTAMP) == 0 &&
 
595
          attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
 
596
        {
 
597
          event->timestamp = attrs[i].integer_val;
 
598
        }
 
599
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_X) == 0 &&
 
600
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
601
        {
 
602
          event->focus_x = attrs[i].float_val;
 
603
        }
 
604
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_Y) == 0 &&
 
605
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
606
        {
 
607
          event->focus_y = attrs[i].float_val;
 
608
        }
 
609
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_ANGLE_DELTA) == 0 &&
 
610
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
611
        {
 
612
          event->angle_delta = attrs[i].float_val;
 
613
        }
 
614
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_ANGULAR_VELOCITY) == 0 &&
 
615
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
616
        {
 
617
          event->angular_velocity = attrs[i].float_val;
 
618
        }
 
619
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_ANGLE) == 0 &&
 
620
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
621
        {
 
622
          event->angle = attrs[i].float_val;
 
623
        }
 
624
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_X) == 0 &&
 
625
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
626
        {
 
627
          event->position_x = attrs[i].float_val;
 
628
        }
 
629
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_Y) == 0 &&
 
630
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
631
        {
 
632
          event->position_y = attrs[i].float_val;
 
633
        }
 
634
    }
 
635
 
 
636
  return touches;
 
637
}
 
638
 
 
639
static gint
 
640
tap_gesture_handle_properties (GripEventGestureTap *event,
 
641
                               GeisSize             attr_count,
 
642
                               GeisGestureAttr     *attrs)
 
643
{
 
644
  guint i;
 
645
  gint touches = 0;
 
646
 
 
647
  for (i = 0; i < attr_count; ++i)
 
648
    {
 
649
      if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TOUCHES) == 0 &&
 
650
          attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
 
651
        {
 
652
          touches = attrs[i].integer_val;
 
653
        }
 
654
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TIMESTAMP) == 0 &&
 
655
          attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
 
656
        {
 
657
          event->timestamp = attrs[i].integer_val;
 
658
        }
 
659
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_X) == 0 &&
 
660
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
661
        {
 
662
          event->focus_x = attrs[i].float_val;
 
663
        }
 
664
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_Y) == 0 &&
 
665
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
666
        {
 
667
          event->focus_y = attrs[i].float_val;
 
668
        }
 
669
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_X) == 0 &&
 
670
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
671
        {
 
672
          event->position_x = attrs[i].float_val;
 
673
        }
 
674
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_Y) == 0 &&
 
675
               attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
 
676
        {
 
677
          event->position_y = attrs[i].float_val;
 
678
        }
 
679
      else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TAP_TIME) == 0 &&
 
680
               attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
 
681
        {
 
682
          event->tap_time = attrs[i].float_val;
 
683
        }
 
684
    }
 
685
 
 
686
  return touches;
 
687
}
 
688
 
 
689
static void
 
690
gesture_added (void              *cookie G_GNUC_UNUSED,
 
691
               GeisGestureType    gesture_type G_GNUC_UNUSED,
 
692
               GeisGestureId      gesture_id G_GNUC_UNUSED,
 
693
               GeisSize           attr_count G_GNUC_UNUSED,
 
694
               GeisGestureAttr   *attrs G_GNUC_UNUSED)
 
695
{
 
696
}
 
697
 
 
698
static void
 
699
gesture_removed (void              *cookie G_GNUC_UNUSED,
 
700
                 GeisGestureType    gesture_type G_GNUC_UNUSED,
 
701
                 GeisGestureId      gesture_id G_GNUC_UNUSED,
 
702
                 GeisSize           attr_count G_GNUC_UNUSED,
 
703
                 GeisGestureAttr   *attrs G_GNUC_UNUSED)
 
704
{
 
705
}
 
706
 
 
707
static gboolean
 
708
matches_widget (GtkWidget *widget,
 
709
                GdkWindow *window,
 
710
                gint       x,
 
711
                gint       y)
 
712
{
 
713
  GtkAllocation alloc;
 
714
  gint ax, ay;
 
715
 
 
716
  gtk_widget_get_allocation (widget, &alloc);
 
717
  gdk_window_get_root_coords (window, alloc.x, alloc.y, &ax, &ay);
 
718
 
 
719
  return (x >= ax && x < ax + alloc.width && y >= ay && y < ay + alloc.height);
 
720
}
 
721
 
 
722
 
 
723
/*
 
724
 * process_gesture:
 
725
 * @cookie:
 
726
 * @type:
 
727
 * @id:
 
728
 * @attr_count:
 
729
 * @attrs:
 
730
 * @time_type:
 
731
 *
 
732
 * The generic gesture event dispatch engine.
 
733
 */
 
734
static void
 
735
process_gesture (void              *cookie,
 
736
                 GeisGestureType    type,
 
737
                 GeisGestureId      id,
 
738
                 GeisSize           attr_count,
 
739
                 GeisGestureAttr   *attrs,
 
740
                 GripTimeType       time_type)
 
741
{
 
742
  GripGestureManager *manager = (GripGestureManager *) cookie;
 
743
  GripInputDevice *input_device = NULL;
 
744
  GtkWindow *gtk_window = NULL;
 
745
  struct Registrations *registrations = NULL;
 
746
  GripGestureRegistration *reg = NULL;
 
747
  GList *l = NULL;
 
748
  GeisSize i;
 
749
 
 
750
  for (i = 0; i < attr_count; ++i)
 
751
  {
 
752
    if (0 == g_strcmp0(attrs[i].name, GEIS_GESTURE_ATTRIBUTE_DEVICE_ID))
 
753
    {
 
754
      input_device = device_id_to_input_device(manager, attrs[i].integer_val);
 
755
    }
 
756
    else if (0 == g_strcmp0(attrs[i].name, GEIS_GESTURE_ATTRIBUTE_EVENT_WINDOW_ID))
 
757
    {
 
758
      GHashTableIter iter;
 
759
      GtkWidget *key;
 
760
      struct Registrations *value;
 
761
      guint window_id = attrs[i].integer_val;
 
762
 
 
763
      g_hash_table_iter_init (&iter, manager->priv->registered_windows);
 
764
      while (g_hash_table_iter_next(&iter, (gpointer *)&key, (gpointer *)&value)) 
 
765
      {
 
766
        if (GDK_WINDOW_XID (gtk_widget_get_window (key)) == window_id)
 
767
        {
 
768
          gtk_window = (GtkWindow *)key;
 
769
          break;
 
770
        }
 
771
      }
 
772
    }
 
773
  }
 
774
  g_return_if_fail(input_device != NULL);
 
775
  g_return_if_fail(gtk_window != NULL);
 
776
 
 
777
  registrations = g_hash_table_lookup (manager->priv->registered_windows, gtk_window);
 
778
  g_return_if_fail(registrations != NULL);
 
779
  reg = registration_for_input_device (registrations, input_device);
 
780
  g_return_if_fail(reg != NULL);
 
781
 
 
782
  for (l = reg->bindings; l != NULL; l = l->next)
 
783
    {
 
784
      GripGestureBinding *binding = (GripGestureBinding *)l->data;
 
785
 
 
786
      if (binding->type == type)
 
787
        {
 
788
          GripGestureEvent *event = grip_gesture_event_new (type);
 
789
 
 
790
          if (type == GRIP_GESTURE_DRAG)
 
791
            {
 
792
              GripEventGestureDrag *drag = (GripEventGestureDrag *)event;
 
793
 
 
794
              drag->type    = type;
 
795
              drag->id      = id;
 
796
              drag->input_device = input_device;
 
797
              drag->fingers = drag_gesture_handle_properties (drag,
 
798
                  attr_count,
 
799
                  attrs);
 
800
 
 
801
              if (drag->fingers == (gint)binding->touches)
 
802
                {
 
803
                  if (matches_widget (binding->widget,
 
804
                                      gtk_widget_get_window(GTK_WIDGET (reg->window)),
 
805
                                      (gint)drag->focus_x,
 
806
                                      (gint)drag->focus_y))
 
807
                    {
 
808
                      binding->callback (binding->widget,
 
809
                                         time_type,
 
810
                                         event,
 
811
                                         binding->data);
 
812
                    }
 
813
                }
 
814
            }
 
815
          else if (type == GRIP_GESTURE_PINCH)
 
816
            {
 
817
              GripEventGesturePinch *pinch = (GripEventGesturePinch *)event;
 
818
 
 
819
              pinch->type    = type;
 
820
              pinch->id      = id;
 
821
              pinch->input_device = input_device;
 
822
              pinch->fingers = pinch_gesture_handle_properties (pinch,
 
823
                  attr_count,
 
824
                  attrs);
 
825
 
 
826
              if (pinch->fingers == binding->touches)
 
827
                {
 
828
                  if (matches_widget (binding->widget,
 
829
                                      gtk_widget_get_window(GTK_WIDGET (reg->window)),
 
830
                                      (gint)pinch->focus_x,
 
831
                                      (gint)pinch->focus_y))
 
832
                    {
 
833
                      binding->callback (binding->widget,
 
834
                                         time_type,
 
835
                                         event,
 
836
                                         binding->data);
 
837
                    }
 
838
                }
 
839
            }
 
840
          else if (type == GRIP_GESTURE_ROTATE)
 
841
            {
 
842
              GripEventGestureRotate *rotate = (GripEventGestureRotate *)event;
 
843
 
 
844
              rotate->type    = type;
 
845
              rotate->id      = id;
 
846
              rotate->input_device = input_device;
 
847
              rotate->fingers = rotate_gesture_handle_properties (rotate,
 
848
                  attr_count,
 
849
                  attrs);
 
850
 
 
851
              if (rotate->fingers == binding->touches)
 
852
                {
 
853
                  if (matches_widget (binding->widget,
 
854
                                      gtk_widget_get_window(GTK_WIDGET (reg->window)),
 
855
                                      (gint)rotate->focus_x,
 
856
                                      (gint)rotate->focus_y))
 
857
                    {
 
858
                      binding->callback (binding->widget,
 
859
                                         time_type,
 
860
                                         event,
 
861
                                         binding->data);
 
862
                    }
 
863
                }
 
864
            }
 
865
          else if (type == GRIP_GESTURE_TAP)
 
866
            {
 
867
              GripEventGestureTap *tap = (GripEventGestureTap *)event;
 
868
 
 
869
              tap->type    = type;
 
870
              tap->id      = id;
 
871
              tap->input_device = input_device;
 
872
              tap->fingers = tap_gesture_handle_properties (tap,
 
873
                  attr_count,
 
874
                  attrs);
 
875
 
 
876
              if (tap->fingers == binding->touches)
 
877
                {
 
878
                  if (matches_widget (binding->widget,
 
879
                                      gtk_widget_get_window(GTK_WIDGET (reg->window)),
 
880
                                      (gint)tap->focus_x,
 
881
                                      (gint)tap->focus_y))
 
882
                    {
 
883
                      binding->callback (binding->widget,
 
884
                                         time_type,
 
885
                                         event,
 
886
                                         binding->data);
 
887
                    }
 
888
                }
 
889
            }
 
890
 
 
891
          grip_gesture_event_free (event);
 
892
        }
 
893
    }
 
894
}
 
895
 
 
896
static void
 
897
gesture_start (void              *cookie,
 
898
               GeisGestureType    type,
 
899
               GeisGestureId      id,
 
900
               GeisSize           attr_count,
 
901
               GeisGestureAttr   *attrs)
 
902
{
 
903
  process_gesture(cookie, type, id, attr_count, attrs, GRIP_TIME_START);
 
904
}
 
905
 
 
906
static void
 
907
gesture_update (void              *cookie,
 
908
                GeisGestureType    type,
 
909
                GeisGestureId      id,
 
910
                GeisSize           attr_count,
 
911
                GeisGestureAttr   *attrs)
 
912
{
 
913
  process_gesture(cookie, type, id, attr_count, attrs, GRIP_TIME_UPDATE);
 
914
}
 
915
 
 
916
static void
 
917
gesture_finish (void              *cookie,
 
918
                GeisGestureType    type,
 
919
                GeisGestureId      id,
 
920
                GeisSize           attr_count,
 
921
                GeisGestureAttr   *attrs)
 
922
{
 
923
  process_gesture(cookie, type, id, attr_count, attrs, GRIP_TIME_END);
 
924
}
 
925
 
 
926
static void
 
927
grip_gesture_manager_init (GripGestureManager *item)
 
928
{
 
929
  GripGestureManagerPrivate *priv;
 
930
 
 
931
  priv = item->priv = GRIP_GESTURE_MANAGER_GET_PRIVATE (item);
 
932
 
 
933
  priv->registered_windows = g_hash_table_new (g_direct_hash, g_direct_equal);
 
934
 
 
935
  priv->devices = g_ptr_array_new ();
 
936
}
 
937
 
 
938
static gboolean
 
939
io_callback (GIOChannel   *source G_GNUC_UNUSED,
 
940
             GIOCondition  condition G_GNUC_UNUSED,
 
941
             gpointer      data)
 
942
{
 
943
  GripGestureRegistration *reg = (GripGestureRegistration *)data;
 
944
 
 
945
  geis_event_dispatch (reg->instance);
 
946
 
 
947
  return TRUE;
 
948
}
 
949
 
 
950
static void
 
951
destroy_registration(GripGestureRegistration *reg)
 
952
{
 
953
  GList *list;
 
954
 
 
955
  for (list = reg->bindings; list != NULL; list = list->next)
 
956
    {
 
957
      GripGestureBinding *binding = (GripGestureBinding *)list->data;
 
958
 
 
959
      if (binding->destroy)
 
960
        {
 
961
          GDestroyNotify d = binding->destroy;
 
962
 
 
963
          d (binding->data);
 
964
        }
 
965
 
 
966
      g_free (binding);
 
967
    }
 
968
 
 
969
  g_list_free (reg->bindings);
 
970
 
 
971
  g_io_channel_shutdown (reg->iochannel, FALSE, NULL);
 
972
  g_source_remove (reg->iochannel_id);
 
973
  g_io_channel_unref (reg->iochannel);
 
974
 
 
975
  geis_finish (reg->instance);
 
976
 
 
977
  reg->instance = NULL;
 
978
  reg->iochannel = NULL;
 
979
}
 
980
 
 
981
static void
 
982
window_destroyed_cb (GtkWidget *object,
 
983
                     gpointer   user_data)
 
984
{
 
985
  GripGestureManager *manager = (GripGestureManager *)user_data;
 
986
  GripGestureManagerPrivate *priv = manager->priv;
 
987
  struct Registrations *reg = g_hash_table_lookup (priv->registered_windows, object);
 
988
 
 
989
  if (!reg)
 
990
    return;
 
991
 
 
992
  destroy_registration(reg->touchpad);
 
993
  destroy_registration(reg->touchscreen);
 
994
  destroy_registration(reg->independent);
 
995
 
 
996
  g_hash_table_remove (priv->registered_windows, object);
 
997
  g_free (reg);
 
998
}
 
999
 
 
1000
static const gchar *
 
1001
grip_type_to_geis_type (GripGestureType gesture_type,
 
1002
                        gint            touch_points)
 
1003
{
 
1004
  /* grail taps begin at 15, so let's convert that into something we
 
1005
   * can index in geis_gesture_types. */
 
1006
  int t = gesture_type == 15 ? 3 : gesture_type;
 
1007
 
 
1008
  return geis_gesture_types[(t * 5 + touch_points) - 1];
 
1009
}
 
1010
 
 
1011
 
 
1012
/* Public API */
 
1013
GripGestureManager *
 
1014
grip_gesture_manager_get (void)
 
1015
{
 
1016
  return g_object_new (GRIP_TYPE_GESTURE_MANAGER, NULL);
 
1017
}
 
1018
 
 
1019
 
 
1020
static void
 
1021
grip_devices_for_type (GripDeviceType type, GArray *selection,
 
1022
                       GripDevices *devices)
 
1023
{
 
1024
  guint i;
 
1025
 
 
1026
  for (i = 0; i < devices->len; ++i)
 
1027
  {
 
1028
    GripInputDevice *input_device = g_ptr_array_index (devices, i);
 
1029
    GeisInputDeviceId id = grip_input_device_get_id (input_device);
 
1030
    GripDeviceType device_type= grip_get_device_type(input_device);
 
1031
 
 
1032
    if ((type & GRIP_DEVICE_TOUCHSCREEN) && device_type == GRIP_DEVICE_TOUCHSCREEN)
 
1033
    {
 
1034
      g_array_append_val (selection, id);
 
1035
    }
 
1036
    if ((type & GRIP_DEVICE_TOUCHPAD) && device_type == GRIP_DEVICE_TOUCHPAD)
 
1037
    {
 
1038
      g_array_append_val (selection, id);
 
1039
    }
 
1040
    if ((type & GRIP_DEVICE_INDEPENDENT) && device_type == GRIP_DEVICE_INDEPENDENT)
 
1041
    {
 
1042
      g_array_append_val (selection, id);
 
1043
    }
 
1044
  }
 
1045
}
 
1046
 
 
1047
/*
 
1048
 * new_window_registration:
 
1049
 * @manager: a GripGestureManager
 
1050
 * @toplevel: a toplevel #GtkWindow
 
1051
 *
 
1052
 * Constructs a new #GripGestureRegistration for a #GtkWidget.
 
1053
 */
 
1054
static GripGestureRegistration *
 
1055
new_window_registration(GripGestureManager *manager,
 
1056
                        GtkWidget          *toplevel)
 
1057
{
 
1058
  GripGestureRegistration *reg;
 
1059
  GeisInstance  instance;
 
1060
  gint fd = -1;
 
1061
  GeisXcbWinInfo xcb_win_info = {
 
1062
    .display_name = NULL,
 
1063
    .screenp      = NULL,
 
1064
    .window_id    = GDK_WINDOW_XID (gtk_widget_get_window(toplevel))
 
1065
  };
 
1066
  GeisWinInfo win_info = {
 
1067
    GEIS_XCB_FULL_WINDOW,
 
1068
    &xcb_win_info
 
1069
  };
 
1070
 
 
1071
  if (geis_init (&win_info, &instance) != GEIS_STATUS_SUCCESS)
 
1072
    {
 
1073
      g_warning ("Failed to initialize gesture manager.");
 
1074
      return NULL;
 
1075
    }
 
1076
 
 
1077
  if (geis_configuration_supported (instance,
 
1078
                                    GEIS_CONFIG_UNIX_FD) != GEIS_STATUS_SUCCESS)
 
1079
    {
 
1080
      g_warning ("Gesture manager does not support UNIX fd.");
 
1081
      return NULL;
 
1082
    }
 
1083
 
 
1084
  if (geis_configuration_get_value (instance,
 
1085
                                    GEIS_CONFIG_UNIX_FD,
 
1086
                                    &fd) != GEIS_STATUS_SUCCESS)
 
1087
    {
 
1088
      g_error ("Gesture manager failed to obtain UNIX fd.");
 
1089
      return NULL;
 
1090
    }
 
1091
 
 
1092
  reg = g_new0 (GripGestureRegistration, 1);
 
1093
 
 
1094
  reg->window   = GTK_WINDOW (toplevel);
 
1095
  reg->instance = instance;
 
1096
 
 
1097
  g_signal_connect (toplevel,
 
1098
                    "destroy",
 
1099
                    G_CALLBACK (window_destroyed_cb),
 
1100
                    manager);
 
1101
 
 
1102
  reg->iochannel = g_io_channel_unix_new (fd);
 
1103
  reg->iochannel_id = g_io_add_watch (reg->iochannel,
 
1104
                                      G_IO_IN,
 
1105
                                      io_callback,
 
1106
                                      reg);
 
1107
  reg->gesture_list = g_ptr_array_new ();
 
1108
 
 
1109
  return reg;
 
1110
}
 
1111
 
 
1112
static void
 
1113
bind_registration(GripGestureManager *manager,
 
1114
    GripGestureRegistration *reg,
 
1115
    GtkWidget               *widget,
 
1116
    GripGestureType         gesture_type,
 
1117
    GripDeviceType          device_type,
 
1118
    gint                    touch_points,
 
1119
    GripGestureCallback     callback,
 
1120
    gpointer                user_data,
 
1121
    GDestroyNotify          destroy)
 
1122
{
 
1123
  GripGestureManagerPrivate *priv;
 
1124
  GripGestureBinding *binding;
 
1125
  GArray *devices;
 
1126
 
 
1127
  priv = manager->priv;
 
1128
 
 
1129
  if (reg->gesture_list->len)
 
1130
    g_ptr_array_remove_index (reg->gesture_list,
 
1131
                              reg->gesture_list->len - 1);
 
1132
 
 
1133
  devices = g_array_new (TRUE, FALSE, sizeof(GeisInputDeviceId));
 
1134
  grip_devices_for_type(device_type, devices, priv->devices);
 
1135
  if (devices->len == 0) {
 
1136
      g_array_free(devices, TRUE);
 
1137
      return;
 
1138
  }
 
1139
 
 
1140
  g_ptr_array_add (reg->gesture_list,
 
1141
                   (gchar *)grip_type_to_geis_type (gesture_type, touch_points));
 
1142
  g_ptr_array_add (reg->gesture_list,
 
1143
                   NULL);
 
1144
 
 
1145
  geis_subscribe (reg->instance,
 
1146
                  (GeisInputDeviceId *)(void *)devices->data,
 
1147
                  (const char**)reg->gesture_list->pdata,
 
1148
                  &gesture_funcs,
 
1149
                  manager);
 
1150
 
 
1151
  g_array_unref (devices);
 
1152
 
 
1153
  /* XXX - check for duplicates in reg->bindings first */
 
1154
  binding = g_new0 (GripGestureBinding, 1);
 
1155
 
 
1156
  binding->type     = gesture_type;
 
1157
  binding->widget   = widget;
 
1158
  binding->touches  = touch_points;
 
1159
  binding->callback = callback;
 
1160
  binding->data     = user_data;
 
1161
  binding->destroy  = destroy;
 
1162
 
 
1163
  reg->bindings = g_list_append (reg->bindings, binding);
 
1164
}
 
1165
 
 
1166
/*
 
1167
 * register_internal:
 
1168
 * @manager: the @GripGestureManager
 
1169
 * @widget: the GtkWidget to be bound
 
1170
 * @gesture_type: the type of gesture to subscribe for
 
1171
 * @device_type: the type of input device to subscribe for
 
1172
 * @touch_points: 
 
1173
 * @callback: the callback to be invoked on gesture events
 
1174
 * @user_data: the callbackl context to be passed back on gesture events
 
1175
 * @destroy:
 
1176
 *
 
1177
 * Binds or rebinds a gesture subscription for a widget.
 
1178
 */
 
1179
static void
 
1180
register_internal (GripGestureManager *manager,
 
1181
                   GtkWidget          *widget,
 
1182
                   GripGestureType     gesture_type,
 
1183
                   GripDeviceType      device_type,
 
1184
                   gint                touch_points,
 
1185
                   GripGestureCallback callback,
 
1186
                   gpointer            user_data,
 
1187
                   GDestroyNotify      destroy)
 
1188
{
 
1189
  GripGestureManagerPrivate *priv;
 
1190
  GtkWidget *toplevel;
 
1191
  struct Registrations *registrations;
 
1192
 
 
1193
  g_return_if_fail (GRIP_IS_GESTURE_MANAGER (manager));
 
1194
  g_return_if_fail (GTK_IS_WIDGET (widget));
 
1195
 
 
1196
  toplevel = gtk_widget_get_toplevel (widget);
 
1197
 
 
1198
  g_return_if_fail (GTK_IS_WINDOW (toplevel));
 
1199
 
 
1200
  priv = manager->priv;
 
1201
 
 
1202
  if (!(registrations = g_hash_table_lookup (priv->registered_windows, toplevel)))
 
1203
    {
 
1204
      registrations = g_new(struct Registrations, 1);
 
1205
      registrations->touchscreen = new_window_registration(manager, toplevel);
 
1206
      registrations->touchpad = new_window_registration(manager, toplevel);
 
1207
      registrations->independent = new_window_registration(manager, toplevel);
 
1208
 
 
1209
      if (registrations->touchscreen == NULL ||
 
1210
          registrations->touchpad == NULL ||
 
1211
          registrations->independent == NULL)
 
1212
        return;
 
1213
    }
 
1214
  else
 
1215
    {
 
1216
      if (device_type & GRIP_DEVICE_TOUCHSCREEN)
 
1217
        geis_unsubscribe (registrations->touchscreen->instance,
 
1218
            (GeisGestureType*)registrations->touchscreen->gesture_list->pdata);
 
1219
      if (device_type & GRIP_DEVICE_TOUCHPAD)
 
1220
        geis_unsubscribe (registrations->touchpad->instance,
 
1221
            (GeisGestureType*)registrations->touchpad->gesture_list->pdata);
 
1222
      if (device_type & GRIP_DEVICE_INDEPENDENT)
 
1223
        geis_unsubscribe (registrations->independent->instance,
 
1224
            (GeisGestureType*)registrations->independent->gesture_list->pdata);
 
1225
    }
 
1226
 
 
1227
  if (device_type & GRIP_DEVICE_TOUCHSCREEN)
 
1228
    bind_registration(manager,
 
1229
        registrations->touchscreen, widget, gesture_type, GRIP_DEVICE_TOUCHSCREEN, touch_points,
 
1230
        callback, user_data, destroy);
 
1231
 
 
1232
  if (device_type & GRIP_DEVICE_TOUCHPAD)
 
1233
    bind_registration(manager,
 
1234
        registrations->touchpad, widget, gesture_type, GRIP_DEVICE_TOUCHPAD, touch_points,
 
1235
        callback, user_data, destroy);
 
1236
 
 
1237
  if (device_type & GRIP_DEVICE_INDEPENDENT)
 
1238
    bind_registration(manager,
 
1239
        registrations->independent, widget, gesture_type, GRIP_DEVICE_INDEPENDENT, touch_points,
 
1240
        callback, user_data, destroy);
 
1241
  g_hash_table_insert (priv->registered_windows,
 
1242
                       toplevel,
 
1243
                       registrations);
 
1244
}
 
1245
 
 
1246
static void
 
1247
toplevel_notify_cb (GtkWidget    *widget,
 
1248
                    GParamSpec   *pspec,
 
1249
                    gpointer      user_data)
 
1250
{
 
1251
  if (pspec->name == g_intern_static_string ("parent"))
 
1252
    {
 
1253
      GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
 
1254
      GripRegistrationRequest *req = (GripRegistrationRequest *)user_data;
 
1255
 
 
1256
      if (GTK_IS_WINDOW (toplevel))
 
1257
        {
 
1258
          g_signal_handlers_disconnect_by_func (widget,
 
1259
                                                G_CALLBACK (toplevel_notify_cb),
 
1260
                                                user_data);
 
1261
 
 
1262
          if (gtk_widget_get_mapped (GTK_WIDGET (toplevel)))
 
1263
            {
 
1264
              register_internal (req->manager,
 
1265
                                 req->widget,
 
1266
                                 req->gesture_type,
 
1267
                                 req->device_type,
 
1268
                                 req->touch_points,
 
1269
                                 req->callback,
 
1270
                                 req->user_data,
 
1271
                                 req->destroy);
 
1272
 
 
1273
              g_free (req);
 
1274
            }
 
1275
          else
 
1276
            {
 
1277
              GripGestureManagerPrivate *priv = req->manager->priv;
 
1278
 
 
1279
              priv->requests = g_list_append (priv->requests, req);
 
1280
 
 
1281
              g_signal_connect (toplevel,
 
1282
                                "map-event",
 
1283
                                G_CALLBACK (window_mapped_cb),
 
1284
                                req->manager);
 
1285
            }
 
1286
        }
 
1287
      else
 
1288
        {
 
1289
          g_signal_connect (G_OBJECT (toplevel),
 
1290
                            "notify",
 
1291
                            G_CALLBACK (toplevel_notify_cb),
 
1292
                            user_data);
 
1293
        }
 
1294
    }
 
1295
}
 
1296
 
 
1297
/*
 
1298
 * register_widget:
 
1299
 *
 
1300
 * Registers a specific widget for a specific gesture made by a specific input
 
1301
 * device type.
 
1302
 *
 
1303
 * If the widget's containing window is a valid window, the widget is registered
 
1304
 * right away, otherwise the registration is deferred until the widget actually
 
1305
 * has a top-level window.
 
1306
 */
 
1307
static void
 
1308
register_widget (GripGestureManager *manager,
 
1309
                 GtkWidget          *widget,
 
1310
                 GripGestureType     gesture_type,
 
1311
                 GripDeviceType      device_type,
 
1312
                 gint                touch_points,
 
1313
                 GripGestureCallback callback,
 
1314
                 gpointer            user_data,
 
1315
                 GDestroyNotify      destroy)
 
1316
{
 
1317
  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
 
1318
 
 
1319
  if (GTK_IS_WINDOW (toplevel))
 
1320
    {
 
1321
      register_internal (manager,
 
1322
                         widget,
 
1323
                         gesture_type,
 
1324
                         device_type,
 
1325
                         touch_points,
 
1326
                         callback,
 
1327
                         user_data,
 
1328
                         destroy);
 
1329
    }
 
1330
  else
 
1331
    {
 
1332
      GripRegistrationRequest *req = g_new0 (GripRegistrationRequest, 1);
 
1333
 
 
1334
      req->manager      = manager;
 
1335
      req->widget       = widget;
 
1336
      req->gesture_type = gesture_type;
 
1337
      req->device_type  = device_type;
 
1338
      req->touch_points = touch_points;
 
1339
      req->callback     = callback;
 
1340
      req->user_data    = user_data;
 
1341
      req->destroy      = destroy;
 
1342
 
 
1343
      g_signal_connect (toplevel,
 
1344
                        "notify",
 
1345
                        G_CALLBACK (toplevel_notify_cb),
 
1346
                        req);
 
1347
    }
 
1348
}
 
1349
 
 
1350
static void
 
1351
window_mapped_cb (GtkWidget   *widget,
 
1352
                  GdkEvent    *event G_GNUC_UNUSED,
 
1353
                  gpointer     user_data)
 
1354
{
 
1355
  GripGestureManager *manager = (GripGestureManager *)user_data;
 
1356
  GripGestureManagerPrivate *priv = manager->priv;
 
1357
  GList *tmp;
 
1358
 
 
1359
  for (tmp = priv->requests; tmp != NULL; tmp = tmp->next)
 
1360
    {
 
1361
      GripRegistrationRequest *req = tmp->data;
 
1362
 
 
1363
      register_widget (req->manager,
 
1364
                       req->widget,
 
1365
                       req->gesture_type,
 
1366
                       req->device_type,
 
1367
                       req->touch_points,
 
1368
                       req->callback,
 
1369
                       req->user_data,
 
1370
                       req->destroy);
 
1371
 
 
1372
      g_free (req);
 
1373
    }
 
1374
 
 
1375
  g_list_free (priv->requests);
 
1376
  priv->requests = NULL;
 
1377
 
 
1378
  g_signal_handlers_disconnect_by_func (widget,
 
1379
                                        window_mapped_cb,
 
1380
                                        user_data);
 
1381
}
 
1382
 
 
1383
/**
 
1384
 * grip_gesture_manager_register_window:
 
1385
 * @manager: A #GripGestureManager instance.
 
1386
 * @widget: A #GtkWidget to register the gesture event for.
 
1387
 * @gesture_type: The type of gesture event to register.
 
1388
 * @device_type: The type of the device use to create the gesture.
 
1389
 * @touch_points: Number of touch points for this gesture.
 
1390
 * @callback: Called when a gesture starts, updates, or ends.
 
1391
 * @user_data: User data
 
1392
 * @destroy: Destroy callback for user data.
 
1393
 *
 
1394
 * Registers a widget to receive gesture events.
 
1395
 *
 
1396
 * The callback parameters provided will be called by the
 
1397
 * #GripGestureManager whenever the user initiates a gesture
 
1398
 * on the specified window.
 
1399
 */
 
1400
void
 
1401
grip_gesture_manager_register_window (GripGestureManager  *manager,
 
1402
                                      GtkWidget           *widget,
 
1403
                                      GripGestureType      gesture_type,
 
1404
                                      GripDeviceType       device_type,
 
1405
                                      gint                 touch_points,
 
1406
                                      GripGestureCallback  callback,
 
1407
                                      gpointer             user_data,
 
1408
                                      GDestroyNotify       destroy)
 
1409
{
 
1410
  GtkWidget *toplevel;
 
1411
 
 
1412
  g_return_if_fail (GRIP_IS_GESTURE_MANAGER (manager));
 
1413
  g_return_if_fail (GTK_IS_WIDGET (widget));
 
1414
 
 
1415
  toplevel = gtk_widget_get_toplevel (widget);
 
1416
 
 
1417
  if (GTK_IS_WINDOW (toplevel))
 
1418
    {
 
1419
      if (gtk_widget_get_mapped (GTK_WIDGET (toplevel)))
 
1420
        {
 
1421
          register_internal (manager,
 
1422
                             widget,
 
1423
                             gesture_type,
 
1424
                             device_type,
 
1425
                             touch_points,
 
1426
                             callback,
 
1427
                             user_data,
 
1428
                             destroy);
 
1429
        }
 
1430
      else
 
1431
        {
 
1432
          GripRegistrationRequest *req = g_new0 (GripRegistrationRequest, 1);
 
1433
          GripGestureManagerPrivate *priv = manager->priv;
 
1434
 
 
1435
          req->manager      = manager;
 
1436
          req->widget       = widget;
 
1437
          req->gesture_type = gesture_type;
 
1438
          req->device_type  = device_type;
 
1439
          req->touch_points = touch_points;
 
1440
          req->callback     = callback;
 
1441
          req->user_data    = user_data;
 
1442
          req->destroy      = destroy;
 
1443
 
 
1444
          priv->requests = g_list_append (priv->requests, req);
 
1445
 
 
1446
          g_signal_connect (toplevel,
 
1447
                            "map-event",
 
1448
                            G_CALLBACK (window_mapped_cb),
 
1449
                            manager);
 
1450
        }
 
1451
    }
 
1452
  else
 
1453
    {
 
1454
      GripRegistrationRequest *req = g_new0 (GripRegistrationRequest, 1);
 
1455
 
 
1456
      req->manager      = manager;
 
1457
      req->widget       = widget;
 
1458
      req->gesture_type = gesture_type;
 
1459
      req->device_type  = device_type;
 
1460
      req->touch_points = touch_points;
 
1461
      req->callback     = callback;
 
1462
      req->user_data    = user_data;
 
1463
      req->destroy      = destroy;
 
1464
 
 
1465
      g_signal_connect (toplevel,
 
1466
                        "notify",
 
1467
                        G_CALLBACK (toplevel_notify_cb),
 
1468
                        req);
 
1469
    }
 
1470
}
 
1471
 
 
1472
static void
 
1473
shutdown_registration(GripGestureRegistration *reg)
 
1474
{
 
1475
  free_registration(reg);
 
1476
  geis_finish(reg->instance);
 
1477
  reg->instance = NULL;
 
1478
  g_free(reg);
 
1479
}
 
1480
 
 
1481
void
 
1482
grip_gesture_manager_unregister_window (GripGestureManager  *manager,
 
1483
                                        GtkWidget           *toplevel)
 
1484
{
 
1485
  GripGestureManagerPrivate *priv = manager->priv;
 
1486
  struct Registrations *registrations;
 
1487
 
 
1488
  g_return_if_fail (GRIP_IS_GESTURE_MANAGER (manager));
 
1489
  g_return_if_fail (GTK_IS_WINDOW (toplevel));
 
1490
 
 
1491
  /* Currently only allow unsubscribing after the window has been shown. */
 
1492
  g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (toplevel)));
 
1493
  registrations = g_hash_table_lookup (priv->registered_windows, toplevel);
 
1494
  if (!registrations) {
 
1495
      return;
 
1496
  }
 
1497
 
 
1498
  shutdown_registration(registrations->touchscreen);
 
1499
  shutdown_registration(registrations->touchpad);
 
1500
  shutdown_registration(registrations->independent);
 
1501
  g_free(registrations);
 
1502
  g_hash_table_remove(priv->registered_windows, toplevel);
 
1503
 
 
1504
}
 
1505
 
 
1506
GType
 
1507
grip_gesture_event_get_type (void)
 
1508
{
 
1509
  static GType type = 0;
 
1510
 
 
1511
  if (type == 0)
 
1512
    {
 
1513
      type = g_boxed_type_register_static (g_intern_static_string ("GripGestureEvent"),
 
1514
                                           (GBoxedCopyFunc)grip_gesture_event_copy,
 
1515
                                           (GBoxedFreeFunc)grip_gesture_event_free);
 
1516
    }
 
1517
 
 
1518
  return type;
 
1519
}
 
1520
 
 
1521
/**
 
1522
 * grip_gesture_event_new:
 
1523
 * @gesture_type: the type of the gesture
 
1524
 *
 
1525
 * Creates a new Grip gesture event.
 
1526
 *
 
1527
 * Returns: a new #GripGestureEvent
 
1528
 */
 
1529
GripGestureEvent *
 
1530
grip_gesture_event_new (GripGestureType gesture_type)
 
1531
{
 
1532
  GripGestureEvent *event = g_slice_new0 (GripGestureEvent);
 
1533
 
 
1534
  event->any.type = gesture_type;
 
1535
 
 
1536
  return event;
 
1537
}
 
1538
 
 
1539
/**
 
1540
 * grip_gesture_event_copy:
 
1541
 * @event: an existing #GripGestureEvent
 
1542
 *
 
1543
 * Creates a new #GripGestureEvent instance using a deep copy of and existing
 
1544
 * event.
 
1545
 *
 
1546
 * Returns: a new #GripGestureEvent
 
1547
 */
 
1548
GripGestureEvent *
 
1549
grip_gesture_event_copy (const GripGestureEvent *event)
 
1550
{
 
1551
  GripGestureEvent *new_event;
 
1552
 
 
1553
  g_return_val_if_fail (event != NULL, NULL);
 
1554
 
 
1555
  new_event = grip_gesture_event_new (event->type);
 
1556
  *new_event = *event;
 
1557
 
 
1558
  return new_event;
 
1559
}
 
1560
 
 
1561
/**
 
1562
 * grip_gesture_event_free:
 
1563
 * @event: a #GripGestureEvent
 
1564
 *
 
1565
 * Frees the resources allocated for a #GripGestureEvent.
 
1566
 */
 
1567
void
 
1568
grip_gesture_event_free (GripGestureEvent *event)
 
1569
{
 
1570
  g_return_if_fail (event != NULL);
 
1571
 
 
1572
  g_slice_free (GripGestureEvent, event);
 
1573
}