[gtk+] gdk: handle implicit touch grabs



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

    gdk: 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.

 gdk/gdkdisplay.c |   11 ++-
 gdk/gdkwindow.c  |  210 ++++++++++++++++++++++++++++++++++++++++++------------
 gtk/gtkmain.c    |   17 +++++
 3 files changed, 189 insertions(+), 49 deletions(-)
---
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index 5684247..b62b810 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -1049,12 +1049,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/gdkwindow.c b/gdk/gdkwindow.c
index 4022b91..f5f07b2 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -8156,6 +8156,8 @@ is_button_type (GdkEventType type)
 	 type == GDK_2BUTTON_PRESS ||
 	 type == GDK_3BUTTON_PRESS ||
 	 type == GDK_BUTTON_RELEASE ||
+         type == GDK_TOUCH_BEGIN ||
+         type == GDK_TOUCH_END ||
 	 type == GDK_SCROLL;
 }
 
@@ -8163,6 +8165,7 @@ static gboolean
 is_motion_type (GdkEventType type)
 {
   return type == GDK_MOTION_NOTIFY ||
+         type == GDK_TOUCH_UPDATE ||
 	 type == GDK_ENTER_NOTIFY ||
 	 type == GDK_LEAVE_NOTIFY;
 }
@@ -9109,18 +9112,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)
+                  GdkEventSequence           *sequence,
+                  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, sequence, 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;
@@ -9320,14 +9342,19 @@ proxy_pointer_event (GdkDisplay                 *display,
 				       serial, non_linear);
       _gdk_display_set_window_under_pointer (display, device, pointer_window);
     }
