mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
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.
This commit is contained in:
parent
de0d9e4da8
commit
2e8682d607
@ -161,6 +161,7 @@ struct _MetaTouchInfo
|
||||
gdouble initial_root_y;
|
||||
|
||||
guint notified : 1;
|
||||
guint use_for_hotspot : 1;
|
||||
};
|
||||
|
||||
struct _MetaDisplay
|
||||
|
@ -340,6 +340,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;
|
||||
|
||||
|
@ -61,6 +61,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>
|
||||
|
||||
/* Windows that unmaximize to a size bigger than that fraction of the workarea
|
||||
@ -8828,15 +8832,17 @@ 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)
|
||||
{
|
||||
if (!window->touch_hold_tiling_mode)
|
||||
{
|
||||
window->tile_mode = META_TILE_NONE;
|
||||
|
||||
if (window->cur_touch_area_height >
|
||||
window->initial_touch_area_height * 1.5)
|
||||
window->initial_touch_area_height * TILING_ZOOM_FACTOR)
|
||||
{
|
||||
if (window->cur_touch_area_width >
|
||||
window->initial_touch_area_width * 1.5 &&
|
||||
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))
|
||||
@ -8848,6 +8854,7 @@ update_move (MetaWindow *window,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
window->tile_mode = META_TILE_NONE;
|
||||
|
||||
@ -11150,6 +11157,7 @@ typedef struct
|
||||
gdouble top_left_y;
|
||||
gdouble bottom_right_x;
|
||||
gdouble bottom_right_y;
|
||||
gboolean only_hotspot;
|
||||
} BoundingRectCoords;
|
||||
|
||||
static void
|
||||
@ -11160,6 +11168,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)
|
||||
@ -11171,6 +11183,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,
|
||||
@ -11246,6 +11307,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),
|
||||
@ -11258,9 +11321,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
|
||||
@ -11271,13 +11334,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);
|
||||
@ -11290,21 +11351,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, ¢er_x, ¢er_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
|
||||
@ -11317,18 +11381,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);
|
||||
|
||||
window->initial_touch_area_width = width;
|
||||
window->initial_touch_area_height = height;
|
||||
/* Update window, and tiling mode */
|
||||
update_move (window, device, FALSE, center_x, center_y);
|
||||
}
|
||||
}
|
||||
else if (window->cur_grab)
|
||||
{
|
||||
window->cur_touch_area_width = width;
|
||||
window->cur_touch_area_height = height;
|
||||
/* 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, x, y);
|
||||
update_move (window, device, FALSE, center_x, center_y);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -11344,6 +11427,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);
|
||||
@ -11365,17 +11449,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);
|
||||
|
||||
if (n_touches >= N_TOUCHES_FOR_GRAB)
|
||||
{
|
||||
gdouble center_x, center_y, width, height;
|
||||
|
||||
window_get_touch_area (window, ¢er_x, ¢er_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)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
if (n_touches == 2)
|
||||
{
|
||||
MetaDevice *device;
|
||||
|
||||
device = meta_input_event_get_device (window->display, event);
|
||||
meta_display_end_grab_op (window->display, device, evtime);
|
||||
}
|
||||
else if (n_touches == 0 &&
|
||||
|
Loading…
Reference in New Issue
Block a user