[mutter/wip/multitouch: 73/73] window: Update drag hotspot as new touches approach



commit bdfb8609a382b1fc378f5d9d05a3d94f6314086b
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Oct 30 18:05:04 2011 +0100

    window: Update drag hotspot as new touches approach
    
    Any number of touches >= 3 starts a drag operation, but the
    window jumped around as new touches joined. So recalculate
    the touch drag area/hotspot and tiling mode as expected
    as soon as touches enter/leave the drag op.

 src/core/display-private.h |    1 +
 src/core/window-private.h  |    3 +
 src/core/window.c          |  203 +++++++++++++++++++++++++++++++++----------
 3 files changed, 160 insertions(+), 47 deletions(-)
---
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 46aaeec..7f0a8e5 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -160,6 +160,7 @@ struct _MetaTouchInfo
   gdouble initial_root_y;
 
   guint notified : 1;
+  guint use_for_hotspot : 1;
 };
 
 struct _MetaDisplay
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 466dae4..759b4e5 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -329,6 +329,9 @@ struct _MetaWindow
   /* if TRUE, window didn't yet get the FocusIn for window->focus_keyboard */
   guint expecting_focus_in : 1;
 
+  /* if TRUE, tiling mode is held regardless of newer touch updates */
+  guint touch_hold_tiling_mode : 1;
+
   /* Keyboard currently owning the window focus, or NULL */
   MetaDevice *focus_keyboard;
 
diff --git a/src/core/window.c b/src/core/window.c
index 549287a..efdbba6 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -60,6 +60,10 @@
 #include <X11/extensions/shape.h>
 #endif
 
+#define N_TOUCHES_FOR_GRAB 3
+#define TOUCH_THRESHOLD 16
+#define TILING_ZOOM_FACTOR 1.5
+
 #include <X11/extensions/Xcomposite.h>
 
 static int destroying_windows_disallowed = 0;
@@ -8659,23 +8663,26 @@ update_move (MetaWindow  *window,
                y >= monitor->rect.y && y <= work_area.y)
         window->tile_mode = META_TILE_MAXIMIZED;
       else if (window->cur_touches &&
-               g_hash_table_size (window->cur_touches) == 3)
+               g_hash_table_size (window->cur_touches) >= N_TOUCHES_FOR_GRAB)
         {
-          window->tile_mode = META_TILE_NONE;
-
-          if (window->cur_touch_area_height >
-              window->initial_touch_area_height * 1.5)
+          if (!window->touch_hold_tiling_mode)
             {
-              if (window->cur_touch_area_width >
-                  window->initial_touch_area_width * 1.5 &&
-                  meta_window_can_tile_maximized (window))
-                window->tile_mode = META_TILE_MAXIMIZED;
-              else if (meta_window_can_tile_side_by_side (window, device))
+              window->tile_mode = META_TILE_NONE;
+
+              if (window->cur_touch_area_height >
+                  window->initial_touch_area_height * TILING_ZOOM_FACTOR)
                 {
-                  if (x < (monitor->rect.x + (monitor->rect.width / 2)))
-                    window->tile_mode = META_TILE_LEFT;
-                  else
-                    window->tile_mode = META_TILE_RIGHT;
+                  if (window->cur_touch_area_width >
+                      window->initial_touch_area_width * TILING_ZOOM_FACTOR &&
+                      meta_window_can_tile_maximized (window))
+                    window->tile_mode = META_TILE_MAXIMIZED;
+                  else if (meta_window_can_tile_side_by_side (window, device))
+                    {
+                      if (x < (monitor->rect.x + (monitor->rect.width / 2)))
+                        window->tile_mode = META_TILE_LEFT;
+                      else
+                        window->tile_mode = META_TILE_RIGHT;
+                    }
                 }
             }
         }
@@ -10808,6 +10815,7 @@ typedef struct
   gdouble top_left_y;
   gdouble bottom_right_x;
   gdouble bottom_right_y;
+  gboolean only_hotspot;
 } BoundingRectCoords;
 
 static void
@@ -10818,6 +10826,10 @@ calculate_touch_bounding_rect (gpointer key,
   BoundingRectCoords *bounding_rect = user_data;
   MetaTouchInfo *touch_info = value;
 
+  if (bounding_rect->only_hotspot &&
+      !touch_info->use_for_hotspot)
+    return;
+
   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)
