diff options
Diffstat (limited to 'src/idogesturemanager.c')
-rw-r--r-- | src/idogesturemanager.c | 688 |
1 files changed, 688 insertions, 0 deletions
diff --git a/src/idogesturemanager.c b/src/idogesturemanager.c new file mode 100644 index 0000000..f603816 --- /dev/null +++ b/src/idogesturemanager.c @@ -0,0 +1,688 @@ +/* + * Copyright 2010 Canonical, Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of either or both of the following licenses: + * + * 1) the GNU Lesser General Public License version 3, as published by the + * Free Software Foundation; and/or + * 2) the GNU Lesser General Public License version 2.1, as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the applicable version of the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of both the GNU Lesser General Public + * License version 3 and version 2.1 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authors: + * Cody Russell <crussell@canonical.com> + */ + +#include "idogesturemanager.h" + +#include <gdk/gdkx.h> +#include <geis/geis.h> + +typedef struct _IdoGestureRegistration IdoGestureRegistration; +typedef struct _IdoGestureBinding IdoGestureBinding; + +struct _IdoGestureManagerPrivate +{ + GHashTable *hash; +}; + +struct _IdoGestureBinding +{ + IdoGestureType type; + IdoGestureCallback start; + IdoGestureCallback update; + IdoGestureCallback end; +}; + +struct _IdoGestureRegistration +{ + GtkWindow *window; + GList *bindings; + GeisInstance instance; +}; + +static void gesture_added (void *cookie, + GeisGestureType gesture_type, + GeisGestureId gesture_id, + GeisSize attr_count, + GeisGestureAttr *attrs); + +static void gesture_removed (void *cookie, + GeisGestureType gesture_type, + GeisGestureId gesture_id, + GeisSize attr_count, + GeisGestureAttr *attrs); + +static void gesture_start (void *cookie, + GeisGestureType gesture_type, + GeisGestureId gesture_id, + GeisSize attr_count, + GeisGestureAttr *attrs); + +static void gesture_update (void *cookie, + GeisGestureType gesture_type, + GeisGestureId gesture_id, + GeisSize attr_count, + GeisGestureAttr *attrs); + +static void gesture_finish (void *cookie, + GeisGestureType gesture_type, + GeisGestureId gesture_id, + GeisSize attr_count, + GeisGestureAttr *attrs); + +static IdoGestureManager *manager_singleton = NULL; +static GeisGestureFuncs gesture_funcs = { + gesture_added, + gesture_removed, + gesture_start, + gesture_update, + gesture_finish +}; + +G_DEFINE_TYPE (IdoGestureManager, ido_gesture_manager, G_TYPE_OBJECT) + +#define IDO_GESTURE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IDO_TYPE_GESTURE_MANAGER, IdoGestureManagerPrivate)) + +static void +ido_gesture_manager_dispose (GObject *object) +{ + IdoGestureManagerPrivate *priv = IDO_GESTURE_MANAGER (object)->priv; + + if (priv->hash != NULL) + { + g_hash_table_unref (priv->hash); + } +} + +static GObject * +ido_gesture_manager_constructor (GType type, + guint n_params, + GObjectConstructParam *params) +{ + GObject *object; + + if (manager_singleton != NULL) + { + object = g_object_ref (manager_singleton); + } + else + { + object = G_OBJECT_CLASS (ido_gesture_manager_parent_class)->constructor (type, + n_params, + params); + + manager_singleton = IDO_GESTURE_MANAGER (object); + g_object_add_weak_pointer (object, (gpointer) &manager_singleton); + } + + return object; +} + +static void +ido_gesture_manager_class_init (IdoGestureManagerClass *class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (class); + + ido_gesture_manager_parent_class = g_type_class_peek_parent (class); + + g_type_class_add_private (gobject_class, sizeof (IdoGestureManagerPrivate)); + + gobject_class->constructor = ido_gesture_manager_constructor; + gobject_class->dispose = ido_gesture_manager_dispose; +} + +/* +static void +print_attr (GeisGestureAttr *attr) +{ + return; + + g_print ("\tattr '%s'=", attr->name); + switch (attr->type) + { + case GEIS_ATTR_TYPE_BOOLEAN: + g_print ("%s\n", attr->boolean_val ? "true" : "false"); + break; + case GEIS_ATTR_TYPE_FLOAT: + g_print ("%f\n", attr->float_val); + break; + case GEIS_ATTR_TYPE_INTEGER: + g_print ("%d\n", (gint)attr->integer_val); + break; + case GEIS_ATTR_TYPE_STRING: + g_print ("\"%s\"\n", attr->string_val); + break; + default: + g_print ("<unknown>\n"); + break; + } +} +*/ + +static void +pinch_gesture_handle_properties (IdoEventGesturePinch *event, + GeisSize attr_count, + GeisGestureAttr *attrs) +{ + gint i = 0; + + for (i = 0; i < attr_count; ++i) + { + if (g_strcmp0 (attrs[i].name, "timestamp") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_INTEGER) + { + event->timestamp = attrs[i].integer_val; + } + else if (g_strcmp0 (attrs[i].name, "focus X") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->focus_x = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "focus Y") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->focus_y = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "radius delta") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->radius_delta = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "radial velocity") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->radial_velocity = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "radius") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->radius = attrs[i].float_val; + } + } +} + +static void +drag_gesture_handle_properties (IdoEventGestureDrag *event, + GeisSize attr_count, + GeisGestureAttr *attrs) +{ + gint i; + + for (i = 0; i < attr_count; ++i) + { + if (g_strcmp0 (attrs[i].name, "timestamp") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_INTEGER) + { + event->timestamp = attrs[i].integer_val; + } + else if (g_strcmp0 (attrs[i].name, "focus X") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->focus_x = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "focus Y") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->focus_y = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "delta X") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->delta_x = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "delta Y") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->delta_y = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "velocity X") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->velocity_x = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "velocity Y") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->velocity_y = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "position X") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->position_x = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "position Y") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->position_y = attrs[i].float_val; + } + } +} + +static void +rotate_gesture_handle_properties (IdoEventGestureRotate *event, + GeisSize attr_count, + GeisGestureAttr *attrs) +{ + gint i; + + for (i = 0; i < attr_count; ++i) + { + if (g_strcmp0 (attrs[i].name, "timestamp") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_INTEGER) + { + event->timestamp = attrs[i].integer_val; + } + else if (g_strcmp0 (attrs[i].name, "focus X") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->focus_x = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "focus Y") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->focus_y = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "angle delta") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->angle_delta = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "angular velocity") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->angular_velocity = attrs[i].float_val; + } + else if (g_strcmp0 (attrs[i].name, "angle") == 0 && + attrs[i].type == GEIS_ATTR_TYPE_FLOAT) + { + event->angle = attrs[i].float_val; + } + } +} + + +static void +gesture_added (void *cookie, + GeisGestureType gesture_type, + GeisGestureId gesture_id, + GeisSize attr_count, + GeisGestureAttr *attrs) +{ +} + +static void +gesture_removed (void *cookie, + GeisGestureType gesture_type, + GeisGestureId gesture_id, + GeisSize attr_count, + GeisGestureAttr *attrs) +{ +} + +static void +gesture_start (void *cookie, + GeisGestureType type, + GeisGestureId id, + GeisSize attr_count, + GeisGestureAttr *attrs) +{ + IdoGestureRegistration *reg = (IdoGestureRegistration *)cookie; + GList *l = NULL; + + for (l = reg->bindings; l != NULL; l = l->next) + { + IdoGestureBinding *binding = (IdoGestureBinding *)l->data; + + if (binding->type == type) + { + if (type == IDO_GESTURE_DRAG1 || + type == IDO_GESTURE_DRAG2 || + type == IDO_GESTURE_DRAG3 || + type == IDO_GESTURE_DRAG4 || + type == IDO_GESTURE_DRAG5) + { + IdoEventGestureDrag drag; + + drag.type = type; + drag.id = id; + + drag_gesture_handle_properties (&drag, + attr_count, + attrs); + + binding->start (reg->window, + ((IdoGestureEvent*)&drag)); + } + else if (type == IDO_GESTURE_PINCH1 || + type == IDO_GESTURE_PINCH2 || + type == IDO_GESTURE_PINCH3 || + type == IDO_GESTURE_PINCH4 || + type == IDO_GESTURE_PINCH5) + { + IdoEventGesturePinch pinch; + + pinch.type = type; + pinch.id = id; + + pinch_gesture_handle_properties (&pinch, + attr_count, + attrs); + + binding->start (reg->window, + ((IdoGestureEvent*)&pinch)); + } + else if (type == IDO_GESTURE_ROTATE1 || + type == IDO_GESTURE_ROTATE2 || + type == IDO_GESTURE_ROTATE3 || + type == IDO_GESTURE_ROTATE4 || + type == IDO_GESTURE_ROTATE5) + { + IdoEventGestureRotate rotate; + + rotate.type = type; + rotate.id = id; + + rotate_gesture_handle_properties (&rotate, + attr_count, + attrs); + + binding->start (reg->window, + ((IdoGestureEvent*)&rotate)); + } + + return; + } + } +} + +static void +gesture_update (void *cookie, + GeisGestureType type, + GeisGestureId id, + GeisSize attr_count, + GeisGestureAttr *attrs) +{ + IdoGestureRegistration *reg = (IdoGestureRegistration *)cookie; + GList *l = NULL; + + for (l = reg->bindings; l != NULL; l = l->next) + { + IdoGestureBinding *binding = (IdoGestureBinding *)l->data; + + if (binding->type == type) + { + if (type == IDO_GESTURE_DRAG1 || + type == IDO_GESTURE_DRAG2 || + type == IDO_GESTURE_DRAG3 || + type == IDO_GESTURE_DRAG4 || + type == IDO_GESTURE_DRAG5) + { + IdoEventGestureDrag drag; + + drag.type = type; + drag.id = id; + + drag_gesture_handle_properties (&drag, + attr_count, + attrs); + + binding->update (reg->window, + ((IdoGestureEvent*)&drag)); + } + else if (type == IDO_GESTURE_PINCH1 || + type == IDO_GESTURE_PINCH2 || + type == IDO_GESTURE_PINCH3 || + type == IDO_GESTURE_PINCH4 || + type == IDO_GESTURE_PINCH5) + { + IdoEventGesturePinch pinch; + + pinch.type = type; + pinch.id = id; + + pinch_gesture_handle_properties (&pinch, + attr_count, + attrs); + + binding->update (reg->window, + ((IdoGestureEvent*)&pinch)); + } + else if (type == IDO_GESTURE_ROTATE1 || + type == IDO_GESTURE_ROTATE2 || + type == IDO_GESTURE_ROTATE3 || + type == IDO_GESTURE_ROTATE4 || + type == IDO_GESTURE_ROTATE5) + { + IdoEventGestureRotate rotate; + + rotate.type = type; + rotate.id = id; + + rotate_gesture_handle_properties (&rotate, + attr_count, + attrs); + + binding->update (reg->window, + ((IdoGestureEvent*)&rotate)); + } + } + } +} + +static void +gesture_finish (void *cookie, + GeisGestureType type, + GeisGestureId id, + GeisSize attr_count, + GeisGestureAttr *attrs) +{ + IdoGestureRegistration *reg = (IdoGestureRegistration *)cookie; + GList *l = NULL; + + for (l = reg->bindings; l != NULL; l = l->next) + { + IdoGestureBinding *binding = (IdoGestureBinding *)l->data; + + if (binding->type == type) + { + if (type == IDO_GESTURE_DRAG1 || + type == IDO_GESTURE_DRAG2 || + type == IDO_GESTURE_DRAG3 || + type == IDO_GESTURE_DRAG4 || + type == IDO_GESTURE_DRAG5) + { + IdoEventGestureDrag drag; + + drag.type = type; + drag.id = id; + + drag_gesture_handle_properties (&drag, + attr_count, + attrs); + + binding->end (reg->window, + ((IdoGestureEvent*)&drag)); + } + else if (type == IDO_GESTURE_PINCH1 || + type == IDO_GESTURE_PINCH2 || + type == IDO_GESTURE_PINCH3 || + type == IDO_GESTURE_PINCH4 || + type == IDO_GESTURE_PINCH5) + { + IdoEventGesturePinch pinch; + + pinch.type = type; + pinch.id = id; + + pinch_gesture_handle_properties (&pinch, + attr_count, + attrs); + + binding->end (reg->window, + ((IdoGestureEvent*)&pinch)); + } + else if (type == IDO_GESTURE_ROTATE1 || + type == IDO_GESTURE_ROTATE2 || + type == IDO_GESTURE_ROTATE3 || + type == IDO_GESTURE_ROTATE4 || + type == IDO_GESTURE_ROTATE5) + { + IdoEventGestureRotate rotate; + + rotate.type = type; + rotate.id = id; + + rotate_gesture_handle_properties (&rotate, + attr_count, + attrs); + + binding->end (reg->window, + ((IdoGestureEvent*)&rotate)); + } + } + } +} + +static void +ido_gesture_manager_init (IdoGestureManager *item) +{ + IdoGestureManagerPrivate *priv; + + priv = item->priv = IDO_GESTURE_MANAGER_GET_PRIVATE (item); + + priv->hash = g_hash_table_new (g_direct_hash, g_direct_equal); +} + +static gboolean +io_callback (GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + IdoGestureRegistration *reg = (IdoGestureRegistration *)data; + + geis_event_dispatch (reg->instance); + + return TRUE; +} + +/* Public API */ +IdoGestureManager * +ido_gesture_manager_get (void) +{ + return g_object_new (IDO_TYPE_GESTURE_MANAGER, NULL); +} + +/** + * ido_gesture_manager_register_window: + * @window: A #GtkWindow to register the gesture event for. + * @gesture_type: The type of gesture event to register. + * @start: Called when a user initiates a gesture. + * @update: Called each time the user updates the gesture. + * @end: Called when the user ends the gesture. + * + * Registers a toplevel window to receive gesture events. + * The callback parameters provided will be called by the + * #IdoGestureManager whenever the user initiates a gesture + * on the specified window. + */ +void +ido_gesture_manager_register_window (IdoGestureManager *manager, + GtkWindow *window, + IdoGestureType gesture_type, + IdoGestureCallback start, + IdoGestureCallback update, + IdoGestureCallback end) +{ + IdoGestureManagerPrivate *priv; + IdoGestureRegistration *reg; + IdoGestureBinding *binding; + + g_return_if_fail (IDO_IS_GESTURE_MANAGER (manager)); + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (window))); + + priv = manager->priv; + + if (!(reg = g_hash_table_lookup (priv->hash, window))) + { + GeisInstance instance; + GIOChannel *iochannel; + gint fd = -1; + GeisXcbWinInfo xcb_win_info = { + .display_name = NULL, + .screenp = NULL, + .window_id = GDK_DRAWABLE_XID (GTK_WIDGET (window)->window) + }; + GeisWinInfo win_info = { + GEIS_XCB_FULL_WINDOW, + &xcb_win_info + }; + + if (geis_init (&win_info, &instance) != GEIS_STATUS_SUCCESS) + { + g_warning ("Failed to initialize gesture manager."); + return; + } + + if (geis_configuration_supported (instance, + GEIS_CONFIG_UNIX_FD) != GEIS_STATUS_SUCCESS) + { + g_warning ("Gesture manager does not support UNIX fd."); + return; + } + + if (geis_configuration_get_value (instance, + GEIS_CONFIG_UNIX_FD, + &fd) != GEIS_STATUS_SUCCESS) + { + g_error ("Gesture manager failed to obtain UNIX fd."); + return; + } + + reg = g_new0 (IdoGestureRegistration, 1); + + reg->window = window; + reg->instance = instance; + + geis_subscribe (reg->instance, + GEIS_ALL_INPUT_DEVICES, + GEIS_ALL_GESTURES, + &gesture_funcs, + reg); + + iochannel = g_io_channel_unix_new (fd); + g_io_add_watch (iochannel, + G_IO_IN, + io_callback, + reg); + } + + /* XXX - check for duplicates in reg->bindings first */ + binding = g_new0 (IdoGestureBinding, 1); + + g_print (" *** Adding binding type %d\n", (gint)gesture_type); + + binding->type = gesture_type; + binding->start = start; + binding->update = update; + binding->end = end; + + reg->bindings = g_list_append (reg->bindings, binding); + + g_hash_table_insert (priv->hash, + window, + reg); +} |