[clutter/android-enter-leave: 29/29] TOFINISH: input-device: add enter/leave events generation for touch events



commit ebacbf92d5e7d29350159e24b9c967d4cbb182bc
Author: Lionel Landwerlin <llandwerlin gmail com>
Date:   Wed Jul 11 16:21:28 2012 +0100

    TOFINISH: input-device: add enter/leave events generation for touch events

 clutter/clutter-device-manager-private.h |   22 ++
 clutter/clutter-device-manager.c         |    2 +-
 clutter/clutter-input-device.c           |  311 +++++++++++++++++++++++++-----
 clutter/clutter-input-device.h           |    5 +
 clutter/clutter-main.c                   |   32 +++-
 clutter/clutter-stage.c                  |    3 +-
 clutter/clutter.symbols                  |    1 +
 7 files changed, 320 insertions(+), 56 deletions(-)
---
diff --git a/clutter/clutter-device-manager-private.h b/clutter/clutter-device-manager-private.h
index c79c6df..f503d4e 100644
--- a/clutter/clutter-device-manager-private.h
+++ b/clutter/clutter-device-manager-private.h
@@ -60,6 +60,15 @@ typedef struct _ClutterScrollInfo
   guint last_value_valid : 1;
 } ClutterScrollInfo;
 
+typedef struct _ClutterTouchInfo
+{
+  ClutterEventSequence *sequence;
+  ClutterActor *actor;
+
+  gint current_x;
+  gint current_y;
+} ClutterTouchInfo;
+
 struct _ClutterInputDevice
 {
   GObject parent_instance;
@@ -82,6 +91,7 @@ struct _ClutterInputDevice
 
   /* the actor underneath the pointer */
   ClutterActor *cursor_actor;
+  GHashTable   *inv_touch_sequence_actors;
 
   /* the actor that has a grab in place for the device */
   ClutterActor *pointer_grab_actor;
@@ -102,6 +112,9 @@ struct _ClutterInputDevice
   gint current_button_number;
   ClutterModifierType current_state;
 
+  /* the current touch points states */
+  GHashTable *touch_sequences_info;
+
   /* the previous state, used for click count generation */
   gint previous_x;
   gint previous_y;
@@ -144,7 +157,14 @@ void            _clutter_device_manager_select_stage_events     (ClutterDeviceMa
 ClutterBackend *_clutter_device_manager_get_backend             (ClutterDeviceManager *device_manager);
 
 /* input device */
+gboolean        _clutter_input_device_has_sequence              (ClutterInputDevice   *device,
+                                                                 ClutterEventSequence *sequence);
+void            _clutter_input_device_add_sequence              (ClutterInputDevice   *device,
+                                                                 ClutterEventSequence *sequence);
+void            _clutter_input_device_remove_sequence           (ClutterInputDevice   *device,
+                                                                 ClutterEventSequence *sequence);
 void            _clutter_input_device_set_coords                (ClutterInputDevice   *device,
+                                                                 ClutterEventSequence *sequence,
                                                                  gint                  x,
                                                                  gint                  y);
 void            _clutter_input_device_set_state                 (ClutterInputDevice   *device,
@@ -155,9 +175,11 @@ void            _clutter_input_device_set_stage                 (ClutterInputDev
                                                                  ClutterStage         *stage);
 ClutterStage *  _clutter_input_device_get_stage                 (ClutterInputDevice   *device);
 void            _clutter_input_device_set_actor                 (ClutterInputDevice   *device,
+                                                                 ClutterEventSequence *sequence,
                                                                  ClutterActor         *actor,
                                                                  gboolean              emit_crossing);
 ClutterActor *  _clutter_input_device_update                    (ClutterInputDevice   *device,
+                                                                 ClutterEventSequence *sequence,
                                                                  gboolean              emit_crossing);
 void            _clutter_input_device_set_n_keys                (ClutterInputDevice   *device,
                                                                  guint                 n_keys);
diff --git a/clutter/clutter-device-manager.c b/clutter/clutter-device-manager.c
index 0015c1a..2dc67be 100644
--- a/clutter/clutter-device-manager.c
+++ b/clutter/clutter-device-manager.c
@@ -423,7 +423,7 @@ _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager)
       if (!clutter_stage_get_motion_events_enabled (device->stage))
         continue;
 
-      _clutter_input_device_update (device, TRUE);
+      _clutter_input_device_update (device, NULL, TRUE);
     }
 }
 