@@ -10829,6 +10841,55 @@ calculate_touch_bounding_rect (gpointer key,
     bounding_rect->bottom_right_y = touch_info->root_y;
 }
 
+static gboolean
+window_get_touch_area (MetaWindow *window,
+                       gdouble    *center_x,
+                       gdouble    *center_y,
+                       gdouble    *width,
+                       gdouble    *height)
+{
+  if (g_hash_table_size (window->cur_touches) == 0)
+    return FALSE;
+
+  if (width || height)
+    {
+      BoundingRectCoords bounding_rect = { DBL_MAX, DBL_MAX,
+                                           DBL_MIN, DBL_MIN,
+                                           FALSE };
+
+      g_hash_table_foreach (window->cur_touches,
+                            calculate_touch_bounding_rect,
+                            &bounding_rect);
+
+      if (width)
+        *width = bounding_rect.bottom_right_x - bounding_rect.top_left_x;
+      if (height)
+        *height = bounding_rect.bottom_right_y - bounding_rect.top_left_y;
+    }
+
+  if (center_x || center_y)
+    {
+      gdouble w, h;
+      BoundingRectCoords bounding_rect = { DBL_MAX, DBL_MAX,
+                                           DBL_MIN, DBL_MIN,
+                                           TRUE };
+
+      g_hash_table_foreach (window->cur_touches,
+                            calculate_touch_bounding_rect,
+                            &bounding_rect);
+
+      w = bounding_rect.bottom_right_x - bounding_rect.top_left_x;
+      h = bounding_rect.bottom_right_y - bounding_rect.top_left_y;
+
+      if (center_x)
+        *center_x = bounding_rect.top_left_x + (w / 2);
+      if (center_y)
+        *center_y = bounding_rect.top_left_y + (h / 2);
+    }
+
+  return TRUE;
+}
+
 static void
 notify_touch (MetaWindow *window,
               MetaDevice *source,
@@ -10904,6 +10965,8 @@ meta_window_update_touch (MetaWindow *window,
       touch_info = g_slice_new (MetaTouchInfo);
       touch_info->initial_root_x = root_x;
       touch_info->initial_root_y = root_y;
+      touch_info->use_for_hotspot =
+        (g_hash_table_size (window->cur_touches) < N_TOUCHES_FOR_GRAB);
 
       g_hash_table_insert (window->cur_touches,
                            GUINT_TO_POINTER (touch_id),
@@ -10916,9 +10979,9 @@ meta_window_update_touch (MetaWindow *window,
 
   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))
+  if (!new_touch && n_touches < N_TOUCHES_FOR_GRAB &&
+      (ABS (touch_info->initial_root_x - touch_info->root_x) >= TOUCH_THRESHOLD ||
+       ABS (touch_info->initial_root_y - touch_info->root_y) >= TOUCH_THRESHOLD))
     {
       /* There aren't yet enough touches on the window to trigger
        * window moving, and one of the touches moved past the
@@ -10929,13 +10992,11 @@ meta_window_update_touch (MetaWindow *window,
       notify_touch_events (window, source, FALSE);
       return TRUE;
     }
-  else if (n_touches >= 3)
+  else if (n_touches >= N_TOUCHES_FOR_GRAB)
     {
-      gdouble x, y, width, height;
-      BoundingRectCoords bounding_rect = { DBL_MAX, DBL_MAX,
-                                           DBL_MIN, DBL_MIN };
+      gdouble center_x, center_y, width, height;
 
-      if (n_touches == 3 && new_touch)
+      if (n_touches == N_TOUCHES_FOR_GRAB && new_touch)
         {
           /* Accept all touches for the move operation */
           notify_touch_events (window, source, TRUE);
@@ -10948,21 +11009,24 @@ meta_window_update_touch (MetaWindow *window,
           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,
+      /* Set grab 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);
+      window_get_touch_area (window, &center_x, &center_y, &width, &height);
+      window->cur_touch_area_width = width;
+      window->cur_touch_area_height = height;
 
       if (new_touch)
         {
-          if (n_touches == 3)
+          window->touch_hold_tiling_mode = FALSE;
+
+          /* (re)set initial bounding box
+           * so the new touch is included
+           */
+          window->initial_touch_area_width = width;
+          window->initial_touch_area_height = height;
+
+          if (n_touches == N_TOUCHES_FOR_GRAB)
             {
               /* Start window move operation with the
                * bounding rectangle center as the hotspot
@@ -10975,18 +11039,37 @@ meta_window_update_touch (MetaWindow *window,
                                           TRUE, FALSE,
                                           1, 0,
                                           evtime,
-                                          x, y);
+                                          center_x, center_y);
+            }
+          else
+            {
+              /* Update hotspot for grab */
+              window->cur_grab->grab_anchor_root_x = center_x;
+              window->cur_grab->grab_anchor_root_y = center_y;
+              window->cur_grab->grab_latest_motion_x = center_x;
+              window->cur_grab->grab_latest_motion_y = center_y;
+              meta_window_get_client_root_coords (window,
+                                                  &window->cur_grab->grab_anchor_window_pos);
+
+              /* Update window, and tiling mode */
+              update_move (window, device, FALSE, center_x, center_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);
+          /* Unset tiling mode as the remaining touches moved past the threshold */
+          if (window->touch_hold_tiling_mode &&
+              ((window->cur_touch_area_width >
+                (window->initial_touch_area_width + (2 * TOUCH_THRESHOLD))) ||
+               (window->cur_touch_area_height >
+                (window->initial_touch_area_height + (2 * TOUCH_THRESHOLD))) ||
+               (ABS (window->cur_grab->grab_anchor_root_x -
+                     window->cur_grab->grab_latest_motion_x) > TOUCH_THRESHOLD) ||
+               (ABS (window->cur_grab->grab_anchor_root_y -
+                     window->cur_grab->grab_latest_motion_y) > TOUCH_THRESHOLD)))
+            window->touch_hold_tiling_mode = FALSE;
+
+          update_move (window, device, FALSE, center_x, center_y);
         }
 
       return TRUE;
@@ -11002,6 +11085,7 @@ meta_window_end_touch (MetaWindow *window,
   MetaTouchInfo *info;
   MetaDevice *source;
   guint touch_id, n_touches;
+  MetaDevice *device;
   Time evtime;
 
   meta_input_event_get_touch_id (window->display, event, &touch_id);
@@ -11023,17 +11107,42 @@ meta_window_end_touch (MetaWindow *window,
                        GUINT_TO_POINTER (touch_id));
 
   n_touches = g_hash_table_size (window->cur_touches);
+  device = meta_input_event_get_device (window->display, event);
 
-  window->initial_touch_area_width = 0;
-  window->initial_touch_area_height = 0;
-  window->cur_touch_area_width = 0;
-  window->cur_touch_area_height = 0;
+  if (n_touches >= N_TOUCHES_FOR_GRAB)
+    {
+      gdouble center_x, center_y, width, height;
 
-  if (n_touches == 2)
+      window_get_touch_area (window, &center_x, &center_y, &width, &height);
+
+      window->initial_touch_area_width = width;
+      window->initial_touch_area_height = height;
+      window->cur_touch_area_width = width;
+      window->cur_touch_area_height = height;
+
+      /* Update hotspot to the new bounding box center */
+      window->cur_grab->grab_anchor_root_x = center_x;
+      window->cur_grab->grab_anchor_root_y = center_y;
+      window->cur_grab->grab_latest_motion_x = center_x;
+      window->cur_grab->grab_latest_motion_y = center_y;
+      meta_window_get_client_root_coords (window,
+                                          &window->cur_grab->grab_anchor_window_pos);
+
+      /* Hold tiling mode until the remaining
+       * touches moved past some threshold
+       */
+      window->touch_hold_tiling_mode = TRUE;
+
+      update_move (window, device, FALSE, center_x, center_y);
+    }
+  else if (n_touches == N_TOUCHES_FOR_GRAB - 1)
     {
-      MetaDevice *device;
+      /* We just lost the last touch to hold the grab */
+      window->initial_touch_area_width = 0;
+      window->initial_touch_area_height = 0;
+      window->cur_touch_area_width = 0;
+      window->cur_touch_area_height = 0;
 
-      device = meta_input_event_get_device (window->display, event);
       meta_display_end_grab_op (window->display, device, evtime);
     }
   else if (n_touches == 0 &&



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