mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
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.
This commit is contained in:
parent
7971d5a871
commit
900b91f385
@ -59,6 +59,7 @@ typedef struct MetaEdgeResistanceData MetaEdgeResistanceData;
|
|||||||
|
|
||||||
typedef struct _MetaGrabInfo MetaGrabInfo;
|
typedef struct _MetaGrabInfo MetaGrabInfo;
|
||||||
typedef struct _MetaFocusInfo MetaFocusInfo;
|
typedef struct _MetaFocusInfo MetaFocusInfo;
|
||||||
|
typedef struct _MetaTouchInfo MetaTouchInfo;
|
||||||
|
|
||||||
typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
|
typedef void (* MetaWindowPingFunc) (MetaDisplay *display,
|
||||||
Window xwindow,
|
Window xwindow,
|
||||||
@ -151,6 +152,17 @@ struct _MetaFocusInfo
|
|||||||
guint32 last_focus_time;
|
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
|
struct _MetaDisplay
|
||||||
{
|
{
|
||||||
GObject parent_instance;
|
GObject parent_instance;
|
||||||
|
@ -2043,6 +2043,14 @@ event_callback (XEvent *event,
|
|||||||
filter_out_event = bypass_compositor = TRUE;
|
filter_out_event = bypass_compositor = TRUE;
|
||||||
break;
|
break;
|
||||||
case ButtonPress:
|
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_button (display, event, &n_button);
|
||||||
meta_input_event_get_state (display, event, &state);
|
meta_input_event_get_state (display, event, &state);
|
||||||
meta_input_event_get_coordinates (display, event,
|
meta_input_event_get_coordinates (display, event,
|
||||||
@ -2259,6 +2267,14 @@ event_callback (XEvent *event,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ButtonRelease:
|
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)
|
if (grab_info && grab_info->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2270,6 +2286,14 @@ event_callback (XEvent *event,
|
|||||||
meta_window_handle_mouse_grab_op_event (window, event);
|
meta_window_handle_mouse_grab_op_event (window, event);
|
||||||
break;
|
break;
|
||||||
case MotionNotify:
|
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)
|
if (grab_info && grab_info->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -47,9 +47,6 @@ gboolean meta_input_event_is_type (MetaDisplay *display,
|
|||||||
XEvent *ev,
|
XEvent *ev,
|
||||||
guint ev_type);
|
guint ev_type);
|
||||||
|
|
||||||
gboolean meta_input_event_ignore (MetaDisplay *display,
|
|
||||||
XEvent *ev);
|
|
||||||
|
|
||||||
gboolean meta_input_event_get_touch_id (MetaDisplay *display,
|
gboolean meta_input_event_get_touch_id (MetaDisplay *display,
|
||||||
XEvent *ev,
|
XEvent *ev,
|
||||||
guint *touch_id);
|
guint *touch_id);
|
||||||
|
@ -429,6 +429,8 @@ struct _MetaWindow
|
|||||||
|
|
||||||
/* Focus info if the window is focused, or NULL */
|
/* Focus info if the window is focused, or NULL */
|
||||||
MetaFocusInfo *cur_focus;
|
MetaFocusInfo *cur_focus;
|
||||||
|
|
||||||
|
GHashTable *cur_touches;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaWindowClass
|
struct _MetaWindowClass
|
||||||
@ -675,4 +677,9 @@ MetaDevice * meta_window_get_client_pointer (MetaWindow *window);
|
|||||||
|
|
||||||
MetaDevice * meta_window_guess_grab_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
|
#endif
|
||||||
|
@ -240,6 +240,9 @@ meta_window_finalize (GObject *object)
|
|||||||
if (window->menu)
|
if (window->menu)
|
||||||
meta_ui_window_menu_free (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);
|
meta_icon_cache_free (&window->icon_cache);
|
||||||
|
|
||||||
g_free (window->sm_client_id);
|
g_free (window->sm_client_id);
|
||||||
@ -11119,3 +11122,234 @@ meta_window_guess_grab_pointer (MetaWindow *window)
|
|||||||
|
|
||||||
return meta_window_get_client_pointer (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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user