diff --git a/clutter/clutter-input-device.c b/clutter/clutter-input-device.c
index a0ba262..5ad75ce 100644
--- a/clutter/clutter-input-device.c
+++ b/clutter/clutter-input-device.c
@@ -100,6 +100,25 @@ clutter_input_device_dispose (GObject *gobject)
       device->keys = NULL;
     }
 
+  if (device->touch_sequences_info)
+    {
+      g_hash_table_unref (device->touch_sequences_info);
+      device->touch_sequences_info = NULL;
+    }
+
+  if (device->inv_touch_sequence_actors)
+    {
+      GHashTableIter iter;
+      gpointer key, value;
+
+      g_hash_table_iter_init (&iter, device->inv_touch_sequence_actors);
+      while (g_hash_table_iter_next (&iter, &key, &value))
+        g_list_free (value);
+
+      g_hash_table_unref (device->inv_touch_sequence_actors);
+      device->inv_touch_sequence_actors = NULL;
+    }
+
   G_OBJECT_CLASS (clutter_input_device_parent_class)->dispose (gobject);
 }
 
@@ -365,6 +384,12 @@ clutter_input_device_init (ClutterInputDevice *self)
   self->current_y = self->previous_y = -1;
   self->current_button_number = self->previous_button_number = -1;
   self->current_state = self->previous_state = 0;
+
+  self->touch_sequences_info = g_hash_table_new_full (g_direct_hash,
+                                                      g_direct_equal,
+                                                      NULL,
+                                                      g_free);
+  self->inv_touch_sequence_actors = g_hash_table_new (NULL, NULL);
 }
 
 /*< private >
@@ -376,17 +401,38 @@ clutter_input_device_init (ClutterInputDevice *self)
  * Stores the last known coordinates of the device
  */
 void
