[mutter/wip/multitouchr: 71/73] window: Implement window moving through touch events



commit cb4291946981168a75f9fbed22481e12445f2d9f
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue Aug 2 19:29:07 2011 +0200

    window: Implement window moving through touch events
    
    Window moving is triggered by 3-4 simultaneous touch events on
    the window, the hotspot being in the center of the touch area
    bounding rect.

 src/core/display-private.h |   12 +++
 src/core/display.c         |   24 +++++
 src/core/input-events.c    |   30 ------
 src/core/input-events.h    |    3 -
 src/core/window-private.h  |    7 ++
 src/core/window.c          |  234 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 277 insertions(+), 33 deletions(-)
---
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 5d72529..b76152e 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -59,6 +59,7 @@ typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
 
 typedef struct _MetaGrabInfo MetaGrabInfo;
 typedef struct _MetaFocusInfo MetaFocusInfo;
+typedef struct _MetaTouchInfo MetaTouchInfo;
 
 typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
 				     Window       xwindow,
@@ -151,6 +152,17 @@ struct _MetaFocusInfo
   guint32 last_focus_time;
 };
 
+struct _MetaTouchInfo
+{
+  gdouble root_x;
+  gdouble root_y;
+
+  gdouble initial_root_x;
+  gdouble initial_root_y;
+
+  guint notified : 1;
+};
+
 struct _MetaDisplay
 {
   GObject parent_instance;
diff --git a/src/core/display.c b/src/core/display.c
index 9ebccaf..7032998 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2043,6 +2043,14 @@ event_callback (XEvent   *event,
             filter_out_event = bypass_compositor = TRUE;
           break;
         case ButtonPress:
+          if (window &&
+              meta_input_event_get_touch_id (display, event, NULL))
+            {
+              meta_window_update_touch (window, event);
+              filter_out_event = TRUE;
+              break;
+            }
+
           meta_input_event_get_button (display, event, &n_button);
           meta_input_event_get_state (display, event, &state);
           meta_input_event_get_coordinates (display, event,
@@ -2259,6 +2267,14 @@ event_callback (XEvent   *event,
             }
           break;
         case ButtonRelease:
+          if (window &&
+              meta_input_event_get_touch_id (display, event, NULL))
+            {
+              meta_window_end_touch (window, event);
+              filter_out_event = TRUE;
+              break;
+            }
+
           if (grab_info && grab_info->grab_op == META_GRAB_OP_COMPOSITOR)
             break;
 
@@ -2270,6 +2286,14 @@ event_callback (XEvent   *event,
             meta_window_handle_mouse_grab_op_event (window, event);
           break;
         case MotionNotify:
+          if (window &&
+              meta_input_event_get_touch_id (display, event, NULL))
+            {
+              meta_window_update_touch (window, event);
+              filter_out_event = TRUE;
+              break;
+            }
+
           if (grab_info && grab_info->grab_op == META_GRAB_OP_COMPOSITOR)
             break;
 
diff --git a/src/core/input-events.c b/src/core/input-events.c
index c9f225c..197634b 100644
--- a/src/core/input-events.c
+++ b/src/core/input-events.c
@@ -160,36 +160,6 @@ meta_input_event_is_type (MetaDisplay *display,
 }
 
 gboolean
-meta_input_event_ignore (MetaDisplay *display,
-                         XEvent      *ev)
-{
-#if defined(HAVE_XINPUT2) && defined(HAVE_XTOUCH)
-  if (ev->type == GenericEvent &&
-      ev->xcookie.extension == display->xinput2_opcode)
-    {
-      XIEvent *xev;
-
-      g_assert (display->have_xinput2 == TRUE);
-      xev = (XIEvent *) ev->xcookie.data;
-
-      switch (xev->evtype)
-        {
-        case XI_Motion:
-        case XI_ButtonPress:
-        case XI_ButtonRelease:
-          if (((XIDeviceEvent *) xev)->flags & XIPointerEmulated)
-            return TRUE;
-
-        default:
-          return FALSE;
-        }
-    }
-#endif /* HAVE_XINPUT2 && HAVE_XTOUCH */
-
-      return FALSE;
-}
-
-gboolean
 meta_input_event_get_touch_id (MetaDisplay *display,
                                XEvent      *ev,
                                guint       *touch_id)
diff --git a/src/core/input-events.h b/src/core/input-events.h
index 99e3224..a70107b 100644
--- a/src/core/input-events.h
+++ b/src/core/input-events.h
@@ -47,9 +47,6 @@ gboolean meta_input_event_is_type           (MetaDisplay *display,
                                              XEvent      *ev,
                                              guint        ev_type);
 
-gboolean meta_input_event_ignore            (MetaDisplay *display,
-                                             XEvent      *ev);
-
 gboolean meta_input_event_get_touch_id      (MetaDisplay *display,
                                              XEvent      *ev,
                                              guint       *touch_id);
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 6b530d3..f9a796f 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -429,6 +429,8 @@ struct _MetaWindow
 
   /* Focus info if the window is focused, or NULL */
   MetaFocusInfo *cur_focus;
+
+  GHashTable *cur_touches;
 };
 
 struct _MetaWindowClass
@@ -675,4 +677,9 @@ MetaDevice * meta_window_get_client_pointer (MetaWindow *window);
 
 MetaDevice * meta_window_guess_grab_pointer (MetaWindow *window);
 
+gboolean     meta_window_update_touch (MetaWindow *window,
+                                       XEvent     *event);
+void         meta_window_end_touch    (MetaWindow *window,
+                                       XEvent     *event);
+
 #endif
diff --git a/src/core/window.c b/src/core/window.c
index 850e1c2..b42244f 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -240,6 +240,9 @@ meta_window_finalize (GObject *object)
   if (window->menu)
     meta_ui_window_menu_free (window->menu);
 
+  if (window->cur_touches)
+    g_hash_table_destroy (window->cur_touches);
+
   meta_icon_cache_free (&window->icon_cache);
 
   g_free (window->sm_client_id);
@@ -11119,3 +11122,234 @@ meta_window_guess_grab_pointer (MetaWindow *window)
 
   return meta_window_get_client_pointer (window);
 }
+
+typedef struct
+{
+  gdouble top_left_x;
+  gdouble top_left_y;
+  gdouble bottom_right_x;
+  gdouble bottom_right_y;
+} BoundingRectCoords;
+
+static void
+calculate_touch_bounding_rect (gpointer key,
+                               gpointer value,
+                               gpointer user_data)
+{
+  BoundingRectCoords *bounding_rect = user_data;
+  MetaTouchInfo *touch_info = value;
+
+  if (touch_info->root_x < bounding_rect->top_left_x)
+    bounding_rect->top_left_x = touch_info->root_x;
+  if (touch_info->root_x > bounding_rect->bottom_right_x)
+    bounding_rect->bottom_right_x = touch_info->root_x;
+
+  if (touch_info->root_y < bounding_rect->top_left_y)
+    bounding_rect->top_left_y = touch_info->root_y;
+  if (touch_info->root_y > bounding_rect->bottom_right_y)
+    bounding_rect->bottom_right_y = touch_info->root_y;
+}
+
+static void
+notify_touch (MetaWindow *window,
+              MetaDevice *source,
+              guint       touch_id,
+              gboolean    accept_events)
+{
+  meta_error_trap_push_with_return (window->display);
+
+  XIAllowTouchEvents (window->display->xdisplay,
+                      meta_device_get_id (source),
+                      touch_id,
+                      (accept_events) ?
+                      XITouchOwnerAccept :
+                      XITouchOwnerRejectEnd);
+
+  if (meta_error_trap_pop_with_return (window->display) != Success)
+    meta_warning ("XIAllowTouchEvents failed on touch sequence %d\n", touch_id);
+}
+
+static void
+notify_touch_events (MetaWindow *window,
+                     MetaDevice *source,
+                     gboolean    accept_events)
+{
+  GHashTableIter iter;
+  gpointer key, value;
+
+  g_hash_table_iter_init (&iter, window->cur_touches);
+
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      guint touch_id = GPOINTER_TO_UINT (key);
+      MetaTouchInfo *info = value;
+
+      if (!info->notified)
+        {
+          notify_touch (window, source, touch_id, accept_events);
+          info->notified = TRUE;
+        }
+    }
+}
+
+gboolean
+meta_window_update_touch (MetaWindow *window,
+                          XEvent     *event)
+{
+  gdouble root_x, root_y;
+  MetaTouchInfo *touch_info;
+  gboolean new_touch = FALSE;
+  MetaDevice *device, *source;
+  guint touch_id, n_touches;
+  Time evtime;
+
+  if (!window->cur_touches)
+    window->cur_touches = g_hash_table_new (NULL, NULL);
+
+  meta_input_event_get_touch_id (window->display,
+                                 event, &touch_id);
+
+  touch_info = g_hash_table_lookup (window->cur_touches,
+                                    GUINT_TO_POINTER (touch_id));
+
+  meta_input_event_get_coordinates (window->display, event,
+                                    NULL, NULL,
+                                    &root_x, &root_y);
+
+  evtime = meta_input_event_get_time (window->display, event);
+  device = meta_input_event_get_device (window->display, event);
+  source = meta_input_event_get_source_device (window->display, event);
+
+  if (!touch_info)
+    {
+      touch_info = g_slice_new (MetaTouchInfo);
+      touch_info->initial_root_x = root_x;
+      touch_info->initial_root_y = root_y;
+
+      g_hash_table_insert (window->cur_touches,
+                           GUINT_TO_POINTER (touch_id),
+                           touch_info);
+      new_touch = TRUE;
+    }
+
+  touch_info->root_x = root_x;
+  touch_info->root_y = root_y;
+
+  n_touches = g_hash_table_size (window->cur_touches);
+
+  if (!new_touch && n_touches < 3 &&
+      (ABS (touch_info->initial_root_x - touch_info->root_x) >= 16 ||
+       ABS (touch_info->initial_root_y - touch_info->root_y) >= 16))
+    {
+      /* There aren't yet enough touches on the window to trigger
+       * window moving, and one of the touches moved past the
+       * threshold, so the current touch sequences could actually
+       * be meant for the client window, release all touches
+       * altogether.
+       */
+      notify_touch_events (window, source, FALSE);
+      return TRUE;
+    }
+  else if (n_touches >= 3)
+    {
+      gdouble x, y, width, height;
+      BoundingRectCoords bounding_rect = { DBL_MAX, DBL_MAX,
+                                           DBL_MIN, DBL_MIN };
+
+      if (n_touches == 3 && new_touch)
+        {
+          /* Accept all touches for the move operation */
+          notify_touch_events (window, source, TRUE);
+        }
+      else if (!touch_info->notified)
+        {
+          /* All other touch sequences have been already
+           * accepted, so only deal with the current one */
+          notify_touch (window, source, touch_id, TRUE);
+          touch_info->notified = TRUE;
+        }
+
+      g_hash_table_foreach (window->cur_touches,
+                            calculate_touch_bounding_rect,
+                            &bounding_rect);
+
+      /* Get x/y coordinates at the middle of the bounding box,
+       * this will be the hotspot for the window moving operation
+       */
+      width = bounding_rect.bottom_right_x - bounding_rect.top_left_x;
+      height = bounding_rect.bottom_right_y - bounding_rect.top_left_y;
+      x = bounding_rect.top_left_x + (width / 2);
+      y = bounding_rect.top_left_y + (height / 2);
+
+      if (new_touch)
+        {
+          if (n_touches == 3)
+            {
+              /* Start window move operation with the
+               * bounding rectangle center as the hotspot
+               */
+              meta_display_begin_grab_op (window->display,
+                                          window->screen,
+                                          window,
+                                          device,
+                                          META_GRAB_OP_MOVING,
+                                          TRUE, FALSE,
+                                          1, 0,
+                                          evtime,
+                                          x, y);
+            }
+
+          window->initial_touch_area_width = width;
+          window->initial_touch_area_height = height;
+        }
+      else if (window->cur_grab)
+        {
+          window->cur_touch_area_width = width;
+          window->cur_touch_area_height = height;
+
+          update_move (window, device, FALSE, x, y);
+        }
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+void
+meta_window_end_touch (MetaWindow *window,
+                       XEvent     *event)
+{
+  MetaTouchInfo *info;
+  MetaDevice *source;
+  guint touch_id, n_touches;
+  Time evtime;
+
+  meta_input_event_get_touch_id (window->display, event, &touch_id);
+  evtime = meta_input_event_get_time (window->display, event);
+  source = meta_input_event_get_source_device (window->display, event);
+
+  info = g_hash_table_lookup (window->cur_touches,
+                              GUINT_TO_POINTER (touch_id));
+  if (!info)
+    return;
+
+  if (!info->notified)
+    {
+      notify_touch (window, source, touch_id, FALSE);
+      info->notified = TRUE;
+    }
+
+  g_hash_table_remove (window->cur_touches,
+                       GUINT_TO_POINTER (touch_id));
+
+  n_touches = g_hash_table_size (window->cur_touches);
+
+  if (n_touches == 2)
+    {
+      MetaDevice *device;
+
+      device = meta_input_event_get_device (window->display, event);
+      meta_display_end_grab_op (window->display, device, evtime);
+    }
+}



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