From 4be23cb80c999dbbf8484e75a34ffa5bc874463d Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Tue, 1 Mar 2011 09:09:59 +0100 Subject: [PATCH] Introduce GdkTouchCluster This is a per-window/device object to gather a group of touch IDs as a single entity. --- docs/reference/gdk/gdk-docs.sgml | 1 + docs/reference/gdk/gdk3-sections.txt | 20 +- docs/reference/gdk/gdk3.types | 1 + gdk/Makefile.am | 2 + gdk/gdk.h | 1 + gdk/gdk.symbols | 5 + gdk/gdktouchcluster.c | 350 +++++++++++++++++++++++++++ gdk/gdktouchcluster.h | 69 ++++++ 8 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 gdk/gdktouchcluster.c create mode 100644 gdk/gdktouchcluster.h diff --git a/docs/reference/gdk/gdk-docs.sgml b/docs/reference/gdk/gdk-docs.sgml index 6534d352b8..21a7cf0521 100644 --- a/docs/reference/gdk/gdk-docs.sgml +++ b/docs/reference/gdk/gdk-docs.sgml @@ -33,6 +33,7 @@ + diff --git a/docs/reference/gdk/gdk3-sections.txt b/docs/reference/gdk/gdk3-sections.txt index a2b5fc0d11..7c4986b6c7 100644 --- a/docs/reference/gdk/gdk3-sections.txt +++ b/docs/reference/gdk/gdk3-sections.txt @@ -766,7 +766,6 @@ gdk_event_get_state gdk_event_get_axis gdk_event_get_coords gdk_event_get_root_coords -gdk_event_get_touch_id gdk_event_request_motions gdk_events_get_angle gdk_events_get_center @@ -846,6 +845,25 @@ gdk_event_get_type gdk_owner_change_get_type +
+Multitouch +touchcluster +GdkTouchCluster +gdk_touch_cluster_add_touch +gdk_touch_cluster_remove_touch +gdk_touch_cluster_remove_all +gdk_touch_cluster_set_device +gdk_touch_cluster_get_device +gdk_touch_cluster_get_touches + + +GDK_TYPE_TOUCH_CLUSTER + + +gdk_touch_cluster_get_type +
+ +
Cursors cursors diff --git a/docs/reference/gdk/gdk3.types b/docs/reference/gdk/gdk3.types index abf4374715..e33ee38433 100644 --- a/docs/reference/gdk/gdk3.types +++ b/docs/reference/gdk/gdk3.types @@ -9,5 +9,6 @@ gdk_display_manager_get_type gdk_drag_context_get_type gdk_keymap_get_type gdk_screen_get_type +gdk_touch_cluster_get_type gdk_visual_get_type gdk_window_get_type diff --git a/gdk/Makefile.am b/gdk/Makefile.am index 8a746c5d60..013e78c14a 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -88,6 +88,7 @@ gdk_public_h_sources = \ gdkselection.h \ gdktestutils.h \ gdkthreads.h \ + gdktouchcluster.h \ gdktypes.h \ gdkvisual.h \ gdkwindow.h @@ -129,6 +130,7 @@ gdk_c_sources = \ gdkrgba.c \ gdkscreen.c \ gdkselection.c \ + gdktouchcluster.c \ gdkvisual.c \ gdkwindow.c \ gdkwindowimpl.c diff --git a/gdk/gdk.h b/gdk/gdk.h index 2b849695d6..5bbf62e58d 100644 --- a/gdk/gdk.h +++ b/gdk/gdk.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index b4478e0226..98abf4fdac 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -319,6 +319,11 @@ gdk_threads_enter gdk_threads_init gdk_threads_leave gdk_threads_set_lock_functions +gdk_touch_cluster_add_touch +gdk_touch_cluster_get_device +gdk_touch_cluster_get_type G_GNUC_CONST +gdk_touch_cluster_list_touches +gdk_touch_cluster_remove_touch gdk_unicode_to_keyval G_GNUC_CONST gdk_utf8_to_string_target gdk_visibility_state_get_type G_GNUC_CONST diff --git a/gdk/gdktouchcluster.c b/gdk/gdktouchcluster.c new file mode 100644 index 0000000000..e8188f705a --- /dev/null +++ b/gdk/gdktouchcluster.c @@ -0,0 +1,350 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2011 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "gdktouchcluster.h" +#include "gdkintl.h" + +/** + * SECTION:touchcluster + * @Short_description: Multitouch handling + * @Title: Multitouch + * @See_also: #GdkEventMultiTouch + * + * #GdkTouchCluster is an object that gathers touch IDs from a + * touch-enabled slave #GdkDevice, in order to send + * #GdkEventMultiTouch events whenever a contained touch ID + * is updated. + * + * #GdkTouchClusters are always associated to a window, + * you need to create them through gdk_window_create_touch_cluster(), + * and free them through gdk_window_remove_touch_cluster(). + * + * Touch IDs from devices can be obtained from %GDK_TOUCH_PRESS, + * %GDK_TOUCH_MOTION or %GDK_TOUCH_RELEASE events through + * gdk_event_get_touch_id(), and then be added via + * gdk_touch_cluster_add_touch(). Note that touch IDs are + * highly transitive, even be an incrementable number only + * identifying the current touch event stream, so touch IDs + * should always be gotten from these events. + * + * Anytime a touch ID is within a cluster, no %GDK_TOUCH_PRESS, + * %GDK_TOUCH_MOTION or %GDK_TOUCH_RELEASE events will happen + * for the individual touch. The event will be available instead + * as part of the #GdkMultitouchEvent that will be emitted. This + * will hold true until gdk_touch_cluster_remove_touch() is + * called for it. Note that GTK+ will automatically take a + * touch ID out of any cluster if %GDK_TOUCH_RELEASE is gotten + * internally. + */ + +typedef struct GdkTouchClusterPrivate GdkTouchClusterPrivate; + +struct GdkTouchClusterPrivate +{ + GdkDevice *device; + GList *touches; +}; + +enum { + PROP_0, + PROP_DEVICE +}; + +enum { + TOUCH_ADDED, + TOUCH_REMOVED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0 }; + +static void gdk_touch_cluster_finalize (GObject *object); +static void gdk_touch_cluster_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gdk_touch_cluster_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + + +G_DEFINE_TYPE (GdkTouchCluster, gdk_touch_cluster, G_TYPE_OBJECT) + +static void +gdk_touch_cluster_class_init (GdkTouchClusterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gdk_touch_cluster_finalize; + object_class->get_property = gdk_touch_cluster_get_property; + object_class->set_property = gdk_touch_cluster_set_property; + + g_object_class_install_property (object_class, + PROP_DEVICE, + g_param_spec_object ("device", + P_("Device"), + P_("Device attached to the cluster"), + GDK_TYPE_DEVICE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + signals[TOUCH_ADDED] = + g_signal_new (g_intern_static_string ("touch-added"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdkTouchClusterClass, touch_added), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + signals[TOUCH_REMOVED] = + g_signal_new (g_intern_static_string ("touch-removed"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdkTouchClusterClass, touch_removed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + + g_type_class_add_private (object_class, sizeof (GdkTouchClusterPrivate)); +} + +static void +gdk_touch_cluster_init (GdkTouchCluster *cluster) +{ + cluster->priv = G_TYPE_INSTANCE_GET_PRIVATE (cluster, + GDK_TYPE_TOUCH_CLUSTER, + GdkTouchClusterPrivate); +} + +static void +gdk_touch_cluster_finalize (GObject *object) +{ + GdkTouchClusterPrivate *priv; + + priv = GDK_TOUCH_CLUSTER (object)->priv; + g_list_free (priv->touches); + + G_OBJECT_CLASS (gdk_touch_cluster_parent_class)->finalize (object); +} + +static void +gdk_touch_cluster_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdkTouchClusterPrivate *priv; + + priv = GDK_TOUCH_CLUSTER (object)->priv; + + switch (prop_id) + { + case PROP_DEVICE: + gdk_touch_cluster_set_device (GDK_TOUCH_CLUSTER (object), + g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gdk_touch_cluster_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdkTouchClusterPrivate *priv; + + priv = GDK_TOUCH_CLUSTER (object)->priv; + + switch (prop_id) + { + case PROP_DEVICE: + g_value_set_object (value, priv->device); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * gdk_touch_cluster_add_touch: + * @cluster: a #GdkTouchCluster + * @touch_id: a touch ID from a touch event + * + * Adds a touch ID to @cluster, so it will generate a + * %GDK_MULTITOUCH_ADDED event, followed by %GDK_MULTITOUCH_UPDATED + * events whenever this touch ID is updated. + * + * If @touch_id already pertained to another #GdkTouchCluster, it + * will be removed from it, generating a %GDK_MULTITOUCH_REMOVED + * for that another cluster. + **/ +void +gdk_touch_cluster_add_touch (GdkTouchCluster *cluster, + guint touch_id) +{ + GdkTouchClusterPrivate *priv; + + g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster)); + + priv = cluster->priv; + + if (!g_list_find (priv->touches, GUINT_TO_POINTER (touch_id))) + { + priv->touches = g_list_prepend (priv->touches, GUINT_TO_POINTER (touch_id)); + g_signal_emit (cluster, signals [TOUCH_ADDED], 0, touch_id); + } +} + +/** + * gdk_touch_cluster_remove_touch: + * @cluster: a #GdkTouchCluster + * @touch_id: a touch ID from a touch event + * + * Removes a touch ID from @cluster, generating a %GDK_MULTITOUCH_REMOVED + * event for @cluster, and causing any further input from @touch_id + * to be reported trough %GDK_TOUCH_MOTION events. + * + * + * Note that GTK+ automatically removes a touch ID from any cluster + * if a %GDK_TOUCH_RELEASE event is gotten internally. + * + **/ +void +gdk_touch_cluster_remove_touch (GdkTouchCluster *cluster, + guint touch_id) +{ + GdkTouchClusterPrivate *priv; + GList *link; + + g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster)); + + priv = cluster->priv; + + link = g_list_find (priv->touches, GUINT_TO_POINTER (touch_id)); + + if (link) + { + priv->touches = g_list_remove_link (priv->touches, link); + g_signal_emit (cluster, signals [TOUCH_REMOVED], 0, touch_id); + g_list_free1 (link); + } +} + +/** + * gdk_touch_cluster_remove_all: + * @cluster: a #GdkTouchCluster + * + * Removes all touch IDs from @cluster. + **/ +void +gdk_touch_cluster_remove_all (GdkTouchCluster *cluster) +{ + GdkTouchClusterPrivate *priv; + GList *link; + + g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster)); + + priv = cluster->priv; + link = priv->touches; + + while (link) + { + priv->touches = g_list_remove_link (priv->touches, link); + g_signal_emit (cluster, signals [TOUCH_REMOVED], 0, link->data); + } + + g_list_free (priv->touches); + priv->touches = NULL; +} + + +/** + * gdk_touch_cluster_get_touches: + * @cluster: a #GdkTouchCluster + * + * Returns a const list of touch IDs as #guint. + * + * Returns: (transfer none): A list of touch IDs. + **/ +GList * +gdk_touch_cluster_get_touches (GdkTouchCluster *cluster) +{ + GdkTouchClusterPrivate *priv; + + g_return_val_if_fail (GDK_IS_TOUCH_CLUSTER (cluster), NULL); + + priv = cluster->priv; + return priv->touches; +} + +/** + * gdk_touch_cluster_set_device: + * @cluster: a #GdkTouchCluster + * @device: a #GdkDevice + * + * Sets the current device associated to @cluster, all contained + * touch IDs must pertain to this device. As a consequence, + * gdk_touch_cluster_remove_all() will be called on @cluster + * if the current device changes. + **/ +void +gdk_touch_cluster_set_device (GdkTouchCluster *cluster, + GdkDevice *device) +{ + GdkTouchClusterPrivate *priv; + + g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster)); + g_return_if_fail (!device || GDK_IS_DEVICE (device)); + + priv = cluster->priv; + + if (priv->device != device) + gdk_touch_cluster_remove_all (cluster); + + priv->device = device; +} + +/** + * gdk_touch_cluster_get_device: + * @cluster: a #GdkTouchCluster + * + * Returns the slave/floating device this touch cluster pertains to, + * only touch IDs from this device can be included in @cluster. + * the #GdkDevice will typically have the %GDK_SOURCE_TOUCH input source. + * + * Returns: (transfer none): The #GdkDevice generating the contained touch IDs + **/ +GdkDevice * +gdk_touch_cluster_get_device (GdkTouchCluster *cluster) +{ + GdkTouchClusterPrivate *priv; + + g_return_val_if_fail (GDK_IS_TOUCH_CLUSTER (cluster), NULL); + + priv = cluster->priv; + return priv->device; +} diff --git a/gdk/gdktouchcluster.h b/gdk/gdktouchcluster.h new file mode 100644 index 0000000000..0904df57dd --- /dev/null +++ b/gdk/gdktouchcluster.h @@ -0,0 +1,69 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2011 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GDK_TOUCH_CLUSTER_H__ +#define __GDK_TOUCH_CLUSTER_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GDK_TYPE_TOUCH_CLUSTER (gdk_touch_cluster_get_type ()) +#define GDK_TOUCH_CLUSTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_TOUCH_CLUSTER, GdkTouchCluster)) +#define GDK_IS_TOUCH_CLUSTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_TOUCH_CLUSTER)) + +typedef struct _GdkTouchCluster GdkTouchCluster; +typedef struct _GdkTouchClusterClass GdkTouchClusterClass; + +struct _GdkTouchCluster +{ + GObject parent_instance; + gpointer priv; +}; + +struct _GdkTouchClusterClass +{ + GObjectClass parent_class; + + void (* touch_added) (GdkTouchCluster *cluster, + guint touch_id); + void (* touch_removed) (GdkTouchCluster *cluster, + guint touch_id); + + gpointer padding[16]; +}; + +GType gdk_touch_cluster_get_type (void) G_GNUC_CONST; + +void gdk_touch_cluster_add_touch (GdkTouchCluster *cluster, + guint touch_id); +void gdk_touch_cluster_remove_touch (GdkTouchCluster *cluster, + guint touch_id); +void gdk_touch_cluster_remove_all (GdkTouchCluster *cluster); + +GList * gdk_touch_cluster_get_touches (GdkTouchCluster *cluster); + +void gdk_touch_cluster_set_device (GdkTouchCluster *cluster, + GdkDevice *device); +GdkDevice * gdk_touch_cluster_get_device (GdkTouchCluster *cluster); + +G_END_DECLS + +#endif /* __GDK_TOUCH_CLUSTER_H__ */