-_clutter_input_device_set_coords (ClutterInputDevice *device,
-                                  gint                x,
-                                  gint                y)
+_clutter_input_device_set_coords (ClutterInputDevice   *device,
+                                  ClutterEventSequence *sequence,
+                                  gint                  x,
+                                  gint                  y)
 {
   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
 
-  if (device->current_x != x)
-    device->current_x = x;
+  if (sequence == NULL)
+    {
+      if (device->current_x != x)
+        device->current_x = x;
+
+      if (device->current_y != y)
+        device->current_y = y;
+    }
+  else
+    {
+      ClutterTouchInfo *info =
+        g_hash_table_lookup (device->touch_sequences_info, sequence);
+
+      if (info == NULL)
+        {
+          g_message ("set coords on %p %ix%i", sequence, x, y);
+
+          info = g_new0 (ClutterTouchInfo, 1);
+          info->sequence = sequence;
+          g_hash_table_insert (device->touch_sequences_info, sequence, info);
+        }
 
-  if (device->current_y != y)
-    device->current_y = y;
+      info->current_x = x;
+      info->current_y = y;
+    }
 }
 
 /*< private >
@@ -422,13 +468,6 @@ _clutter_input_device_set_time (ClutterInputDevice *device,
     device->current_time = time_;
 }
 
-static void
-on_cursor_actor_destroy (ClutterActor       *actor,
-                         ClutterInputDevice *device)
-{
-  device->cursor_actor = NULL;
-}
-
 /*< private >
  * clutter_input_device_set_stage:
  * @device: a #ClutterInputDevice
@@ -466,6 +505,99 @@ _clutter_input_device_get_stage (ClutterInputDevice *device)
   return device->stage;
 }
 
+static ClutterActor *
+_clutter_input_device_get_actor (ClutterInputDevice   *device,
+                                 ClutterEventSequence *sequence)
+{
+  ClutterTouchInfo *info;
+
+  if (sequence == NULL)
+    return device->cursor_actor;
+
+  info = g_hash_table_lookup (device->touch_sequences_info, sequence);
+
+  return info->actor;
+}
+
+static void on_cursor_actor_destroy (ClutterActor       *actor,
+                                     ClutterInputDevice *device);
+
+static void
+_clutter_input_device_associate_actor (ClutterInputDevice   *device,
+                                       ClutterEventSequence *sequence,
+                                       ClutterActor         *actor)
+{
+  if (sequence == NULL)
+    device->cursor_actor = actor;
+  else
+    {
+      ClutterTouchInfo *info =
+        g_hash_table_lookup (device->touch_sequences_info, sequence);
+      GList *sequences =
+        g_hash_table_lookup (device->inv_touch_sequence_actors, actor);
+
+      if (info == NULL)
+        {
+          g_message ("associate actor on %p", sequence);
+          info = g_new0 (ClutterTouchInfo, 1);
+          info->sequence = sequence;
+          g_hash_table_insert (device->touch_sequences_info, sequence, info);
+        }
+
+      info->actor = actor;
+
+      g_hash_table_insert (device->inv_touch_sequence_actors,
+                           actor, g_list_prepend (sequences, sequence));
+    }
+
+  g_signal_connect (actor,
+                    "destroy", G_CALLBACK (on_cursor_actor_destroy),
+                    device);
+  _clutter_actor_set_has_pointer (actor, TRUE);
+}
+
+static void
+_clutter_input_device_unassociate_actor (ClutterInputDevice   *device,
+                                         ClutterActor         *actor,
+                                         gboolean              destroyed)
+{
+  if (device->cursor_actor == actor)
+    device->cursor_actor = NULL;
+  else
+    {
+      GList *l, *sequences =
+        g_hash_table_lookup (device->inv_touch_sequence_actors,
+                             actor);
+
+      for (l = sequences; l != NULL; l = l->next)
+        {
+          ClutterTouchInfo *info =
+            g_hash_table_lookup (device->touch_sequences_info, l->data);
+
+          if (info)
+            info->actor = NULL;
+        }
+
+      g_list_free (sequences);
+      g_hash_table_remove (device->inv_touch_sequence_actors, actor);
+    }
+
+  if (destroyed == FALSE)
+    {
+      g_signal_handlers_disconnect_by_func (actor,
+                                            G_CALLBACK (on_cursor_actor_destroy),
+                                            device);
+      _clutter_actor_set_has_pointer (actor, FALSE);
+    }
+}
+
+static void
+on_cursor_actor_destroy (ClutterActor       *actor,
+                         ClutterInputDevice *device)
+{
+  _clutter_input_device_unassociate_actor (device, actor, TRUE);
+}
+
 /*< private >
  * clutter_input_device_set_actor:
  * @device: a #ClutterInputDevice
@@ -486,28 +618,32 @@ _clutter_input_device_get_stage (ClutterInputDevice *device)
  *     actor
  */
 void
