[mutter] core: Add minimal handling of touch events



commit 991c85f6a00be7cdc03b021d14b28b554d5e5b01
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Feb 3 19:08:06 2014 +0100

    core: Add minimal handling of touch events
    
    Currently touch events are ignored in the core event handler,
    and hence dealt with within GDK. If those touch events were
    emulating pointer events, GDK would attempt to convert back
    those events to pointer events as the frame GdkWindow doesn't
    have the GDK_TOUCH_MASK set.
    
    This results in XI_TouchBegin events being initially processed
    by GDK, converted to button events, and triggering a grab op
    that subverts touch events into pointer events, so the touch
    is never ever seen again by GDK. This leaves GDK in an
    inconsistent internal state wrt pointer grabs, so future
    pointer-emulating touches will refer to the same window forever.
    
    Fix this by handling touch events minimally, just enough to
    convert XI_TouchBegin to GDK_BUTTON_PRESS within mutter, so GDK
    is bypassed for every touch event just like it is for pointer
    events. This, and the XIGrabDevice() that keeps coercing pointer
    events when the grab operation starts, are enough to fix window
    drag and drop on touch devices.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=723552

 src/core/display.c |   76 +++++++++++++++++++++++++++++++++++++++++++--------
 src/ui/ui.c        |   18 +++++++++---
 2 files changed, 78 insertions(+), 16 deletions(-)
