summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2011-10-30 18:05:04 +0100
committerCarlos Garnacho <carlosg@gnome.org>2011-10-31 01:09:36 +0100
commitbdfb8609a382b1fc378f5d9d05a3d94f6314086b (patch)
treec81996eab40df066181a23aa51a34e91e8d2d088
parent141a353a520c31fbe03cf28df441df886df46dcb (diff)
downloadmutter-wip/multitouch.tar.gz
window: Update drag hotspot as new touches approachwip/multitouch
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.
-rw-r--r--src/core/display-private.h1
-rw-r--r--src/core/window-private.h3
-rw-r--r--src/core/window.c203
3 files changed, 160 insertions, 47 deletions
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 46aaeecbc..7f0a8e5d0 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 466dae4e0..759b4e5e0 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 549287a60..efdbba6e4 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 &&