-_clutter_input_device_set_actor (ClutterInputDevice *device,
-                                 ClutterActor       *actor,
-                                 gboolean            emit_crossing)
+_clutter_input_device_set_actor (ClutterInputDevice   *device,
+                                 ClutterEventSequence *sequence,
+                                 ClutterActor         *actor,
+                                 gboolean              emit_crossing)
 {
-  ClutterActor *old_actor;
+  ClutterActor *old_actor = _clutter_input_device_get_actor (device,
+                                                             sequence);
 
-  if (device->cursor_actor == actor)
+  if (old_actor == actor)
     return;
 
-  old_actor = device->cursor_actor;
-
   if (old_actor != NULL)
     {
+      ClutterActor *tmp_old_actor;
+
       if (emit_crossing)
         {
           ClutterEvent *event;
 
+          g_message ("emit leave crossing");
+
           event = clutter_event_new (CLUTTER_LEAVE);
           event->crossing.time = device->current_time;
           event->crossing.flags = 0;
           event->crossing.stage = device->stage;
-          event->crossing.source = device->cursor_actor;
+          event->crossing.source = old_actor;
           event->crossing.x = device->current_x;
           event->crossing.y = device->current_y;
           event->crossing.related = actor;
@@ -524,23 +660,23 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
         }
 
       /* processing the event might have destroyed the actor */
-      if (device->cursor_actor != NULL)
-        {
-          _clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
-          g_signal_handlers_disconnect_by_func (device->cursor_actor,
-                                                G_CALLBACK (on_cursor_actor_destroy),
-                                                device);
-
-          device->cursor_actor = NULL;
-        }
+      tmp_old_actor = _clutter_input_device_get_actor (device, sequence);
+      _clutter_input_device_unassociate_actor (device,
+                                               old_actor,
+                                               tmp_old_actor == NULL);
+      old_actor = tmp_old_actor;
     }
 
   if (actor != NULL)
     {
+      _clutter_input_device_associate_actor (device, sequence, actor);
+
       if (emit_crossing)
         {
           ClutterEvent *event;
 
+          g_message ("emit enter crossing");
+
           event = clutter_event_new (CLUTTER_ENTER);
           event->crossing.time = device->current_time;
           event->crossing.flags = 0;
@@ -557,15 +693,6 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
           clutter_event_free (event);
         }
     }
-
-  device->cursor_actor = actor;
-  if (device->cursor_actor != NULL)
-    {
-      g_signal_connect (device->cursor_actor,
-                        "destroy", G_CALLBACK (on_cursor_actor_destroy),
-                        device);
-      _clutter_actor_set_has_pointer (device->cursor_actor, TRUE);
-    }
 }
 
 /**
@@ -679,6 +806,49 @@ clutter_input_device_get_device_coords (ClutterInputDevice *device,
     *y = device->current_y;
 }
 
+/**
+ * clutter_input_device_get_coords:
+ * @device: a #ClutterInputDevice
+ * @sequence: a #ClutterEventSequence
+ * @x: (out): return location for the X coordinate
+ * @y: (out): return location for the Y coordinate
+ *
+ * Retrieves the latest coordinates of a sequence of @device
+ *
+ * Since: 1.12
+ */
+void
+clutter_input_device_get_coords (ClutterInputDevice   *device,
+                                 ClutterEventSequence *sequence,
+                                 gint                 *x,
+                                 gint                 *y)
+{
+  g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
+
+  if (sequence == NULL)
+    {
+      if (x)
+        *x = device->current_x;
+
+      if (y)
+        *y = device->current_y;
+    }
+  else
+    {
+      ClutterTouchInfo *info =
+        g_hash_table_lookup (device->touch_sequences_info, sequence);
+
+      if (info != NULL)
+        {
+          if (x)
+            *x = info->current_x;
+
+          if (y)
+            *y = info->current_y;
+        }
+    }
+}
+
 /*
  * _clutter_input_device_update:
  * @device: a #ClutterInputDevice
@@ -694,8 +864,9 @@ clutter_input_device_get_device_coords (ClutterInputDevice *device,
  * Since: 1.2
  */
 ClutterActor *