-  else if (source_event->type == GDK_MOTION_NOTIFY)
+  else if (source_event->type == GDK_MOTION_NOTIFY ||
+           source_event->type == GDK_TOUCH_UPDATE)
     {
       GdkWindow *event_win;
       guint evmask;
       gboolean is_hint;
+      GdkEventSequence *sequence;
+
+      sequence = gdk_event_get_event_sequence (source_event);
 
       event_win = get_event_window (display,
                                     device,
+                                    sequence,
                                     pointer_window,
                                     source_event->type,
                                     state,
@@ -9351,6 +9378,7 @@ proxy_pointer_event (GdkDisplay                 *display,
                                          toplevel_x, toplevel_y,
                                          state, time_, NULL,
                                          serial, FALSE);
+
       is_hint = FALSE;
 
       if (event_win &&
@@ -9371,21 +9399,34 @@ proxy_pointer_event (GdkDisplay                 *display,
 	    }
 	}
 
-      if (event_win && !display->ignore_core_events)
-	{
-	  event = _gdk_make_event (event_win, GDK_MOTION_NOTIFY, source_event, FALSE);
-	  event->motion.time = time_;
-	  convert_toplevel_coords_to_window (event_win,
-					     toplevel_x, toplevel_y,
-					     &event->motion.x, &event->motion.y);
-	  event->motion.x_root = source_event->motion.x_root;
-	  event->motion.y_root = source_event->motion.y_root;
-	  event->motion.state = state;
-	  event->motion.is_hint = is_hint;
-	  event->motion.device = source_event->motion.device;
+      if (!event_win)
+        return TRUE;
+
+      if (!display->ignore_core_events)
+        {
+          GdkEventType event_type;
+
+          event_type = source_event->type;
+
+          event = gdk_event_new (event_type);
+          event->any.window = g_object_ref (event_win);
+          event->any.send_event = source_event->any.send_event;
+          event->motion.time = time_;
+          convert_toplevel_coords_to_window (event_win,
+                                             toplevel_x, toplevel_y,
+                                             &event->motion.x, &event->motion.y);
+          event->motion.x_root = source_event->motion.x_root;
+          event->motion.y_root = source_event->motion.y_root;
+          event->motion.state = state;
+          event->motion.is_hint = is_hint;
+          event->motion.device = source_event->motion.device;
           event->motion.axes = g_memdup (source_event->motion.axes,
                                          sizeof (gdouble) * gdk_device_get_n_axes (source_event->motion.device));
           gdk_event_set_source_device (event, source_device);
+
+          /* Just insert the event */
+          _gdk_event_queue_insert_after (gdk_window_get_display (event_win),
+                                         source_event, event);
 	}
     }
 
@@ -9417,6 +9458,8 @@ proxy_button_event (GdkEvent *source_event,
   GdkDisplay *display;
   GdkWindow *w;
   GdkDevice *device, *source_device;
+  GdkEventMask evmask;
+  GdkEventSequence *sequence;
 
   type = source_event->any.type;
   event_window = source_event->any.window;
@@ -9429,9 +9472,13 @@ proxy_button_event (GdkEvent *source_event,
   toplevel_window = convert_native_coords_to_toplevel (event_window,
 						       toplevel_x, toplevel_y,
 						       &toplevel_x, &toplevel_y);
+
+  sequence = gdk_event_get_event_sequence (source_event);
+
   pointer_info = _gdk_display_get_pointer_info (display, device);
 
-  if (type == GDK_BUTTON_PRESS &&
+  if ((type == GDK_BUTTON_PRESS ||
+       type == GDK_TOUCH_BEGIN) &&
       !source_event->any.send_event &&
       _gdk_display_has_device_grab (display, device, serial) == NULL)
     {
@@ -9446,23 +9493,46 @@ 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_BEGIN &&
+              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_BEGIN &&
+              pointer_window->event_mask & GDK_TOUCH_MASK)
+            {
+              _gdk_display_add_touch_grab (display, device, sequence,
+                                           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,
@@ -9471,9 +9541,10 @@ proxy_button_event (GdkEvent *source_event,
 
   event_win = get_event_window (display,
                                 device,
-				pointer_window,
-				type, state,
-				NULL, serial);
+                                sequence,
+                                pointer_window,
+                                type, state,
+                                &evmask, serial);
 
   if (event_win == NULL || display->ignore_core_events)
     return TRUE;
@@ -9523,7 +9594,6 @@ proxy_button_event (GdkEvent *source_event,
       event->button.device = source_event->button.device;
       event->button.axes = g_memdup (source_event->button.axes,
                                      sizeof (gdouble) * gdk_device_get_n_axes (source_event->button.device));
-
       gdk_event_set_source_device (event, source_device);
 
       if (type == GDK_BUTTON_PRESS)
@@ -9547,6 +9617,40 @@ proxy_button_event (GdkEvent *source_event,
         }
       return TRUE;
 
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_END:
+      convert_toplevel_coords_to_window (event_win,
+                                         toplevel_x, toplevel_y,
+                                         &event->button.x, &event->button.y);
+      event->touch.x_root = source_event->touch.x_root;
+      event->touch.y_root = source_event->touch.y_root;
+      event->touch.state = state;
+      event->touch.device = source_event->touch.device;
+      event->touch.axes = g_memdup (source_event->touch.axes,
+                                     sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
+      event->touch.sequence = source_event->touch.sequence;
+
+      gdk_event_set_source_device (event, source_device);
+
+      if ((type == GDK_TOUCH_END &&
+           _gdk_event_get_pointer_emulated (source_event)) &&
+           pointer_window == pointer_info->window_under_pointer &&
+           gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+        {
+          /* Synthesize a leave notify event
+           * whenever a touch device is released
+           */
+          pointer_info->need_touch_press_enter = TRUE;
+          _gdk_synthesize_crossing_events (display,
+                                           pointer_window, NULL,
+                                           device, source_device,
+                                           GDK_CROSSING_TOUCH_END,
+                                           toplevel_x, toplevel_y,
+                                           state, time_, NULL,
+                                           serial, FALSE);
+        }
+      return TRUE;
+
     case GDK_SCROLL:
       event->scroll.direction = source_event->scroll.direction;
       convert_toplevel_coords_to_window (event_win,
@@ -9804,16 +9908,32 @@ _gdk_windowing_got_event (GdkDisplay *display,
   else if (is_button_type (event->type))
     unlink_event = proxy_button_event (event, serial);
 
-  if (event->type == GDK_BUTTON_RELEASE && !event->any.send_event)
+  if ((event->type == GDK_BUTTON_RELEASE ||
+       event->type == GDK_TOUCH_END) &&
+      !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)
+      GdkEventSequence *sequence;
+
+      sequence = gdk_event_get_event_sequence (event);
+      if (event->type == GDK_TOUCH_END && sequence)
+        {
+          _gdk_display_end_touch_grab (display, device, sequence);
+        }
+
+      if (event->type == GDK_BUTTON_RELEASE ||
+          _gdk_event_get_pointer_emulated (event))
         {
-          button_release_grab->serial_end = serial;
-          button_release_grab->implicit_ungrab = FALSE;
-          _gdk_display_device_grab_update (display, device, source_device, serial);
+          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);
+            }
         }
     }
 
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 68ecbfe..65df934 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1339,6 +1339,14 @@ rewrite_event_for_window (GdkEvent  *event,
                                 new_window,
                                 &event->motion.x, &event->motion.y);
       break;
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_UPDATE:
+    case GDK_TOUCH_END:
+    case GDK_TOUCH_CANCEL:
+      rewrite_events_translate (event->any.window,
+                                new_window,
+                                &event->touch.x, &event->touch.y);
+      break;
     case GDK_KEY_PRESS:
     case GDK_KEY_RELEASE:
     case GDK_PROXIMITY_IN:
@@ -1384,6 +1392,10 @@ rewrite_event_for_grabs (GdkEvent *event)
     case GDK_PROXIMITY_OUT:
     case GDK_KEY_PRESS:
     case GDK_KEY_RELEASE:
+    case GDK_TOUCH_BEGIN:
+    case GDK_TOUCH_UPDATE:
+    case GDK_TOUCH_END:
+    case GDK_TOUCH_CANCEL:
       display = gdk_window_get_display (event->any.window);
       device = gdk_event_get_device (event);
 
@@ -1643,6 +1655,7 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_BUTTON_PRESS:
     case GDK_2BUTTON_PRESS:
     case GDK_3BUTTON_PRESS:
+    case GDK_TOUCH_BEGIN:
       if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_propagate_event (grab_widget, event);
       break;
@@ -1693,6 +1706,9 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_BUTTON_RELEASE:
     case GDK_PROXIMITY_IN:
     case GDK_PROXIMITY_OUT:
+    case GDK_TOUCH_UPDATE:
+    case GDK_TOUCH_END:
+    case GDK_TOUCH_CANCEL:
       if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_propagate_event (grab_widget, event);
       break;
@@ -1743,6 +1759,7 @@ gtk_main_do_event (GdkEvent *event)
       || event->type == GDK_DRAG_ENTER
       || event->type == GDK_GRAB_BROKEN
       || event->type == GDK_MOTION_NOTIFY
+      || event->type == GDK_TOUCH_UPDATE
       || event->type == GDK_SCROLL)
     {
       _gtk_tooltip_handle_event (event);



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