2
* Copyright 2010, 2011 Canonical, Ltd.
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:
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.
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.
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/>
23
* Cody Russell <crussell@canonical.com>
26
#include "gripgesturemanager.h"
29
#include <geis/geis.h>
30
#include "gripinputdevice.h"
32
typedef struct _GripGestureRegistration GripGestureRegistration;
33
typedef struct _GripGestureBinding GripGestureBinding;
34
typedef struct _GripRegistrationRequest GripRegistrationRequest;
36
typedef GPtrArray GripDevices;
38
struct Registrations {
39
GripGestureRegistration *touchscreen;
40
GripGestureRegistration *touchpad;
41
GripGestureRegistration *independent;
44
struct _GripGestureManagerPrivate
46
GHashTable *registered_windows;
60
* The mapping between a GEIS subscription and a GTK widget. Sort of.
62
struct _GripGestureBinding
67
GripGestureCallback callback;
69
GDestroyNotify destroy;
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
80
* A collection of all gesture subscriptions for all widgets contained within a
81
* top-level GTK window.
83
struct _GripGestureRegistration
87
GPtrArray *gesture_list;
88
GeisInstance instance;
89
GIOChannel *iochannel;
93
struct _GripRegistrationRequest
95
GripGestureManager *manager;
97
GripGestureType gesture_type;
98
GripDeviceType device_type;
100
GripGestureCallback callback;
102
GDestroyNotify destroy;
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,
134
static guint signals[SIGNAL_LAST];
136
static void gesture_added (void *cookie,
137
GeisGestureType gesture_type,
138
GeisGestureId gesture_id,
140
GeisGestureAttr *attrs);
142
static void gesture_removed (void *cookie,
143
GeisGestureType gesture_type,
144
GeisGestureId gesture_id,
146
GeisGestureAttr *attrs);
148
static void gesture_start (void *cookie,
149
GeisGestureType gesture_type,
150
GeisGestureId gesture_id,
152
GeisGestureAttr *attrs);
154
static void gesture_update (void *cookie,
155
GeisGestureType gesture_type,
156
GeisGestureId gesture_id,
158
GeisGestureAttr *attrs);
160
static void gesture_finish (void *cookie,
161
GeisGestureType gesture_type,
162
GeisGestureId gesture_id,
164
GeisGestureAttr *attrs);
166
static void window_mapped_cb (GtkWidget *widget,
170
static GeisGestureFuncs gesture_funcs = {
180
device_added (void *cookie, GeisInputDeviceId id G_GNUC_UNUSED, void *attrs)
182
GripGestureManager *gesture_manager = (GripGestureManager *) cookie;
183
GripInputDevice *input_device = g_object_new (GRIP_TYPE_INPUT_DEVICE,
184
"device-attrs", attrs,
187
g_ptr_array_add(gesture_manager->priv->devices, input_device);
188
g_signal_emit (gesture_manager, signals[DEVICE_AVAILABLE], 0, input_device);
193
device_removed (void *cookie, GeisInputDeviceId id, void *attrs G_GNUC_UNUSED)
196
GripGestureManager *gesture_manager = (GripGestureManager *) cookie;
197
GripDevices *devices = gesture_manager->priv->devices;
199
for (i = 0; i < devices->len; ++i)
201
GripInputDevice *input_device = g_ptr_array_index (devices, i);
202
if (id == grip_input_device_get_id (input_device))
204
g_signal_emit (gesture_manager, signals[DEVICE_UNAVAILABLE], 0,
206
g_ptr_array_remove_index (devices, i);
213
static GeisInputFuncs input_funcs = {
221
grip_get_devices (GripGestureManager *gesture_manager)
223
GeisXcbWinInfo xcb_win_info = {
224
.display_name = NULL,
228
GeisWinInfo win_info = {
229
GEIS_XCB_FULL_WINDOW,
232
GeisInstance instance;
235
status = geis_init (&win_info, &instance);
236
if (status != GEIS_STATUS_SUCCESS)
238
g_warning ("failed to determine device types\n");
242
status = geis_input_devices (instance, &input_funcs, gesture_manager);
243
if (status != GEIS_STATUS_SUCCESS)
245
g_warning ("failed to determine device types\n");
249
status = geis_event_dispatch (instance);
250
if (status != GEIS_STATUS_SUCCESS)
252
g_warning ("failed to determine device types\n");
256
geis_finish (instance);
259
G_DEFINE_TYPE (GripGestureManager, grip_gesture_manager, G_TYPE_OBJECT)
261
#define GRIP_GESTURE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GRIP_TYPE_GESTURE_MANAGER, GripGestureManagerPrivate))
264
grip_gesture_manager_dispose (GObject *object G_GNUC_UNUSED)
270
free_registration(GripGestureRegistration *reg)
277
geis_unsubscribe (reg->instance,
278
(GeisGestureType*)reg->gesture_list->pdata);
280
/* We don't need to free the values in the GPtrArray. */
281
g_ptr_array_free (reg->gesture_list, TRUE);
283
for (tmp = reg->bindings; tmp != NULL; tmp = tmp->next)
288
g_list_free (reg->bindings);
291
/* Helper function needed to make things work with GTK. */
294
free_registration_adapter (gpointer key G_GNUC_UNUSED,
296
gpointer user_data G_GNUC_UNUSED)
298
struct Registrations *regs = (struct Registrations *)value;
299
free_registration(regs->touchscreen);
300
free_registration(regs->touchpad);
301
free_registration(regs->independent);
305
grip_gesture_manager_finalize (GObject *object)
307
GripGestureManagerPrivate *priv = GRIP_GESTURE_MANAGER_GET_PRIVATE (object);
309
if (priv->registered_windows != NULL)
311
g_hash_table_foreach (priv->registered_windows,
312
free_registration_adapter,
315
g_hash_table_unref (priv->registered_windows);
316
priv->registered_windows = NULL;
318
g_ptr_array_foreach (priv->devices, (GFunc) g_object_unref, NULL);
319
g_ptr_array_unref (priv->devices);
324
grip_gesture_manager_constructor (GType type,
326
GObjectConstructParam *params)
328
static GObject *self = NULL;
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));
338
return g_object_ref (self);
342
grip_gesture_manager_class_init (GripGestureManagerClass *class)
344
GObjectClass *gobject_class;
346
gobject_class = G_OBJECT_CLASS (class);
348
grip_gesture_manager_parent_class = g_type_class_peek_parent (class);
350
g_type_class_add_private (gobject_class, sizeof (GripGestureManagerPrivate));
352
gobject_class->constructor = grip_gesture_manager_constructor;
353
gobject_class->dispose = grip_gesture_manager_dispose;
354
gobject_class->finalize = grip_gesture_manager_finalize;
357
* GripGestureManager::device-available:
358
* @gesture_manager: the #GripGestureManager sending the signal
359
* @input_device: the new #GripInputDevice just added.
361
* Signals the availability of a new gesture-capable input device.
363
signals[DEVICE_AVAILABLE] = g_signal_new ("device-available",
364
GRIP_TYPE_GESTURE_MANAGER,
368
g_cclosure_marshal_VOID__OBJECT,
371
GRIP_TYPE_INPUT_DEVICE);
374
* GripGestureManager::device-unavailable:
375
* @gesture_manager: the #GripGestureManager sending the signal
376
* @input_device: the new #GripInputDevice just added.
378
* Signals the unavailability of a gesture-capable input device.
380
signals[DEVICE_UNAVAILABLE] = g_signal_new ("device-unavailable",
381
GRIP_TYPE_GESTURE_MANAGER,
385
g_cclosure_marshal_VOID__OBJECT,
388
GRIP_TYPE_INPUT_DEVICE);
394
* device_id_to_input_device:
395
* @gesture_manager: the #GripGestureManager
396
* @device_id: the device ID
398
* Finds a known #GripInputDevice given a GEIS device identifier.
400
* Returns: a pointer to a #GripInputDevice or %NULL if not found.
402
static GripInputDevice *
403
device_id_to_input_device (GripGestureManager *gesture_manager,
404
GeisInputDeviceId device_id)
407
GripInputDevice *input_device = NULL;
409
for (j = 0; j < gesture_manager->priv->devices->len; ++j)
411
GripInputDevice *device;
413
device = g_ptr_array_index (gesture_manager->priv->devices, j);
414
if (grip_input_device_get_id (device) == device_id)
416
input_device = device;
424
* registration_for_input_device:
425
* @registrations: A collection of #GripGestureRegistration
426
* @input_device: A pointer to a #GripInputDevice
428
* Determines which #GripGestureRegistration to use dependeng on properties of
429
* the #GripInputDevice.
431
* Returns: a pointer to a #GripGestureRegistration or %NULL if not found.
433
static GripGestureRegistration *
434
registration_for_input_device (struct Registrations *registrations,
435
GripInputDevice *input_device)
437
GripDeviceType device_type = grip_get_device_type(input_device);
438
if (device_type == GRIP_DEVICE_TOUCHSCREEN)
440
return registrations->touchscreen;
442
else if (GRIP_DEVICE_TOUCHPAD)
444
return registrations->touchpad;
446
else if (GRIP_DEVICE_INDEPENDENT)
448
return registrations->independent;
455
pinch_gesture_handle_properties (GripEventGesturePinch *event,
457
GeisGestureAttr *attrs)
462
for (i = 0; i < attr_count; ++i)
464
if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TOUCHES) == 0 &&
465
attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
467
touches = attrs[i].integer_val;
469
if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TIMESTAMP) == 0 &&
470
attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
472
event->timestamp = attrs[i].integer_val;
474
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_X) == 0 &&
475
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
477
event->focus_x = attrs[i].float_val;
479
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_Y) == 0 &&
480
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
482
event->focus_y = attrs[i].float_val;
484
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_RADIUS_DELTA) == 0 &&
485
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
487
event->radius_delta = attrs[i].float_val;
489
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_RADIAL_VELOCITY) == 0 &&
490
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
492
event->radial_velocity = attrs[i].float_val;
494
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_RADIUS) == 0 &&
495
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
497
event->radius = attrs[i].float_val;
499
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_X) == 0 &&
500
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
502
event->position_x = attrs[i].float_val;
504
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_Y) == 0 &&
505
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
507
event->position_y = attrs[i].float_val;
515
drag_gesture_handle_properties (GripEventGestureDrag *event,
517
GeisGestureAttr *attrs)
522
for (i = 0; i < attr_count; ++i)
524
if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TOUCHES) == 0 &&
525
attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
527
touches = attrs[i].integer_val;
529
if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TIMESTAMP) == 0 &&
530
attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
532
event->timestamp = attrs[i].integer_val;
534
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_X) == 0 &&
535
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
537
event->focus_x = attrs[i].float_val;
539
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_Y) == 0 &&
540
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
542
event->focus_y = attrs[i].float_val;
544
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_DELTA_X) == 0 &&
545
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
547
event->delta_x = attrs[i].float_val;
549
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_DELTA_Y) == 0 &&
550
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
552
event->delta_y = attrs[i].float_val;
554
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_VELOCITY_X) == 0 &&
555
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
557
event->velocity_x = attrs[i].float_val;
559
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_VELOCITY_Y) == 0 &&
560
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
562
event->velocity_y = attrs[i].float_val;
564
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_X) == 0 &&
565
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
567
event->position_x = attrs[i].float_val;
569
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_Y) == 0 &&
570
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
572
event->position_y = attrs[i].float_val;
580
rotate_gesture_handle_properties (GripEventGestureRotate *event,
582
GeisGestureAttr *attrs)
587
for (i = 0; i < attr_count; ++i)
589
if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TOUCHES) == 0 &&
590
attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
592
touches = attrs[i].integer_val;
594
if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TIMESTAMP) == 0 &&
595
attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
597
event->timestamp = attrs[i].integer_val;
599
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_X) == 0 &&
600
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
602
event->focus_x = attrs[i].float_val;
604
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_Y) == 0 &&
605
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
607
event->focus_y = attrs[i].float_val;
609
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_ANGLE_DELTA) == 0 &&
610
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
612
event->angle_delta = attrs[i].float_val;
614
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_ANGULAR_VELOCITY) == 0 &&
615
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
617
event->angular_velocity = attrs[i].float_val;
619
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_ANGLE) == 0 &&
620
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
622
event->angle = attrs[i].float_val;
624
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_X) == 0 &&
625
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
627
event->position_x = attrs[i].float_val;
629
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_Y) == 0 &&
630
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
632
event->position_y = attrs[i].float_val;
640
tap_gesture_handle_properties (GripEventGestureTap *event,
642
GeisGestureAttr *attrs)
647
for (i = 0; i < attr_count; ++i)
649
if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TOUCHES) == 0 &&
650
attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
652
touches = attrs[i].integer_val;
654
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TIMESTAMP) == 0 &&
655
attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
657
event->timestamp = attrs[i].integer_val;
659
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_X) == 0 &&
660
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
662
event->focus_x = attrs[i].float_val;
664
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_FOCUS_Y) == 0 &&
665
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
667
event->focus_y = attrs[i].float_val;
669
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_X) == 0 &&
670
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
672
event->position_x = attrs[i].float_val;
674
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_POSITION_Y) == 0 &&
675
attrs[i].type == GEIS_ATTR_TYPE_FLOAT)
677
event->position_y = attrs[i].float_val;
679
else if (g_strcmp0 (attrs[i].name, GEIS_GESTURE_ATTRIBUTE_TAP_TIME) == 0 &&
680
attrs[i].type == GEIS_ATTR_TYPE_INTEGER)
682
event->tap_time = attrs[i].float_val;
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)
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)
708
matches_widget (GtkWidget *widget,
716
gtk_widget_get_allocation (widget, &alloc);
717
gdk_window_get_root_coords (window, alloc.x, alloc.y, &ax, &ay);
719
return (x >= ax && x < ax + alloc.width && y >= ay && y < ay + alloc.height);
732
* The generic gesture event dispatch engine.
735
process_gesture (void *cookie,
736
GeisGestureType type,
739
GeisGestureAttr *attrs,
740
GripTimeType time_type)
742
GripGestureManager *manager = (GripGestureManager *) cookie;
743
GripInputDevice *input_device = NULL;
744
GtkWindow *gtk_window = NULL;
745
struct Registrations *registrations = NULL;
746
GripGestureRegistration *reg = NULL;
750
for (i = 0; i < attr_count; ++i)
752
if (0 == g_strcmp0(attrs[i].name, GEIS_GESTURE_ATTRIBUTE_DEVICE_ID))
754
input_device = device_id_to_input_device(manager, attrs[i].integer_val);
756
else if (0 == g_strcmp0(attrs[i].name, GEIS_GESTURE_ATTRIBUTE_EVENT_WINDOW_ID))
760
struct Registrations *value;
761
guint window_id = attrs[i].integer_val;
763
g_hash_table_iter_init (&iter, manager->priv->registered_windows);
764
while (g_hash_table_iter_next(&iter, (gpointer *)&key, (gpointer *)&value))
766
if (GDK_WINDOW_XID (gtk_widget_get_window (key)) == window_id)
768
gtk_window = (GtkWindow *)key;
774
g_return_if_fail(input_device != NULL);
775
g_return_if_fail(gtk_window != NULL);
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);
782
for (l = reg->bindings; l != NULL; l = l->next)
784
GripGestureBinding *binding = (GripGestureBinding *)l->data;
786
if (binding->type == type)
788
GripGestureEvent *event = grip_gesture_event_new (type);
790
if (type == GRIP_GESTURE_DRAG)
792
GripEventGestureDrag *drag = (GripEventGestureDrag *)event;
796
drag->input_device = input_device;
797
drag->fingers = drag_gesture_handle_properties (drag,
801
if (drag->fingers == (gint)binding->touches)
803
if (matches_widget (binding->widget,
804
gtk_widget_get_window(GTK_WIDGET (reg->window)),
806
(gint)drag->focus_y))
808
binding->callback (binding->widget,
815
else if (type == GRIP_GESTURE_PINCH)
817
GripEventGesturePinch *pinch = (GripEventGesturePinch *)event;
821
pinch->input_device = input_device;
822
pinch->fingers = pinch_gesture_handle_properties (pinch,
826
if (pinch->fingers == binding->touches)
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))
833
binding->callback (binding->widget,
840
else if (type == GRIP_GESTURE_ROTATE)
842
GripEventGestureRotate *rotate = (GripEventGestureRotate *)event;
846
rotate->input_device = input_device;
847
rotate->fingers = rotate_gesture_handle_properties (rotate,
851
if (rotate->fingers == binding->touches)
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))
858
binding->callback (binding->widget,
865
else if (type == GRIP_GESTURE_TAP)
867
GripEventGestureTap *tap = (GripEventGestureTap *)event;
871
tap->input_device = input_device;
872
tap->fingers = tap_gesture_handle_properties (tap,
876
if (tap->fingers == binding->touches)
878
if (matches_widget (binding->widget,
879
gtk_widget_get_window(GTK_WIDGET (reg->window)),
883
binding->callback (binding->widget,
891
grip_gesture_event_free (event);
897
gesture_start (void *cookie,
898
GeisGestureType type,
901
GeisGestureAttr *attrs)
903
process_gesture(cookie, type, id, attr_count, attrs, GRIP_TIME_START);
907
gesture_update (void *cookie,
908
GeisGestureType type,
911
GeisGestureAttr *attrs)
913
process_gesture(cookie, type, id, attr_count, attrs, GRIP_TIME_UPDATE);
917
gesture_finish (void *cookie,
918
GeisGestureType type,
921
GeisGestureAttr *attrs)
923
process_gesture(cookie, type, id, attr_count, attrs, GRIP_TIME_END);
927
grip_gesture_manager_init (GripGestureManager *item)
929
GripGestureManagerPrivate *priv;
931
priv = item->priv = GRIP_GESTURE_MANAGER_GET_PRIVATE (item);
933
priv->registered_windows = g_hash_table_new (g_direct_hash, g_direct_equal);
935
priv->devices = g_ptr_array_new ();
939
io_callback (GIOChannel *source G_GNUC_UNUSED,
940
GIOCondition condition G_GNUC_UNUSED,
943
GripGestureRegistration *reg = (GripGestureRegistration *)data;
945
geis_event_dispatch (reg->instance);
951
destroy_registration(GripGestureRegistration *reg)
955
for (list = reg->bindings; list != NULL; list = list->next)
957
GripGestureBinding *binding = (GripGestureBinding *)list->data;
959
if (binding->destroy)
961
GDestroyNotify d = binding->destroy;
969
g_list_free (reg->bindings);
971
g_io_channel_shutdown (reg->iochannel, FALSE, NULL);
972
g_source_remove (reg->iochannel_id);
973
g_io_channel_unref (reg->iochannel);
975
geis_finish (reg->instance);
977
reg->instance = NULL;
978
reg->iochannel = NULL;
982
window_destroyed_cb (GtkWidget *object,
985
GripGestureManager *manager = (GripGestureManager *)user_data;
986
GripGestureManagerPrivate *priv = manager->priv;
987
struct Registrations *reg = g_hash_table_lookup (priv->registered_windows, object);
992
destroy_registration(reg->touchpad);
993
destroy_registration(reg->touchscreen);
994
destroy_registration(reg->independent);
996
g_hash_table_remove (priv->registered_windows, object);
1000
static const gchar *
1001
grip_type_to_geis_type (GripGestureType gesture_type,
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;
1008
return geis_gesture_types[(t * 5 + touch_points) - 1];
1013
GripGestureManager *
1014
grip_gesture_manager_get (void)
1016
return g_object_new (GRIP_TYPE_GESTURE_MANAGER, NULL);
1021
grip_devices_for_type (GripDeviceType type, GArray *selection,
1022
GripDevices *devices)
1026
for (i = 0; i < devices->len; ++i)
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);
1032
if ((type & GRIP_DEVICE_TOUCHSCREEN) && device_type == GRIP_DEVICE_TOUCHSCREEN)
1034
g_array_append_val (selection, id);
1036
if ((type & GRIP_DEVICE_TOUCHPAD) && device_type == GRIP_DEVICE_TOUCHPAD)
1038
g_array_append_val (selection, id);
1040
if ((type & GRIP_DEVICE_INDEPENDENT) && device_type == GRIP_DEVICE_INDEPENDENT)
1042
g_array_append_val (selection, id);
1048
* new_window_registration:
1049
* @manager: a GripGestureManager
1050
* @toplevel: a toplevel #GtkWindow
1052
* Constructs a new #GripGestureRegistration for a #GtkWidget.
1054
static GripGestureRegistration *
1055
new_window_registration(GripGestureManager *manager,
1056
GtkWidget *toplevel)
1058
GripGestureRegistration *reg;
1059
GeisInstance instance;
1061
GeisXcbWinInfo xcb_win_info = {
1062
.display_name = NULL,
1064
.window_id = GDK_WINDOW_XID (gtk_widget_get_window(toplevel))
1066
GeisWinInfo win_info = {
1067
GEIS_XCB_FULL_WINDOW,
1071
if (geis_init (&win_info, &instance) != GEIS_STATUS_SUCCESS)
1073
g_warning ("Failed to initialize gesture manager.");
1077
if (geis_configuration_supported (instance,
1078
GEIS_CONFIG_UNIX_FD) != GEIS_STATUS_SUCCESS)
1080
g_warning ("Gesture manager does not support UNIX fd.");
1084
if (geis_configuration_get_value (instance,
1085
GEIS_CONFIG_UNIX_FD,
1086
&fd) != GEIS_STATUS_SUCCESS)
1088
g_error ("Gesture manager failed to obtain UNIX fd.");
1092
reg = g_new0 (GripGestureRegistration, 1);
1094
reg->window = GTK_WINDOW (toplevel);
1095
reg->instance = instance;
1097
g_signal_connect (toplevel,
1099
G_CALLBACK (window_destroyed_cb),
1102
reg->iochannel = g_io_channel_unix_new (fd);
1103
reg->iochannel_id = g_io_add_watch (reg->iochannel,
1107
reg->gesture_list = g_ptr_array_new ();
1113
bind_registration(GripGestureManager *manager,
1114
GripGestureRegistration *reg,
1116
GripGestureType gesture_type,
1117
GripDeviceType device_type,
1119
GripGestureCallback callback,
1121
GDestroyNotify destroy)
1123
GripGestureManagerPrivate *priv;
1124
GripGestureBinding *binding;
1127
priv = manager->priv;
1129
if (reg->gesture_list->len)
1130
g_ptr_array_remove_index (reg->gesture_list,
1131
reg->gesture_list->len - 1);
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);
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,
1145
geis_subscribe (reg->instance,
1146
(GeisInputDeviceId *)(void *)devices->data,
1147
(const char**)reg->gesture_list->pdata,
1151
g_array_unref (devices);
1153
/* XXX - check for duplicates in reg->bindings first */
1154
binding = g_new0 (GripGestureBinding, 1);
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;
1163
reg->bindings = g_list_append (reg->bindings, binding);
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
1173
* @callback: the callback to be invoked on gesture events
1174
* @user_data: the callbackl context to be passed back on gesture events
1177
* Binds or rebinds a gesture subscription for a widget.
1180
register_internal (GripGestureManager *manager,
1182
GripGestureType gesture_type,
1183
GripDeviceType device_type,
1185
GripGestureCallback callback,
1187
GDestroyNotify destroy)
1189
GripGestureManagerPrivate *priv;
1190
GtkWidget *toplevel;
1191
struct Registrations *registrations;
1193
g_return_if_fail (GRIP_IS_GESTURE_MANAGER (manager));
1194
g_return_if_fail (GTK_IS_WIDGET (widget));
1196
toplevel = gtk_widget_get_toplevel (widget);
1198
g_return_if_fail (GTK_IS_WINDOW (toplevel));
1200
priv = manager->priv;
1202
if (!(registrations = g_hash_table_lookup (priv->registered_windows, toplevel)))
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);
1209
if (registrations->touchscreen == NULL ||
1210
registrations->touchpad == NULL ||
1211
registrations->independent == NULL)
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);
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);
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);
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,
1247
toplevel_notify_cb (GtkWidget *widget,
1251
if (pspec->name == g_intern_static_string ("parent"))
1253
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1254
GripRegistrationRequest *req = (GripRegistrationRequest *)user_data;
1256
if (GTK_IS_WINDOW (toplevel))
1258
g_signal_handlers_disconnect_by_func (widget,
1259
G_CALLBACK (toplevel_notify_cb),
1262
if (gtk_widget_get_mapped (GTK_WIDGET (toplevel)))
1264
register_internal (req->manager,
1277
GripGestureManagerPrivate *priv = req->manager->priv;
1279
priv->requests = g_list_append (priv->requests, req);
1281
g_signal_connect (toplevel,
1283
G_CALLBACK (window_mapped_cb),
1289
g_signal_connect (G_OBJECT (toplevel),
1291
G_CALLBACK (toplevel_notify_cb),
1300
* Registers a specific widget for a specific gesture made by a specific input
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.
1308
register_widget (GripGestureManager *manager,
1310
GripGestureType gesture_type,
1311
GripDeviceType device_type,
1313
GripGestureCallback callback,
1315
GDestroyNotify destroy)
1317
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1319
if (GTK_IS_WINDOW (toplevel))
1321
register_internal (manager,
1332
GripRegistrationRequest *req = g_new0 (GripRegistrationRequest, 1);
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;
1343
g_signal_connect (toplevel,
1345
G_CALLBACK (toplevel_notify_cb),
1351
window_mapped_cb (GtkWidget *widget,
1352
GdkEvent *event G_GNUC_UNUSED,
1355
GripGestureManager *manager = (GripGestureManager *)user_data;
1356
GripGestureManagerPrivate *priv = manager->priv;
1359
for (tmp = priv->requests; tmp != NULL; tmp = tmp->next)
1361
GripRegistrationRequest *req = tmp->data;
1363
register_widget (req->manager,
1375
g_list_free (priv->requests);
1376
priv->requests = NULL;
1378
g_signal_handlers_disconnect_by_func (widget,
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.
1394
* Registers a widget to receive gesture events.
1396
* The callback parameters provided will be called by the
1397
* #GripGestureManager whenever the user initiates a gesture
1398
* on the specified window.
1401
grip_gesture_manager_register_window (GripGestureManager *manager,
1403
GripGestureType gesture_type,
1404
GripDeviceType device_type,
1406
GripGestureCallback callback,
1408
GDestroyNotify destroy)
1410
GtkWidget *toplevel;
1412
g_return_if_fail (GRIP_IS_GESTURE_MANAGER (manager));
1413
g_return_if_fail (GTK_IS_WIDGET (widget));
1415
toplevel = gtk_widget_get_toplevel (widget);
1417
if (GTK_IS_WINDOW (toplevel))
1419
if (gtk_widget_get_mapped (GTK_WIDGET (toplevel)))
1421
register_internal (manager,
1432
GripRegistrationRequest *req = g_new0 (GripRegistrationRequest, 1);
1433
GripGestureManagerPrivate *priv = manager->priv;
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;
1444
priv->requests = g_list_append (priv->requests, req);
1446
g_signal_connect (toplevel,
1448
G_CALLBACK (window_mapped_cb),
1454
GripRegistrationRequest *req = g_new0 (GripRegistrationRequest, 1);
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;
1465
g_signal_connect (toplevel,
1467
G_CALLBACK (toplevel_notify_cb),
1473
shutdown_registration(GripGestureRegistration *reg)
1475
free_registration(reg);
1476
geis_finish(reg->instance);
1477
reg->instance = NULL;
1482
grip_gesture_manager_unregister_window (GripGestureManager *manager,
1483
GtkWidget *toplevel)
1485
GripGestureManagerPrivate *priv = manager->priv;
1486
struct Registrations *registrations;
1488
g_return_if_fail (GRIP_IS_GESTURE_MANAGER (manager));
1489
g_return_if_fail (GTK_IS_WINDOW (toplevel));
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) {
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);
1507
grip_gesture_event_get_type (void)
1509
static GType type = 0;
1513
type = g_boxed_type_register_static (g_intern_static_string ("GripGestureEvent"),
1514
(GBoxedCopyFunc)grip_gesture_event_copy,
1515
(GBoxedFreeFunc)grip_gesture_event_free);
1522
* grip_gesture_event_new:
1523
* @gesture_type: the type of the gesture
1525
* Creates a new Grip gesture event.
1527
* Returns: a new #GripGestureEvent
1530
grip_gesture_event_new (GripGestureType gesture_type)
1532
GripGestureEvent *event = g_slice_new0 (GripGestureEvent);
1534
event->any.type = gesture_type;
1540
* grip_gesture_event_copy:
1541
* @event: an existing #GripGestureEvent
1543
* Creates a new #GripGestureEvent instance using a deep copy of and existing
1546
* Returns: a new #GripGestureEvent
1549
grip_gesture_event_copy (const GripGestureEvent *event)
1551
GripGestureEvent *new_event;
1553
g_return_val_if_fail (event != NULL, NULL);
1555
new_event = grip_gesture_event_new (event->type);
1556
*new_event = *event;
1562
* grip_gesture_event_free:
1563
* @event: a #GripGestureEvent
1565
* Frees the resources allocated for a #GripGestureEvent.
1568
grip_gesture_event_free (GripGestureEvent *event)
1570
g_return_if_fail (event != NULL);
1572
g_slice_free (GripGestureEvent, event);