---
diff --git a/src/core/display.c b/src/core/display.c
index 31bc646..e8a284f 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1815,6 +1815,9 @@ get_input_event (MetaDisplay *display,
 
       switch (input_event->evtype)
         {
+        case XI_TouchBegin:
+        case XI_TouchUpdate:
+        case XI_TouchEnd:
         case XI_Motion:
         case XI_ButtonPress:
         case XI_ButtonRelease:
@@ -2293,6 +2296,7 @@ event_callback (XEvent   *event,
     {
       XIDeviceEvent *device_event = (XIDeviceEvent *) input_event;
       XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
+      gint button = 0;
 
       if (window && !window->override_redirect &&
           ((input_event->evtype == XI_KeyPress) || (input_event->evtype == XI_ButtonPress)))
@@ -2328,20 +2332,33 @@ event_callback (XEvent   *event,
           if (meta_display_process_key_event (display, window, (XIDeviceEvent *) input_event))
             filter_out_event = bypass_compositor = TRUE;
           break;
+        case XI_TouchBegin:
+          /* Filter out non-pointer-emulating touches */
+          if ((((XIDeviceEvent *) input_event)->flags & XITouchEmulatingPointer) == 0)
+            break;
+
+          /* Fall through */
         case XI_ButtonPress:
           if (display->grab_op == META_GRAB_OP_COMPOSITOR)
             break;
 
           display->overlay_key_only_pressed = FALSE;
 
-          if (device_event->detail == 4 || device_event->detail == 5)
-            /* Scrollwheel event, do nothing and deliver event to compositor below */
-            break;
+          if (input_event->evtype == XI_ButtonPress)
+            {
+              if (device_event->detail == 4 || device_event->detail == 5)
+                /* Scrollwheel event, do nothing and deliver event to compositor below */
+                break;
+              else
+                button = device_event->detail;
+            }
+          else if (input_event->evtype == XI_TouchBegin)
+            button = 1;
 
           if ((window &&
                meta_grab_op_is_mouse (display->grab_op) &&
                (device_event->mods.effective & display->window_grab_modifiers) &&
-               display->grab_button != device_event->detail &&
+               display->grab_button != button &&
                display->grab_window == window) ||
               grab_op_is_keyboard (display->grab_op))
             {
@@ -2371,8 +2388,7 @@ event_callback (XEvent   *event,
                */
               unmodified = (device_event->mods.effective & grab_mask) == 0;
           
-              if (unmodified ||
-                  device_event->detail == 1)
+              if (unmodified || button == 1)
                 {
                   /* don't focus if frame received, will be lowered in
                    * frames.c or special-cased if the click was on a
@@ -2393,7 +2409,7 @@ event_callback (XEvent   *event,
                         {
                           meta_topic (META_DEBUG_FOCUS,
                                       "Focusing %s due to unmodified button %u press (display.c)\n",
-                                      window->desc, device_event->detail);
+                                      window->desc, button);
                           meta_window_focus (window, device_event->time);
                         }
                       else
@@ -2409,7 +2425,7 @@ event_callback (XEvent   *event,
                   if (!unmodified)
                     begin_move = TRUE;
                 }
-              else if (!unmodified && device_event->detail == meta_prefs_get_mouse_button_resize())
+              else if (!unmodified && button == meta_prefs_get_mouse_button_resize())
                 {
                   if (window->has_resize_func)
                     {
@@ -2451,21 +2467,21 @@ event_callback (XEvent   *event,
                                                     op,
                                                     TRUE,
                                                     FALSE,
-                                                    device_event->detail,
+                                                    button,
                                                     0,
                                                     device_event->time,
                                                     device_event->root_x,
                                                     device_event->root_y);
                     }
                 }
-              else if (device_event->detail == meta_prefs_get_mouse_button_menu())
+              else if (button == meta_prefs_get_mouse_button_menu())
                 {
                   if (meta_prefs_get_raise_on_click ())
                     meta_window_raise (window);
                   meta_window_show_menu (window,
                                          device_event->root_x,
                                          device_event->root_y,
-                                         device_event->detail,
+                                         button,
                                          device_event->time);
                 }
 
@@ -2490,7 +2506,7 @@ event_callback (XEvent   *event,
                                               META_GRAB_OP_MOVING,
                                               TRUE,
                                               FALSE,
-                                              device_event->detail,
+                                              button,
                                               0,
                                               device_event->time,
                                               device_event->root_x,
@@ -2640,6 +2656,18 @@ event_callback (XEvent   *event,
             filter_out_event = bypass_compositor = TRUE;
           break;
 #endif /* HAVE_XI23 */
+        case XI_TouchUpdate:
+        case XI_TouchEnd:
+          /* Filter out non-pointer-emulating touches */
+          if ((((XIDeviceEvent *) input_event)->flags & XITouchEmulatingPointer) == 0)
+            break;
+
+          /* Currently unhandled, if any grab_op is started through XI_TouchBegin,
+           * the XIGrabDevice() evmask drops touch events, so only emulated
+           * XI_Motions and XI_ButtonRelease will follow.
+           */
+          g_assert_not_reached ();
+          break;
         }
     }
   else
@@ -3115,6 +3143,9 @@ event_get_modified_window (MetaDisplay *display,
         case XI_ButtonRelease:
         case XI_KeyPress:
         case XI_KeyRelease:
+        case XI_TouchBegin:
+        case XI_TouchUpdate:
+        case XI_TouchEnd:
           return ((XIDeviceEvent *) input_event)->event;
         case XI_FocusIn:
         case XI_FocusOut:
@@ -3401,6 +3432,15 @@ meta_spew_xi2_event (MetaDisplay *display,
     case XI_Leave:
       name = "XI_Leave";
       break;
+    case XI_TouchBegin:
+      name = "XI_TouchBegin";
+      break;
+    case XI_TouchUpdate:
+      name = "XI_TouchUpdate";
+      break;
+    case XI_TouchEnd:
+      name = "XI_TouchEnd";
+      break;
 #ifdef HAVE_XI23
     case XI_BarrierHit:
       name = "XI_BarrierHit";
@@ -3458,6 +3498,18 @@ meta_spew_xi2_event (MetaDisplay *display,
                                enter_event->root_x,
                                enter_event->root_y);
       break;
+    case XI_TouchBegin:
+    case XI_TouchUpdate:
+    case XI_TouchEnd:
+      extra = g_strdup_printf ("win: 0x%lx root: 0x%lx touch sequence: %d x: %g y: %g state: 0x%x flags: 
0x%x",
+                               device_event->event,
+                               device_event->root,
+                               device_event->detail,
+                               device_event->root_x,
+                               device_event->root_y,
+                               device_event->mods.effective,
+                               device_event->flags);
+      break;
     }
 
   *name_p = name;
diff --git a/src/ui/ui.c b/src/ui/ui.c
index 7d023dc..c890288 100644
--- a/src/ui/ui.c
+++ b/src/ui/ui.c
@@ -123,6 +123,7 @@ maybe_redirect_mouse_event (XEvent *xevent)
 
   switch (xev->evtype)
     {
+    case XI_TouchBegin:
     case XI_ButtonPress:
     case XI_ButtonRelease:
     case XI_Motion:
@@ -159,20 +160,27 @@ maybe_redirect_mouse_event (XEvent *xevent)
 
   switch (xev->evtype)
     {
+    case XI_TouchBegin:
     case XI_ButtonPress:
     case XI_ButtonRelease:
-      if (xev_d->evtype == XI_ButtonPress)
+      if (xev_d->evtype == XI_ButtonPress || xev_d->evtype == XI_TouchBegin)
         {
           GtkSettings *settings = gtk_settings_get_default ();
           int double_click_time;
           int double_click_distance;
+          int button;
 
           g_object_get (settings,
                         "gtk-double-click-time", &double_click_time,
                         "gtk-double-click-distance", &double_click_distance,
                         NULL);
 
-          if (xev_d->detail == ui->button_click_number &&
+          if (xev->evtype == XI_TouchBegin)
+            button = 1;
+          else
+            button = xev_d->detail;
+
+          if (button == ui->button_click_number &&
               xev_d->event == ui->button_click_window &&
               xev_d->time < ui->button_click_time + double_click_time &&
               ABS (xev_d->event_x - ui->button_click_x) <= double_click_distance &&
@@ -185,20 +193,22 @@ maybe_redirect_mouse_event (XEvent *xevent)
           else
             {
               gevent = gdk_event_new (GDK_BUTTON_PRESS);
-              ui->button_click_number = xev_d->detail;
+              ui->button_click_number = button;
               ui->button_click_window = xev_d->event;
               ui->button_click_time = xev_d->time;
               ui->button_click_x = xev_d->event_x;
               ui->button_click_y = xev_d->event_y;
             }
+
+          gevent->button.button = button;
         }
       else
         {
           gevent = gdk_event_new (GDK_BUTTON_RELEASE);
+          gevent->button.button = xev_d->detail;
         }
 
       gevent->button.window = g_object_ref (gdk_window);
-      gevent->button.button = xev_d->detail;
       gevent->button.time = xev_d->time;
       gevent->button.x = xev_d->event_x;
       gevent->button.y = xev_d->event_y;


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