-_clutter_input_device_update (ClutterInputDevice *device,
-                              gboolean            emit_crossing)
+_clutter_input_device_update (ClutterInputDevice   *device,
+                              ClutterEventSequence *sequence,
+                              gboolean              emit_crossing)
 {
   ClutterStage *stage;
   ClutterActor *new_cursor_actor;
@@ -713,11 +884,12 @@ _clutter_input_device_update (ClutterInputDevice *device,
       return NULL;
     }
 
-  clutter_input_device_get_device_coords (device, &x, &y);
+  clutter_input_device_get_coords (device, sequence, &x, &y);
 
-  old_cursor_actor = device->cursor_actor;
+  old_cursor_actor = _clutter_input_device_get_actor (device, sequence);
   new_cursor_actor =
     _clutter_stage_do_pick (stage, x, y, CLUTTER_PICK_REACTIVE);
+  g_message ("picking sequence=%p in device_update at %ix%i", sequence, x, y);
 
   /* if the pick could not find an actor then we do not update the
    * input device, to avoid ghost enter/leave events; the pick should
@@ -739,7 +911,9 @@ _clutter_input_device_update (ClutterInputDevice *device,
   if (new_cursor_actor == old_cursor_actor)
     return old_cursor_actor;
 
-  _clutter_input_device_set_actor (device, new_cursor_actor, emit_crossing);
+  _clutter_input_device_set_actor (device, sequence,
+                                   new_cursor_actor,
+                                   emit_crossing);
 
   return device->cursor_actor;
 }
@@ -909,6 +1083,7 @@ clutter_input_device_update_from_event (ClutterInputDevice *device,
                                         gboolean            update_stage)
 {
   ClutterModifierType event_state;
+  ClutterEventSequence *sequence;
   ClutterStage *event_stage;
   gfloat event_x, event_y;
   guint32 event_time;
@@ -919,9 +1094,10 @@ clutter_input_device_update_from_event (ClutterInputDevice *device,
   event_state = clutter_event_get_state (event);
   event_time = clutter_event_get_time (event);
   event_stage = clutter_event_get_stage (event);
+  sequence = clutter_event_get_event_sequence (event);
   clutter_event_get_coords (event, &event_x, &event_y);
 
-  _clutter_input_device_set_coords (device, event_x, event_y);
+  _clutter_input_device_set_coords (device, sequence, event_x, event_y);
   _clutter_input_device_set_state (device, event_state);
   _clutter_input_device_set_time (device, event_time);
 
@@ -1306,6 +1482,49 @@ _clutter_input_device_remove_slave (ClutterInputDevice *master,
     master->slaves = g_list_remove (master->slaves, slave);
 }
 
+void
+_clutter_input_device_add_sequence (ClutterInputDevice   *device,
+                                    ClutterEventSequence *sequence)
+{
+  ClutterTouchInfo *info =
+    g_hash_table_lookup (device->touch_sequences_info, sequence);
+
+  if (info != NULL)
+    return;
+
+  g_message ("add sequence %p", sequence);
+
+  info = g_new0 (ClutterTouchInfo, 1);
+  info->sequence = sequence;
+  g_hash_table_insert (device->touch_sequences_info, sequence, info);
+}
+
+void
+_clutter_input_device_remove_sequence (ClutterInputDevice   *device,
+                                       ClutterEventSequence *sequence)
+{
+  ClutterTouchInfo *info =
+    g_hash_table_lookup (device->touch_sequences_info, sequence);
+
+  if (info == NULL)
+    return;
+
+  g_message ("remove sequence %p", sequence);
+
+  if (info->actor != NULL)
+    {
+      GList *sequences =
+        g_hash_table_lookup (device->inv_touch_sequence_actors, info->actor);
+
+      sequences = g_list_remove (sequences, sequence);
+
+      g_hash_table_replace (device->inv_touch_sequence_actors,
+                            info->actor, sequence);
+    }
+
+  g_hash_table_remove (device->touch_sequences_info, sequence);
+}
+
 /**
  * clutter_input_device_get_slave_devices:
  * @device: a #ClutterInputDevice
diff --git a/clutter/clutter-input-device.h b/clutter/clutter-input-device.h
index 7b60e43..8228215 100644
--- a/clutter/clutter-input-device.h
+++ b/clutter/clutter-input-device.h
@@ -54,6 +54,11 @@ gint                    clutter_input_device_get_device_id      (ClutterInputDev
 void                    clutter_input_device_get_device_coords  (ClutterInputDevice  *device,
                                                                  gint                *x,
                                                                  gint                *y);
+CLUTTER_AVAILABLE_IN_1_12
+void                    clutter_input_device_get_coords        (ClutterInputDevice   *device,
+                                                                ClutterEventSequence *sequence,
+                                                                gint                 *x,
+                                                                gint                 *y);
 ClutterActor *          clutter_input_device_get_pointer_actor  (ClutterInputDevice  *device);
 ClutterStage *          clutter_input_device_get_pointer_stage  (ClutterInputDevice  *device);
 const gchar *           clutter_input_device_get_device_name    (ClutterInputDevice  *device);
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index 7273f88..bf41c08 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -2265,6 +2265,7 @@ emit_event (ClutterEvent *event,
           parent == NULL ||         /* stage gets all events */
           is_key_event)             /* keyboard events are always emitted */
         {
+          g_message ("\temit event %p/%s", actor, G_OBJECT_TYPE_NAME (actor));
           g_ptr_array_add (event_tree, g_object_ref (actor));
         }
 
