[gtk+/multitouch: 101/121] gdk,csw: handle implicit touch grabs



commit 65a6b27aff7bd6e5a3061457adc0d76ff7003678
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Dec 29 00:06:45 2011 +0100

    gdk,csw: handle implicit touch grabs
    
    If the touch sequence happens on a window with GDK_TOUCH_MASK set,
    a GdkTouchGrabInfo is created to back it up. Else a device grab is
    only created if the sequence emulates the pointer.
    
    If both a device and a touch grab are present on a window, the later
    of them both is obeyed, Any grab on the device happening after a
    touch grab generates grab broken on all the windows an implicit
    touch grab was going on, and all touches would be automatically
    removed from every touch cluster.

 gdk/gdkdisplay.c   |   38 +++++++++++-
 gdk/gdkinternals.h |    3 +
 gdk/gdkwindow.c    |  156 ++++++++++++++++++++++++++++++++++++++++------------
 3 files changed, 157 insertions(+), 40 deletions(-)
---
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index 10b2462..a1f322f 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -697,6 +697,33 @@ _gdk_display_add_device_grab (GdkDisplay       *display,
   return info;
 }
 
+static void
+_gdk_display_break_touch_grabs (GdkDisplay *display,
+                                GdkDevice  *device,
+                                GdkWindow  *new_grab_window)
+{
+  guint i = 0;
+
+  while (i < display->touch_implicit_grabs->len)
+    {
+      GdkTouchGrabInfo *info;
+
+      info = &g_array_index (display->touch_implicit_grabs,
+                             GdkTouchGrabInfo, i);
+
+      if (info->device == device &&
+          info->window != new_grab_window)
+        {
+          generate_grab_broken_event (GDK_WINDOW (info->window),
+                                      device, TRUE, new_grab_window);
+          _gdk_window_finish_touch_id (info->window, device, info->touch_id);
+          g_array_remove_index_fast (display->touch_implicit_grabs, i);
+        }
+      else
+        i++;
+    }
+}
+
 void
 _gdk_display_add_touch_grab (GdkDisplay    *display,
                              GdkDevice     *device,
@@ -1025,12 +1052,15 @@ _gdk_display_device_grab_update (GdkDisplay *display,
 	    next_grab = NULL; /* Actually its not yet active */
 	}
 
+      if (next_grab)
+        _gdk_display_break_touch_grabs (display, device, next_grab->window);
+
       if ((next_grab == NULL && current_grab->implicit_ungrab) ||
-	  (next_grab != NULL && current_grab->window != next_grab->window))
-	generate_grab_broken_event (GDK_WINDOW (current_grab->window),
+          (next_grab != NULL && current_grab->window != next_grab->window))
+        generate_grab_broken_event (GDK_WINDOW (current_grab->window),
                                     device,
-				    current_grab->implicit,
-				    next_grab? next_grab->window : NULL);
+                                    current_grab->implicit,
+                                    next_grab? next_grab->window : NULL);
 
       /* Remove old grab */
       grabs = g_list_delete_link (grabs, grabs);
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 150c909..50537e8 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -334,6 +334,9 @@ gboolean   _gdk_window_update_viewable   (GdkWindow      *window);
 
 void       _gdk_window_process_updates_recurse (GdkWindow *window,
                                                 cairo_region_t *expose_region);
