From e90ec22f6273efe3da3241355886d14b6c9d06a9 Mon Sep 17 00:00:00 2001 From: Cody Russell Date: Sun, 15 Aug 2010 17:47:53 +0100 Subject: Feel up your widgets. --- configure.ac | 4 + example/Makefile.am | 14 + example/gesture.c | 173 ++++++++++++ gtk-doc.make | 14 +- src/Makefile.am | 5 +- src/idogesturemanager.c | 688 ++++++++++++++++++++++++++++++++++++++++++++++++ src/idogesturemanager.h | 162 ++++++++++++ 7 files changed, 1055 insertions(+), 5 deletions(-) create mode 100644 example/gesture.c create mode 100644 src/idogesturemanager.c create mode 100644 src/idogesturemanager.h diff --git a/configure.ac b/configure.ac index cdab267..b53afa7 100644 --- a/configure.ac +++ b/configure.ac @@ -72,6 +72,10 @@ PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.19.7) AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) +PKG_CHECK_MODULES(GEIS, libutouch-geis >= 0.3) +AC_SUBST(GEIS_CFLAGS) +AC_SUBST(GEIS_LIBS) + dnl =========================================================================== if test "x$GCC" = "xyes"; then diff --git a/example/Makefile.am b/example/Makefile.am index bd96642..702cc8f 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1,7 +1,19 @@ noinst_PROGRAMS = \ + gesture \ messagedialog \ menus +gesture_SOURCES = \ + gesture.c + +gesture_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + $(GCC_FLAGS) \ + $(GTK_CFLAGS) \ + $(MAINTAINER_CFLAGS) + messagedialog_SOURCES = \ messagedialog.c @@ -24,6 +36,8 @@ menus_CPPFLAGS = \ $(GTK_CFLAGS) \ $(MAINTAINER_CFLAGS) +gesture_LDADD = $(top_builddir)/src/libido-0.1.la + messagedialog_LDADD = $(top_builddir)/src/libido-0.1.la menus_LDADD = $(top_builddir)/src/libido-0.1.la diff --git a/example/gesture.c b/example/gesture.c new file mode 100644 index 0000000..57c4c24 --- /dev/null +++ b/example/gesture.c @@ -0,0 +1,173 @@ +#include +#include +#include + +#include "idogesturemanager.h" + +static gint rotate = 0; +static gdouble scale = 1.0; +static gdouble translate[2] = { 200, 200 }; +static gint in_touch = 0; + +static gboolean +expose_event (GtkWidget *widget, + GdkEventExpose *event, + gpointer data) +{ + cairo_t *cr; + gdouble radians; + gint width = (in_touch > 0) ? 10 : 1; + + cr = gdk_cairo_create (widget->window); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, width); + + radians = rotate * (G_PI / 180); + cairo_translate (cr, translate[0], translate[1]); + cairo_scale (cr, scale, scale); + cairo_rotate (cr, radians); + + cairo_rectangle (cr, -50, -50, 100, 100); + cairo_stroke_preserve (cr); + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_fill (cr); + + cairo_destroy (cr); + + return FALSE; +} + +GtkWidget * +create_window (void) +{ + GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + GtkWidget *da; + const GdkColor white = { 0, 0xffff, 0xffff, 0xffff }; + + gtk_window_set_title (GTK_WINDOW (window), "Touch Demo"); + gtk_window_set_default_size (GTK_WINDOW (window), 600, 600); + g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window); + + da = gtk_drawing_area_new (); + gtk_container_add (GTK_CONTAINER (window), da); + + gtk_widget_modify_bg (da, GTK_STATE_NORMAL, &white); + + g_signal_connect (da, "expose-event", + G_CALLBACK (expose_event), NULL); + + return window; +} + +static void +gesture_start (GtkWindow *window, + IdoGestureEvent *event) +{ + in_touch++; + + gtk_widget_queue_draw (GTK_WIDGET (window)); +} + +static void +gesture_end (GtkWindow *window, + IdoGestureEvent *event) +{ + in_touch--; + + gtk_widget_queue_draw (GTK_WIDGET (window)); +} + +static void +rotate_update (GtkWindow *window, + IdoGestureEvent *event) +{ + IdoEventGestureRotate *e = (IdoEventGestureRotate *)event; + + rotate += e->angle_delta * 100; + + gtk_widget_queue_draw (GTK_WIDGET (window)); +} + +static void +pinch_update (GtkWindow *window, + IdoGestureEvent *event) +{ + IdoEventGesturePinch *e = (IdoEventGesturePinch *)event; + + scale += e->radius_delta / 100; + + gtk_widget_queue_draw (GTK_WIDGET (window)); +} + +static void +drag_update (GtkWindow *window, + IdoGestureEvent *event) +{ + IdoEventGestureDrag *e = (IdoEventGestureDrag *)event; + + translate[0] += e->delta_x; + translate[1] += e->delta_y; + + gtk_widget_queue_draw (GTK_WIDGET (window)); +} + +static void +window_mapped (GtkWidget *widget) +{ + IdoGestureManager *manager = ido_gesture_manager_get (); + GtkWindow *window = GTK_WINDOW (widget); + + ido_gesture_manager_register_window (manager, + window, + IDO_GESTURE_PINCH2, + gesture_start, + pinch_update, + gesture_end); + + ido_gesture_manager_register_window (manager, + window, + IDO_GESTURE_ROTATE2, + gesture_start, + rotate_update, + gesture_end); + + ido_gesture_manager_register_window (manager, + window, + IDO_GESTURE_DRAG2, + gesture_start, + drag_update, + gesture_end); +} + +static void +abort_handler (int x) +{ + g_print (" **** ABORT ****\n"); + + exit (1); +} + +int +main (int argc, char **argv) +{ + GtkWidget *window; + + gtk_init (&argc, &argv); + + /* Don't crash X if we're using some shitty Intel graphics like + * my Dell XT2 has in it. */ + signal (SIGABRT, abort_handler); + + window = create_window (); + + g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + g_signal_connect (window, "map-event", G_CALLBACK (window_mapped), NULL); + + gtk_widget_show_all (window); + + gtk_main (); + + return 0; +} + diff --git a/gtk-doc.make b/gtk-doc.make index 63adaed..57fab98 100644 --- a/gtk-doc.make +++ b/gtk-doc.make @@ -75,8 +75,11 @@ $(REPORT_FILES): sgml-build.stamp scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB) @echo 'gtk-doc: Scanning header files' @-chmod -R u+w $(srcdir) - @cd $(srcdir) && \ - gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) + @_source_dir='' ; for i in $(DOC_SOURCE_DIR) ; do \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ + done ; \ + cd $(srcdir) && \ + gtkdoc-scan --module=$(DOC_MODULE) --ignore-headers="$(IGNORE_HFILES)" $${_source_dir} $(SCAN_OPTIONS) $(EXTRA_HFILES) @if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null 2>&1 ; then \ CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \ else \ @@ -109,8 +112,11 @@ $(srcdir)/tmpl/*.sgml: sgml-build.stamp: tmpl.stamp $(DOC_MODULE)-sections.txt $(srcdir)/tmpl/*.sgml $(expand_content_files) @echo 'gtk-doc: Building XML' @-chmod -R u+w $(srcdir) - @cd $(srcdir) && \ - gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS) + @_source_dir='' ; for i in $(DOC_SOURCE_DIR) ; do \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ + done ; \ + cd $(srcdir) && \ + gtkdoc-mkdb --module=$(DOC_MODULE) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $${_source_dir} $(MKDB_OPTIONS) @touch sgml-build.stamp sgml.stamp: sgml-build.stamp diff --git a/src/Makefile.am b/src/Makefile.am index 1485019..d17482d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,7 @@ stamp_files = \ sources_h = \ idocalendarmenuitem.h \ idoentrymenuitem.h \ + idogesturemanager.h \ idomessagedialog.h \ idorange.h \ idoscalemenuitem.h \ @@ -46,6 +47,7 @@ INCLUDES = \ AM_CPPFLAGS = \ $(GCC_FLAGS) \ $(GTK_CFLAGS) \ + $(GEIS_CFLAGS) \ $(MAINTAINER_CFLAGS) lib_LTLIBRARIES = libido-0.1.la @@ -54,6 +56,7 @@ libido_0_1_la_SOURCES = \ idotypebuiltins.c \ idocalendarmenuitem.c \ idoentrymenuitem.c \ + idogesturemanager.c \ idomessagedialog.c \ idorange.c \ idoscalemenuitem.c \ @@ -70,7 +73,7 @@ libidoinclude_HEADERS = \ idotimeline.h \ libido.h -libido_0_1_la_LIBADD = $(GTK_LIBS) +libido_0_1_la_LIBADD = $(GTK_LIBS) $(GEIS_LIBS) libido_0_1_la_LDFLAGS = $(GTK_LT_LDFLAGS) idoheadersdir = $(includedir)/ido-0.1/ido 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 + * + * + * Authors: + * Cody Russell + */ + +#include "idogesturemanager.h" + +#include +#include + +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 ("\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); +} diff --git a/src/idogesturemanager.h b/src/idogesturemanager.h new file mode 100644 index 0000000..bc3ad33 --- /dev/null +++ b/src/idogesturemanager.h @@ -0,0 +1,162 @@ +/* + * 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 + * + * + * Authors: + * Cody Russell + */ + +#ifndef __IDO_GESTURE_MANAGER_H__ +#define __IDO_GESTURE_MANAGER_H__ + +#include + +G_BEGIN_DECLS + +#define IDO_TYPE_GESTURE_MANAGER (ido_gesture_manager_get_type ()) +#define IDO_GESTURE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IDO_TYPE_GESTURE_MANAGER, IdoGestureManager)) +#define IDO_GESTURE_MANAGER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), IDO_TYPE_GESTURE_MANAGER, IdoGestureManagerClass)) +#define IDO_IS_GESTURE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IDO_TYPE_GESTURE_MANAGER)) +#define IDO_IS_GESTURE_MANAGER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), IDO_TYPE_GESTURE_MANAGER)) +#define IDO_GESTURE_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), IDO_TYPE_GESTURE_MANAGER, IdoGestureManagerClass)) + +typedef struct _IdoGestureManager IdoGestureManager; +typedef struct _IdoGestureManagerClass IdoGestureManagerClass; +typedef struct _IdoGestureManagerPrivate IdoGestureManagerPrivate; + +typedef union _IdoGestureEvent IdoGestureEvent; +typedef struct _IdoEventGestureDrag IdoEventGestureDrag; +typedef struct _IdoEventGesturePinch IdoEventGesturePinch; +typedef struct _IdoEventGestureRotate IdoEventGestureRotate; + +typedef enum { + IDO_GESTURE_DRAG1, + IDO_GESTURE_PINCH1, + IDO_GESTURE_ROTATE1, + + IDO_GESTURE_DRAG2, + IDO_GESTURE_PINCH2, + IDO_GESTURE_ROTATE2, + + IDO_GESTURE_DRAG3, + IDO_GESTURE_PINCH3, + IDO_GESTURE_ROTATE3, + + IDO_GESTURE_DRAG4, + IDO_GESTURE_PINCH4, + IDO_GESTURE_ROTATE4, + + IDO_GESTURE_DRAG5, + IDO_GESTURE_PINCH5, + IDO_GESTURE_ROTATE5, + + IDO_GESTURE_TAP1, + IDO_GESTURE_TAP2, + IDO_GESTURE_TAP3, + IDO_GESTURE_TAP4, + IDO_GESTURE_TAP5 +} IdoGestureType; + +struct _IdoEventGestureDrag +{ + IdoGestureType type; + guint id; + GdkWindow *window; + GdkWindow *root; + GdkWindow *child; + guint32 timestamp; + gint fingers; + gdouble focus_x; + gdouble focus_y; + gint delta_x; + gint delta_y; + gdouble velocity_x; + gdouble velocity_y; + gdouble position_x; + gdouble position_y; +}; + +struct _IdoEventGesturePinch +{ + IdoGestureType type; + guint id; + GdkWindow *window; + GdkWindow *root; + GdkWindow *child; + guint32 timestamp; + guint fingers; + gdouble focus_x; + gdouble focus_y; + gdouble radius_delta; + gdouble radial_velocity; + gdouble radius; +}; + +struct _IdoEventGestureRotate +{ + IdoGestureType type; + guint id; + GdkWindow *window; + GdkWindow *root; + GdkWindow *child; + guint32 timestamp; + guint fingers; + gdouble focus_x; + gdouble focus_y; + gdouble angle_delta; + gdouble angular_velocity; + gdouble angle; +}; + +union _IdoGestureEvent +{ + IdoGestureType type; + IdoEventGestureDrag drag; + IdoEventGesturePinch pinch; + IdoEventGestureRotate rotate; +}; + +struct _IdoGestureManager +{ + GObject parent_instance; + + IdoGestureManagerPrivate *priv; +}; + +struct _IdoGestureManagerClass +{ + GObjectClass parent_class; +}; + +typedef void (* IdoGestureCallback) (GtkWindow *window, + IdoGestureEvent *gesture); + +GType ido_gesture_manager_get_type (void) G_GNUC_CONST; +IdoGestureManager *ido_gesture_manager_get (void); +void ido_gesture_manager_register_window (IdoGestureManager *manager, + GtkWindow *window, + IdoGestureType gesture_type, + IdoGestureCallback start, + IdoGestureCallback update, + IdoGestureCallback end); + +G_END_DECLS + +#endif /* __IDO_GESTURE_MANAGER_H__ */ -- cgit v1.2.3