@@ -2333,11 +2334,13 @@ emit_touch_event (ClutterEvent       *event,
                                            event->touch.sequence)) != NULL))
     {
       /* sequence grab */
+      g_message ("emit grabbed touch event %p", event->touch.sequence);
       clutter_actor_event (grab_actor, event, FALSE);
     }
   else
     {
       /* no grab, time to capture and bubble */
+      g_message ("emit touch event %p", event->touch.sequence);
       emit_event (event, FALSE);
     }
 }
@@ -2424,9 +2427,7 @@ _clutter_process_event_details (ClutterActor        *stage,
                                 ClutterMainContext  *context,
                                 ClutterEvent        *event)
 {
-  ClutterInputDevice *device = NULL;
-
-  device = clutter_event_get_device (event);
+  ClutterInputDevice *device = clutter_event_get_device (event);
 
   switch (event->type)
     {
@@ -2467,7 +2468,7 @@ _clutter_process_event_details (ClutterActor        *stage,
 
             emit_pointer_event (event, device);
 
-            actor = _clutter_input_device_update (device, FALSE);
+            actor = _clutter_input_device_update (device, NULL, FALSE);
             if (actor != stage)
               {
                 ClutterEvent *crossing;
@@ -2601,7 +2602,7 @@ _clutter_process_event_details (ClutterActor        *stage,
                * get the actor underneath
                */
               if (device != NULL)
-                actor = _clutter_input_device_update (device, TRUE);
+                actor = _clutter_input_device_update (device, NULL, TRUE);
               else
                 {
                   CLUTTER_NOTE (EVENT, "No device found: picking");
@@ -2644,8 +2645,13 @@ _clutter_process_event_details (ClutterActor        *stage,
       case CLUTTER_TOUCH_END:
         {
           ClutterActor *actor;
+          ClutterEventSequence *sequence =
+            clutter_event_get_event_sequence (event);
           gfloat x, y;
 
+          if (event->type == CLUTTER_TOUCH_BEGIN)
+            _clutter_input_device_add_sequence (device, sequence);
+
           clutter_event_get_coords (event, &x, &y);
 
           /* Only do a pick to find the source if source is not already set
@@ -2653,9 +2659,15 @@ _clutter_process_event_details (ClutterActor        *stage,
            */
           if (event->any.source == NULL)
             {
-              actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage),
-                                              x, y,
-                                              CLUTTER_PICK_REACTIVE);
+              if (device != NULL)
+                actor = _clutter_input_device_update (device, sequence, TRUE);
+              else
+                {
+                  actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage),
+                                                  x, y,
+                                                  CLUTTER_PICK_REACTIVE);
+                }
+
               if (actor == NULL)
                 break;
 
@@ -2673,6 +2685,10 @@ _clutter_process_event_details (ClutterActor        *stage,
                         actor);
 
           emit_touch_event (event, device);
+
+          if (event->type == CLUTTER_TOUCH_END)
+            _clutter_input_device_remove_sequence (device, sequence);
+
           break;
         }
 
diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c
index 1525ca8..2bc175d 100644
--- a/clutter/clutter-stage.c
+++ b/clutter/clutter-stage.c
@@ -941,12 +941,13 @@ _clutter_stage_queue_event (ClutterStage *stage,
   if (device != NULL)
     {
       ClutterModifierType event_state = clutter_event_get_state (event);
+      ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
       guint32 event_time = clutter_event_get_time (event);
       gfloat event_x, event_y;
 
       clutter_event_get_coords (event, &event_x, &event_y);
 
-      _clutter_input_device_set_coords (device, event_x, event_y);
+      _clutter_input_device_set_coords (device, sequence, event_x, event_y);
       _clutter_input_device_set_state (device, event_state);
       _clutter_input_device_set_time (device, event_time);
     }
diff --git a/clutter/clutter.symbols b/clutter/clutter.symbols
index 106f82d..0365e5a 100644
--- a/clutter/clutter.symbols
+++ b/clutter/clutter.symbols
@@ -771,6 +771,7 @@ clutter_input_axis_get_type
 clutter_input_device_get_associated_device
 clutter_input_device_get_axis
 clutter_input_device_get_axis_value
+clutter_input_device_get_coords
 clutter_input_device_get_device_coords
 clutter_input_device_get_device_id
 clutter_input_device_get_device_name



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]