+gboolean   _gdk_window_finish_touch_id   (GdkWindow      *window,
+                                          GdkDevice      *device,
+                                          guint           touch_id);
 
 void       _gdk_screen_close             (GdkScreen      *screen);
 
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 4368052..82ea271 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -9200,18 +9200,37 @@ _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
 static GdkWindow *
 get_event_window (GdkDisplay                 *display,
                   GdkDevice                  *device,
-		  GdkWindow                  *pointer_window,
-		  GdkEventType                type,
-		  GdkModifierType             mask,
-		  guint                      *evmask_out,
-		  gulong                      serial)
+                  guint                       touch_id,
+                  GdkWindow                  *pointer_window,
+                  GdkEventType                type,
+                  GdkModifierType             mask,
+                  guint                      *evmask_out,
+                  gulong                      serial)
 {
   guint evmask;
   GdkWindow *grab_window;
   GdkDeviceGrabInfo *grab;
+  GdkTouchGrabInfo *touch_grab;
 
+  touch_grab = _gdk_display_has_touch_grab (display, device, touch_id, serial);
   grab = _gdk_display_has_device_grab (display, device, serial);
 
+  if (touch_grab != NULL &&
+      (!grab || grab->implicit || touch_grab->serial >= grab->serial_start))
+    {
+      evmask = touch_grab->event_mask;
+      evmask = update_evmask_for_button_motion (evmask, mask);
+
+      if (evmask & type_masks[type])
+        {
+          if (evmask_out)
+            *evmask_out = evmask;
+          return touch_grab->window;
+        }
+      else
+        return NULL;
+    }
+
   if (grab != NULL && !grab->owner_events)
     {
       evmask = grab->event_mask;
@@ -9384,6 +9403,24 @@ _gdk_window_lookup_touch_cluster (GdkWindow *window,
   return info->cluster;
 }
 
+gboolean
+_gdk_window_finish_touch_id (GdkWindow *window,
+                             GdkDevice *device,
+                             guint      touch_id)
+{
+  TouchEventInfo *info;
+
+  info = touch_event_info_lookup (window, device, touch_id, FALSE);
+
+  if (info)
+    {
+      gdk_touch_cluster_remove_touch (info->cluster, touch_id);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 static gboolean
 proxy_pointer_event (GdkDisplay                 *display,
 		     GdkEvent                   *source_event,
@@ -9536,9 +9573,14 @@ proxy_pointer_event (GdkDisplay                 *display,
       GdkWindow *event_win;
       guint evmask;
       gboolean is_hint;
+      guint touch_id;
+
+      if (!gdk_event_get_touch_id (source_event, &touch_id))
+        touch_id = 0;
 
       event_win = get_event_window (display,
                                     device,
+                                    touch_id,
                                     pointer_window,
                                     source_event->type,
                                     state,
@@ -9670,6 +9712,7 @@ proxy_button_event (GdkEvent *source_event,
   GdkWindow *w;
   GdkDevice *device, *source_device;
   GdkEventMask evmask;
+  guint touch_id;
 
   type = source_event->any.type;
   event_window = source_event->any.window;
@@ -9683,10 +9726,14 @@ proxy_button_event (GdkEvent *source_event,
 						       toplevel_x, toplevel_y,
 						       &toplevel_x, &toplevel_y);
 
+  if (!gdk_event_get_touch_id (source_event, &touch_id))
+    touch_id = 0;
+
   pointer_info = _gdk_display_get_pointer_info (display, device);
   *handle_ungrab = TRUE;
 
-  if (type == GDK_BUTTON_PRESS &&
+  if ((type == GDK_BUTTON_PRESS ||
+       type == GDK_TOUCH_PRESS) &&
       !source_event->any.send_event &&
       _gdk_display_has_device_grab (display, device, serial) == NULL)
     {
@@ -9701,23 +9748,49 @@ proxy_button_event (GdkEvent *source_event,
 	     (parent = get_event_parent (w)) != NULL &&
 	     parent->window_type != GDK_WINDOW_ROOT)
 	{
-	  if (w->event_mask & GDK_BUTTON_PRESS_MASK)
+	  if (w->event_mask & GDK_BUTTON_PRESS_MASK &&
+              (type == GDK_BUTTON_PRESS ||
+               _gdk_event_get_pointer_emulated (source_event)))
 	    break;
+
+          if (type == GDK_TOUCH_PRESS &&
+              w->event_mask & GDK_TOUCH_MASK)
+            break;
+
 	  w = parent;
 	}
-      pointer_window = (GdkWindow *)w;
-
-      _gdk_display_add_device_grab  (display,
-                                     device,
-                                     pointer_window,
-                                     event_window,
-                                     GDK_OWNERSHIP_NONE,
-                                     FALSE,
-                                     gdk_window_get_events (pointer_window),
-                                     serial,
-				     time_,
-                                     TRUE);
-      _gdk_display_device_grab_update (display, device, source_device, serial);
+      pointer_window = w;
+
+      if (pointer_window)
+        {
+          if (type == GDK_TOUCH_PRESS &&
+              pointer_window->event_mask & GDK_TOUCH_MASK)
+            {
+              guint touch_id;
+
+              gdk_event_get_touch_id (source_event, &touch_id);
+              _gdk_display_add_touch_grab (display, device, touch_id,
+                                           pointer_window, event_window,
+                                           gdk_window_get_events (pointer_window),
+                                           serial, time_);
+            }
+          else if (type == GDK_BUTTON_PRESS ||
+                   _gdk_event_get_pointer_emulated (source_event))
+            {
+              _gdk_display_add_device_grab  (display,
+                                             device,
+                                             pointer_window,
+                                             event_window,
+                                             GDK_OWNERSHIP_NONE,
+                                             FALSE,
+                                             gdk_window_get_events (pointer_window),
+                                             serial,
+                                             time_,
+                                             TRUE);
+              _gdk_display_device_grab_update (display, device,
+                                               source_device, serial);
+            }
+        }
     }
 
   pointer_window = get_pointer_window (display, toplevel_window, device,
@@ -9726,9 +9799,10 @@ proxy_button_event (GdkEvent *source_event,
 
   event_win = get_event_window (display,
                                 device,
-				pointer_window,
-				type, state,
-				&evmask, serial);
+                                touch_id,
+                                pointer_window,
+                                type, state,
+                                &evmask, serial);
 
   if (event_win == NULL || display->ignore_core_events)
     return TRUE;
@@ -9838,9 +9912,6 @@ proxy_button_event (GdkEvent *source_event,
 
       if (by_touch)
         g_hash_table_remove (by_touch, GUINT_TO_POINTER (touch_id));
-
-      /* Only remove the grab if it was the last pending touch on the window */
-      *handle_ungrab = (g_hash_table_size (by_touch) == 0);
     }
   else if (type == GDK_TOUCH_PRESS)
     store_touch_event (event_win, gdk_event_copy (event),
@@ -10098,16 +10169,29 @@ _gdk_windowing_got_event (GdkDisplay *display,
        event->type == GDK_TOUCH_RELEASE) &&
       !event->any.send_event)
     {
-      button_release_grab =
-	_gdk_display_has_device_grab (display, device, serial);
-      if (button_release_grab &&
-	  button_release_grab->implicit &&
-	  (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
-	{
-	  button_release_grab->serial_end = serial;
-	  button_release_grab->implicit_ungrab = FALSE;
-	  _gdk_display_device_grab_update (display, device, source_device, serial);
-	}
+      guint touch_id;
+
+      if (event->type == GDK_TOUCH_RELEASE &&
+          gdk_event_get_touch_id (event, &touch_id))
+        {
+          _gdk_display_end_touch_grab (display, device, touch_id);
+        }
+
+      if (event->type == GDK_BUTTON_RELEASE ||
+          _gdk_event_get_pointer_emulated (event))
+        {
+          button_release_grab =
+            _gdk_display_has_device_grab (display, device, serial);
+
+          if (button_release_grab &&
+              button_release_grab->implicit &&
+              (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
+            {
+              button_release_grab->serial_end = serial;
+              button_release_grab->implicit_ungrab = FALSE;
+              _gdk_display_device_grab_update (display, device, source_device, serial);
+            }
+        }
     }
 
  out:



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