Compare commits

..

13 Commits

Author SHA1 Message Date
Carlos Garnacho
2e8682d607 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.
2012-11-03 20:00:21 -04:00
Carlos Garnacho
de0d9e4da8 window: Implement tiling/maximizing through touch events
If during a multitouch drag, the area height is 1.5x the original
size, the window is tiled to the closest side the hotspot is on
(left/right).

If both with/height are 1.5x the original, the window is maximized.
2012-11-03 20:00:21 -04:00
Carlos Garnacho
900b91f385 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.
2012-11-03 20:00:20 -04:00
Carlos Garnacho
7971d5a871 devices-xi2: Enable touch events 2012-11-03 20:00:20 -04:00
Carlos Garnacho
c8f0a136cc core: Handle TouchUpdate with TouchPendingEnd as TouchEnd
The touch sequence is possibly unhandled, but we need a call
to meta_window_end_touch() so such touch sequences are notified
to the server, this would trigger the real TouchEnd event as
the touch is rejected, but should be a no-op the second time
2012-11-03 19:59:52 -04:00
Carlos Garnacho
3b578c2983 device-map: Get slave devices in the XI2 implementation
Slave devices are at least needed for touch devices.
2012-11-03 19:59:52 -04:00
Carlos Garnacho
0142e34af8 device-map: Implement passive touch grabs in XI2 backend 2012-11-03 19:59:52 -04:00
Carlos Garnacho
6439856800 device-map: Add grab/ungrab_touch() methods
These functions deal with passive touch grabs, where
available
2012-11-03 19:59:52 -04:00
Carlos Garnacho
704e2320c3 core: Add meta_input_event_get_source_device()
This function would return the slave device behind and
event, this is mostly needed for touch passive grabs,
as XIAllowTouchEvents() at the moment requires a slave
device, this has changed in the latest drafts of the
multitouch protocol.
2012-11-03 19:59:52 -04:00
Carlos Garnacho
bbc69c4220 input-events: Add meta_input_event_get_touch_id()
This function returns the touch ID generating an input event,
if any.
2012-11-03 19:59:38 -04:00
Carlos Garnacho
6a03efe435 input-events: Add meta_input_event_ignored()
This function tells whether an input event should be ignored,
the only current reason being the duplication of touch events
and their emulated XI2 pointer event counterparts.
2012-11-03 19:59:13 -04:00
Carlos Garnacho
85c1058c94 input-events: Handle touch events
TouchBegin/End/Update are now handled similarly to
ButtonPress/Release/MotionNotify.
2012-11-03 19:58:47 -04:00
Jasper St. Pierre
91f87e8173 keybindings: Add a "device" parameter to MetaKeyHandlerFunc
This allows keybinding handlers to get access to devices.
2012-11-03 19:47:37 -04:00
13 changed files with 863 additions and 101 deletions

View File

@@ -27,6 +27,7 @@
#include "core.h"
#include "frame.h"
#include "workspace-private.h"
#include "input-events.h"
#include <meta/prefs.h>
#include <meta/errors.h>
@@ -866,7 +867,8 @@ meta_core_select_events (Display *xdisplay,
XISelectEvents (xdisplay, xwindow, &mask, 1);
/* Unset any input event so they are only handled via XInput2 */
evmask &= ~(KeyPressMask | KeyReleaseMask |
evmask &= ~(META_INPUT_TOUCH_EVENTS_MASK |
KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask |
PointerMotionMask | PointerMotionHintMask |

View File

@@ -76,6 +76,10 @@ struct _MetaDeviceMapClass
Window xwindow,
guint n_button,
guint modifiers);
void (* grab_touch) (MetaDeviceMap *pointer,
Window xwindow);
void (* ungrab_touch) (MetaDeviceMap *pointer,
Window xwindow);
};
GType meta_device_map_get_type (void) G_GNUC_CONST;
@@ -108,4 +112,9 @@ void meta_device_map_ungrab_button (MetaDeviceMap *device_map,
guint n_button,
guint modifiers);
void meta_device_map_grab_touch (MetaDeviceMap *device_map,
Window xwindow);
void meta_device_map_ungrab_touch (MetaDeviceMap *device_map,
Window xwindow);
#endif /* META_DEVICE_MAP_PRIVATE_H */

View File

@@ -25,6 +25,7 @@
#include "device-map-xi2.h"
#include <X11/extensions/XInput2.h>
#include "devices-xi2.h"
#include "input-events.h"
#define XINPUT2_VERSION_MAJOR 2
#define XINPUT2_VERSION_MINOR 2
@@ -123,26 +124,23 @@ meta_device_map_xi2_ungrab_button (MetaDeviceMap *device_map,
n_button, xwindow, 1, &mods);
}
static void
add_device_from_info (MetaDeviceMap *device_map,
gint use,
gint device_id)
static MetaDevice *
create_device_from_info (MetaDeviceMap *device_map,
gint use,
gint device_id)
{
MetaDevice *device;
MetaDevice *device = NULL;
MetaDisplay *display;
display = meta_device_map_get_display (device_map);
if (use == XIMasterPointer)
if (use == XIMasterPointer ||
use == XISlavePointer)
device = meta_device_pointer_xi2_new (display, device_id);
else if (use == XIMasterKeyboard)
device = meta_device_keyboard_xi2_new (display, device_id);
if (device)
{
meta_device_map_add_device (device_map, device);
g_object_unref (device);
}
return device;
}
static void
@@ -175,15 +173,27 @@ meta_device_map_xi2_constructed (GObject *object)
* detached slave devices are left for applications
* to handle.
*/
info = XIQueryDevice (display->xdisplay, XIAllMasterDevices, &n_devices);
info = XIQueryDevice (display->xdisplay, XIAllDevices, &n_devices);
pairs = g_hash_table_new (NULL, NULL);
for (i = 0; i < n_devices; i++)
{
add_device_from_info (device_map, info[i].use, info[i].deviceid);
g_hash_table_insert (pairs,
GINT_TO_POINTER (info[i].deviceid),
GINT_TO_POINTER (info[i].attachment));
MetaDevice *device;
device = create_device_from_info (device_map, info[i].use,
info[i].deviceid);
if (device)
{
meta_device_map_add_device (device_map, device);
if (info[i].use == XIMasterPointer ||
info[i].use == XIMasterKeyboard)
g_hash_table_insert (pairs,
GINT_TO_POINTER (info[i].deviceid),
GINT_TO_POINTER (info[i].attachment));
g_object_unref (device);
}
}
g_hash_table_foreach (pairs, pair_devices, device_map);
@@ -192,6 +202,45 @@ meta_device_map_xi2_constructed (GObject *object)
XIFreeDeviceInfo (info);
}
static void
meta_device_map_xi2_grab_touch (MetaDeviceMap *device_map,
Window xwindow)
{
XIGrabModifiers unused = { 0 };
MetaDisplay *display;
XIEventMask mask;
display = meta_device_map_get_display (device_map);
g_message ("Grabbing passively on touch begin\n");
mask.deviceid = XIAllMasterDevices;
mask.mask = meta_device_xi2_translate_event_mask (META_INPUT_TOUCH_EVENTS_MASK |
ButtonPressMask |
ButtonReleaseMask |
PointerMotionMask |
KeyPressMask |
KeyReleaseMask,
&mask.mask_len);
XIGrabTouchBegin (display->xdisplay,
XIAllMasterDevices,
xwindow, True,
&mask, 1, &unused);
}
static void
meta_device_map_xi2_ungrab_touch (MetaDeviceMap *device_map,
Window xwindow)
{
XIGrabModifiers unused = { 0 };
MetaDisplay *display;
display = meta_device_map_get_display (device_map);
XIUngrabTouchBegin (display->xdisplay,
XIAllMasterDevices,
xwindow, 0, &unused);
}
static void
meta_device_map_xi2_class_init (MetaDeviceMapXI2Class *klass)
{
@@ -204,6 +253,8 @@ meta_device_map_xi2_class_init (MetaDeviceMapXI2Class *klass)
device_map_class->ungrab_key = meta_device_map_xi2_ungrab_key;
device_map_class->grab_button = meta_device_map_xi2_grab_button;
device_map_class->ungrab_button = meta_device_map_xi2_ungrab_button;
device_map_class->grab_touch = meta_device_map_xi2_grab_touch;
device_map_class->ungrab_touch = meta_device_map_xi2_ungrab_touch;
}
static void
@@ -237,16 +288,23 @@ meta_device_map_xi2_handle_hierarchy_event (MetaDeviceMapXI2 *device_map,
for (i = 0; i < xev->num_info; i++)
{
if (xev->info[i].flags & XIMasterAdded)
if (xev->info[i].flags & XIMasterAdded ||
xev->info[i].flags & XISlaveAdded)
{
add_device_from_info (META_DEVICE_MAP (device_map),
xev->info[i].use,
xev->info[i].deviceid);
g_hash_table_insert (pairs,
GINT_TO_POINTER (xev->info[i].deviceid),
GINT_TO_POINTER (xev->info[i].attachment));
MetaDevice *device;
device = create_device_from_info (META_DEVICE_MAP (device_map),
xev->info[i].use,
xev->info[i].deviceid);
if (device &&
xev->info[i].flags & XIMasterAdded)
g_hash_table_insert (pairs,
GINT_TO_POINTER (xev->info[i].deviceid),
GINT_TO_POINTER (xev->info[i].attachment));
}
else if (xev->info[i].flags & XIMasterRemoved)
else if (xev->info[i].flags & XIMasterRemoved ||
xev->info[i].flags & XISlaveRemoved)
{
MetaDevice *device;

View File

@@ -388,3 +388,33 @@ meta_device_map_ungrab_button (MetaDeviceMap *device_map,
if (klass->ungrab_button)
(klass->ungrab_button) (device_map, xwindow, n_button, modifiers);
}
void
meta_device_map_grab_touch (MetaDeviceMap *device_map,
Window xwindow)
{
MetaDeviceMapClass *klass;
g_return_if_fail (META_IS_DEVICE_MAP (device_map));
g_return_if_fail (xwindow != None);
klass = META_DEVICE_MAP_GET_CLASS (device_map);
if (klass->grab_touch)
(klass->grab_touch) (device_map, xwindow);
}
void
meta_device_map_ungrab_touch (MetaDeviceMap *device_map,
Window xwindow)
{
MetaDeviceMapClass *klass;
g_return_if_fail (META_IS_DEVICE_MAP (device_map));
g_return_if_fail (xwindow != None);
klass = META_DEVICE_MAP_GET_CLASS (device_map);
if (klass->ungrab_touch)
(klass->ungrab_touch) (device_map, xwindow);
}

View File

@@ -25,6 +25,7 @@
#include "devices-xi2.h"
#include "display-private.h"
#include "screen-private.h"
#include "input-events.h"
#include <X11/extensions/XInput2.h>
/* Common functions */
@@ -97,6 +98,13 @@ meta_device_xi2_translate_event_mask (guint evmask,
XISetMask (mask, XI_FocusOut);
}
if (evmask & META_INPUT_TOUCH_EVENTS_MASK)
{
XISetMask (mask, XI_TouchBegin);
XISetMask (mask, XI_TouchEnd);
XISetMask (mask, XI_TouchUpdate);
}
return mask;
}

View File

@@ -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,18 @@ 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;
guint use_for_hotspot : 1;
};
struct _MetaDisplay
{
GObject parent_instance;
@@ -425,6 +438,10 @@ void meta_display_grab_window_buttons (MetaDisplay *display,
Window xwindow);
void meta_display_ungrab_window_buttons (MetaDisplay *display,
Window xwindow);
void meta_display_grab_window_touches (MetaDisplay *display,
MetaWindow *window);
void meta_display_ungrab_window_touches (MetaDisplay *display,
MetaWindow *window);
void meta_display_grab_focus_window_button (MetaDisplay *display,
MetaWindow *window);

View File

@@ -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;
@@ -4372,6 +4396,36 @@ meta_display_ungrab_window_buttons (MetaDisplay *display,
}
}
void
meta_display_grab_window_touches (MetaDisplay *display,
MetaWindow *window)
{
if (!window->frame)
return;
meta_error_trap_push_with_return (display);
meta_device_map_grab_touch (display->device_map,
window->frame->xwindow);
if (meta_error_trap_pop_with_return (display) != Success)
{
meta_verbose ("Unable to add a passive touch grab on window '%s'\n",
window->desc);
return;
}
}
void
meta_display_ungrab_window_touches (MetaDisplay *display,
MetaWindow *window)
{
if (!window->frame)
return;
meta_device_map_ungrab_touch (display->device_map,
window->frame->xwindow);
}
/* Grab buttons we only grab while unfocused in click-to-focus mode */
#define MAX_FOCUS_BUTTON 4
void

View File

@@ -86,6 +86,26 @@ meta_input_event_get_type (MetaDisplay *display,
case XI_Leave:
type = LeaveNotify;
break;
case XI_TouchBegin:
type = ButtonPress;
break;
case XI_TouchEnd:
type = ButtonRelease;
break;
case XI_TouchUpdate:
if (((XIDeviceEvent *) xev)->flags & XITouchPendingEnd)
{
/* Consider these events like TouchEnd, as we
* could still need to call XIAllowTouchEvents()
* for this touch sequence so we get the real
* TouchEnd event, handling this event type the
* second time it arrives should be a NO-OP.
*/
type = ButtonRelease;
}
else
type = MotionNotify;
break;
default:
retval = FALSE;
break;
@@ -137,6 +157,63 @@ meta_input_event_is_type (MetaDisplay *display,
return (type == ev_type);
}
gboolean
meta_input_event_ignore (MetaDisplay *display,
XEvent *ev)
{
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;
}
}
return FALSE;
}
gboolean
meta_input_event_get_touch_id (MetaDisplay *display,
XEvent *ev,
guint *touch_id)
{
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_TouchBegin:
case XI_TouchEnd:
case XI_TouchUpdate:
if (touch_id)
*touch_id = ((XIDeviceEvent *) xev)->detail;
return TRUE;
default:
return FALSE;
}
}
return FALSE;
}
Window
meta_input_event_get_window (MetaDisplay *display,
XEvent *ev)
@@ -159,6 +236,9 @@ meta_input_event_get_window (MetaDisplay *display,
case XI_ButtonRelease:
case XI_KeyPress:
case XI_KeyRelease:
case XI_TouchBegin:
case XI_TouchEnd:
case XI_TouchUpdate:
return ((XIDeviceEvent *) xev)->event;
case XI_FocusIn:
case XI_FocusOut:
@@ -195,6 +275,9 @@ meta_input_event_get_root_window (MetaDisplay *display,
case XI_ButtonRelease:
case XI_KeyPress:
case XI_KeyRelease:
case XI_TouchBegin:
case XI_TouchEnd:
case XI_TouchUpdate:
return ((XIDeviceEvent *) xev)->root;
case XI_FocusIn:
case XI_FocusOut:
@@ -250,6 +333,9 @@ meta_input_event_get_time (MetaDisplay *display,
case XI_ButtonRelease:
case XI_KeyPress:
case XI_KeyRelease:
case XI_TouchBegin:
case XI_TouchEnd:
case XI_TouchUpdate:
return ((XIDeviceEvent *) xev)->time;
case XI_FocusIn:
case XI_FocusOut:
@@ -312,6 +398,9 @@ meta_input_event_get_coordinates (MetaDisplay *display,
case XI_ButtonRelease:
case XI_KeyPress:
case XI_KeyRelease:
case XI_TouchBegin:
case XI_TouchEnd:
case XI_TouchUpdate:
{
XIDeviceEvent *event = (XIDeviceEvent *) xev;
@@ -422,6 +511,9 @@ meta_input_event_get_state (MetaDisplay *display,
case XI_ButtonRelease:
case XI_KeyPress:
case XI_KeyRelease:
case XI_TouchBegin:
case XI_TouchEnd:
case XI_TouchUpdate:
s = ((XIDeviceEvent *) xev)->mods.effective;
break;
case XI_FocusIn:
@@ -643,6 +735,9 @@ meta_input_event_get_device (MetaDisplay *display,
case XI_ButtonRelease:
case XI_KeyPress:
case XI_KeyRelease:
case XI_TouchBegin:
case XI_TouchEnd:
case XI_TouchUpdate:
return meta_device_map_lookup (display->device_map,
((XIDeviceEvent *) xev)->deviceid);
case XI_FocusIn:
@@ -675,3 +770,44 @@ meta_input_event_get_device (MetaDisplay *display,
return NULL;
}
MetaDevice *
meta_input_event_get_source_device (MetaDisplay *display,
XEvent *ev)
{
#ifdef HAVE_XINPUT2
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:
case XI_KeyPress:
case XI_KeyRelease:
case XI_TouchBegin:
case XI_TouchEnd:
case XI_TouchUpdate:
return meta_device_map_lookup (display->device_map,
((XIDeviceEvent *) xev)->sourceid);
case XI_FocusIn:
case XI_FocusOut:
case XI_Enter:
case XI_Leave:
return meta_device_map_lookup (display->device_map,
((XIEnterEvent *) xev)->sourceid);
default:
break;
}
}
#endif
return NULL;
}

View File

@@ -35,6 +35,11 @@
#include "display-private.h"
#include <meta/device-map.h>
/* Add an extra flag for touch events in
* evmasks, an arbitrarily high bit is taken.
*/
#define META_INPUT_TOUCH_EVENTS_MASK (1L<<31)
gboolean meta_input_event_get_type (MetaDisplay *display,
XEvent *ev,
guint *ev_type);
@@ -42,6 +47,10 @@ gboolean meta_input_event_is_type (MetaDisplay *display,
XEvent *ev,
guint ev_type);
gboolean meta_input_event_get_touch_id (MetaDisplay *display,
XEvent *ev,
guint *touch_id);
Window meta_input_event_get_window (MetaDisplay *display,
XEvent *ev);
Window meta_input_event_get_root_window (MetaDisplay *display,
@@ -73,6 +82,7 @@ gboolean meta_input_event_get_crossing_details (MetaDisplay *display,
MetaDevice *meta_input_event_get_device (MetaDisplay *display,
XEvent *ev);
MetaDevice *meta_input_event_get_source_device (MetaDisplay *display,
XEvent *ev);
#endif /* META_EVENT_H */

View File

@@ -106,6 +106,7 @@ static void handle_workspace_switch (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy);
static gboolean process_mouse_move_resize_grab (MetaDisplay *display,
@@ -1365,6 +1366,7 @@ invoke_handler (MetaDisplay *display,
MetaKeyHandler *handler,
MetaWindow *window,
XEvent *event,
MetaDevice *device,
MetaKeyBinding *binding)
{
@@ -1374,6 +1376,7 @@ invoke_handler (MetaDisplay *display,
window : NULL,
event,
binding,
device,
handler->user_data);
else
(* handler->default_func) (display, screen,
@@ -1381,6 +1384,7 @@ invoke_handler (MetaDisplay *display,
window: NULL,
event,
binding,
device,
NULL);
}
@@ -1389,13 +1393,14 @@ invoke_handler_by_name (MetaDisplay *display,
MetaScreen *screen,
const char *handler_name,
MetaWindow *window,
XEvent *event)
XEvent *event,
MetaDevice *device)
{
MetaKeyHandler *handler;
handler = HANDLER (handler_name);
if (handler)
invoke_handler (display, screen, handler, window, event, NULL);
invoke_handler (display, screen, handler, window, event, device, NULL);
}
/* now called from only one place, may be worth merging */
@@ -1409,6 +1414,7 @@ process_event (MetaKeyBinding *bindings,
KeySym keysym,
gboolean on_window)
{
MetaDevice *device;
guint evtype, keycode, state;
int i;
@@ -1421,6 +1427,8 @@ process_event (MetaKeyBinding *bindings,
if (evtype == KeyRelease)
return FALSE;
device = meta_input_event_get_device (display, event);;
/*
* TODO: This would be better done with a hash table;
* it doesn't suit to use O(n) for such a common operation.
@@ -1460,7 +1468,7 @@ process_event (MetaKeyBinding *bindings,
*/
display->allow_terminal_deactivation = TRUE;
invoke_handler (display, screen, handler, window, event, &bindings[i]);
invoke_handler (display, screen, handler, window, event, device, &bindings[i]);
return TRUE;
}
@@ -2380,7 +2388,7 @@ process_tab_grab (MetaDisplay *display,
{
if (end_keyboard_grab (display, device, keycode))
{
invoke_handler_by_name (display, screen, "tab-popup-select", NULL, event);
invoke_handler_by_name (display, screen, "tab-popup-select", NULL, event, device);
/* We return FALSE to end the grab; if the handler ended the grab itself
* that will be a noop. If the handler didn't end the grab, then it's a
@@ -2417,7 +2425,7 @@ process_tab_grab (MetaDisplay *display,
binding->handler->func &&
binding->handler->func != binding->handler->default_func)
{
invoke_handler (display, screen, binding->handler, NULL, event, binding);
invoke_handler (display, screen, binding->handler, NULL, event, device, binding);
return TRUE;
}
break;
@@ -2436,7 +2444,7 @@ process_tab_grab (MetaDisplay *display,
}
/* Some unhandled key press */
invoke_handler_by_name (display, screen, "tab-popup-cancel", NULL, event);
invoke_handler_by_name (display, screen, "tab-popup-cancel", NULL, event, device);
return FALSE;
}
@@ -2662,11 +2670,12 @@ process_tab_grab (MetaDisplay *display,
static void
handle_switch_to_workspace (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *event_window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *event_window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
gint which = binding->handler->data;
MetaWorkspace *workspace;
@@ -2683,8 +2692,8 @@ handle_switch_to_workspace (MetaDisplay *display,
* Note that we're the only caller of that function, so perhaps
* we should merge with it.
*/
handle_workspace_switch (display, screen, event_window, event, binding,
dummy);
handle_workspace_switch (display, screen, event_window, event,
binding, device, dummy);
return;
}
@@ -2703,11 +2712,12 @@ handle_switch_to_workspace (MetaDisplay *display,
static void
handle_maximize_vertically (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->has_resize_func)
{
@@ -2720,11 +2730,12 @@ handle_maximize_vertically (MetaDisplay *display,
static void
handle_maximize_horizontally (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->has_resize_func)
{
@@ -2788,6 +2799,7 @@ handle_move_to_corner_nw (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, FALSE, FALSE, dummy);
@@ -2799,6 +2811,7 @@ handle_move_to_corner_ne (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, TRUE, FALSE, dummy);
@@ -2810,6 +2823,7 @@ handle_move_to_corner_sw (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, FALSE, TRUE, dummy);
@@ -2821,6 +2835,7 @@ handle_move_to_corner_se (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
handle_move_to_corner_backend (display, screen, window, TRUE, TRUE, TRUE, TRUE, dummy);
@@ -2832,6 +2847,7 @@ handle_move_to_side_n (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
handle_move_to_corner_backend (display, screen, window, FALSE, TRUE, FALSE, FALSE, dummy);
@@ -2843,6 +2859,7 @@ handle_move_to_side_s (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
handle_move_to_corner_backend (display, screen, window, FALSE, TRUE, FALSE, TRUE, dummy);
@@ -2854,6 +2871,7 @@ handle_move_to_side_e (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
handle_move_to_corner_backend (display, screen, window, TRUE, FALSE, TRUE, FALSE, dummy);
@@ -2865,6 +2883,7 @@ handle_move_to_side_w (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
handle_move_to_corner_backend (display, screen, window, TRUE, FALSE, FALSE, FALSE, dummy);
@@ -2876,6 +2895,7 @@ handle_move_to_center (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
MetaRectangle work_area;
@@ -3029,11 +3049,12 @@ process_workspace_switch_grab (MetaDisplay *display,
static void
handle_show_desktop (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
Time evtime;
@@ -3056,11 +3077,12 @@ handle_show_desktop (MetaDisplay *display,
static void
handle_panel (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
MetaKeyBindingAction action = binding->handler->data;
Atom action_atom;
@@ -3111,16 +3133,15 @@ handle_panel (MetaDisplay *display,
static void
handle_activate_window_menu (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *event_window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *event_window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
MetaFocusInfo *focus_info;
MetaDevice *device;
device = meta_input_event_get_device (display, event);
focus_info = meta_display_get_focus_info (display, device);
if (focus_info->focus_window &&
@@ -3210,8 +3231,8 @@ do_choose_window (MetaDisplay *display,
if (state & ShiftMask)
backward = !backward;
evtime = meta_input_event_get_time (display, event);
device = meta_input_event_get_device (display, event);
evtime = meta_input_event_get_time (display, event);
initial_selection = meta_display_get_tab_next (display,
type,
@@ -3302,11 +3323,12 @@ do_choose_window (MetaDisplay *display,
static void
handle_switch (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *event_window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *event_window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
gint backwards = (binding->handler->flags & META_KEY_BINDING_IS_REVERSED) != 0;
@@ -3316,11 +3338,12 @@ handle_switch (MetaDisplay *display,
static void
handle_cycle (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *event_window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *event_window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
gint backwards = (binding->handler->flags & META_KEY_BINDING_IS_REVERSED) != 0;
@@ -3334,6 +3357,7 @@ handle_tab_popup_select (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
/* Stub for custom handlers; no default implementation */
@@ -3345,6 +3369,7 @@ handle_tab_popup_cancel (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
/* Stub for custom handlers; no default implementation */
@@ -3356,6 +3381,7 @@ handle_toggle_fullscreen (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->fullscreen)
@@ -3370,6 +3396,7 @@ handle_toggle_above (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->wm_state_above)
@@ -3384,26 +3411,26 @@ handle_toggle_tiled (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
MetaTileMode mode = binding->handler->data;
MetaDevice *device = meta_input_event_get_device (display, event);
MetaDevice *pointer = meta_device_get_paired_device (device);
if ((META_WINDOW_TILED_LEFT (window) && mode == META_TILE_LEFT) ||
(META_WINDOW_TILED_RIGHT (window) && mode == META_TILE_RIGHT))
{
window->tile_monitor_number = window->saved_maximize ? window->monitor->number
: -1;
: -1;
window->tile_mode = window->saved_maximize ? META_TILE_MAXIMIZED
: META_TILE_NONE;
: META_TILE_NONE;
if (window->saved_maximize)
meta_window_maximize (window, META_MAXIMIZE_VERTICAL |
META_MAXIMIZE_HORIZONTAL);
META_MAXIMIZE_HORIZONTAL);
else
meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL |
META_MAXIMIZE_HORIZONTAL);
META_MAXIMIZE_HORIZONTAL);
}
else if (meta_window_can_tile_side_by_side (window, pointer))
{
@@ -3422,11 +3449,12 @@ handle_toggle_tiled (MetaDisplay *display,
static void
handle_toggle_maximized (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (META_WINDOW_MAXIMIZED (window))
meta_window_unmaximize (window,
@@ -3444,6 +3472,7 @@ handle_maximize (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->has_maximize_func)
@@ -3458,6 +3487,7 @@ handle_unmaximize (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->maximized_vertically || window->maximized_horizontally)
@@ -3472,6 +3502,7 @@ handle_toggle_shaded (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
Time evtime;
@@ -3490,6 +3521,7 @@ handle_close (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->has_close_func)
@@ -3504,6 +3536,7 @@ handle_minimize (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->has_minimize_func)
@@ -3516,6 +3549,7 @@ handle_begin_move (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->has_move_func)
@@ -3534,6 +3568,7 @@ handle_begin_resize (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->has_resize_func)
@@ -3548,11 +3583,12 @@ handle_begin_resize (MetaDisplay *display,
static void
handle_toggle_on_all_workspaces (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
gpointer dummy)
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
if (window->on_all_workspaces_requested)
meta_window_unstick (window);
@@ -3562,10 +3598,11 @@ handle_toggle_on_all_workspaces (MetaDisplay *display,
static void
handle_move_to_workspace (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
gint which = binding->handler->data;
@@ -3621,6 +3658,7 @@ handle_raise_or_lower (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
/* Get window at pointer */
@@ -3668,6 +3706,7 @@ handle_raise (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
meta_window_raise (window);
@@ -3679,24 +3718,24 @@ handle_lower (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
meta_window_lower (window);
}
static void
handle_workspace_switch (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
gint motion = binding->handler->data;
unsigned int grab_mask;
MetaWorkspace *next;
gboolean grabbed_before_release;
MetaDevice *device;
guint state;
Time evtime;
@@ -3711,7 +3750,6 @@ handle_workspace_switch (MetaDisplay *display,
/* FIXME should we use binding->mask ? */
grab_mask = state & ~(display->ignored_modifier_mask);
evtime = meta_input_event_get_time (display, event);
device = meta_input_event_get_device (display, event);
if (!meta_display_begin_grab_op (display,
screen,
@@ -3752,10 +3790,11 @@ handle_workspace_switch (MetaDisplay *display,
static void
handle_set_spew_mark (MetaDisplay *display,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaScreen *screen,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer dummy)
{
meta_verbose ("-- MARK MARK MARK MARK --\n");

View File

@@ -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;
@@ -429,6 +432,12 @@ struct _MetaWindow
/* Focus info if the window is focused, or NULL */
MetaFocusInfo *cur_focus;
GHashTable *cur_touches;
gdouble initial_touch_area_width;
gdouble initial_touch_area_height;
gdouble cur_touch_area_width;
gdouble cur_touch_area_height;
};
struct _MetaWindowClass
@@ -675,4 +684,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

View File

@@ -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
@@ -240,6 +244,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);
@@ -1297,6 +1304,14 @@ meta_window_new_with_attrs (MetaDisplay *display,
meta_display_grab_focus_window_button (window->display, window);
}
if (window->frame &&
(window->type == META_WINDOW_NORMAL ||
window->type == META_WINDOW_DIALOG ||
window->type == META_WINDOW_MODAL_DIALOG))
{
meta_display_grab_window_touches (window->display, window);
}
if (window->type == META_WINDOW_DESKTOP ||
window->type == META_WINDOW_DOCK)
{
@@ -1905,6 +1920,7 @@ meta_window_unmanage (MetaWindow *window,
meta_window_ungrab_keys (window);
meta_display_ungrab_window_buttons (window->display, window->xwindow);
meta_display_ungrab_focus_window_button (window->display, window);
meta_display_ungrab_window_touches (window->display, window);
meta_display_unregister_x_window (window->display, window->xwindow);
@@ -8815,6 +8831,30 @@ update_move (MetaWindow *window,
else if (meta_window_can_tile_maximized (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) >= 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 * TILING_ZOOM_FACTOR)
{
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;
}
}
}
}
else
window->tile_mode = META_TILE_NONE;
@@ -11110,3 +11150,347 @@ 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;
gboolean only_hotspot;
} BoundingRectCoords;
static void
calculate_touch_bounding_rect (gpointer key,
gpointer value,
gpointer user_data)
{
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)
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 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,
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;
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),
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 < 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
* 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 >= N_TOUCHES_FOR_GRAB)
{
gdouble center_x, center_y, width, height;
if (n_touches == N_TOUCHES_FOR_GRAB && 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;
}
/* Set grab x/y coordinates at the middle of the bounding box,
* this will be the hotspot for the window moving operation
*/
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)
{
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
*/
meta_display_begin_grab_op (window->display,
window->screen,
window,
device,
META_GRAB_OP_MOVING,
TRUE, FALSE,
1, 0,
evtime,
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);
}
}
else if (window->cur_grab)
{
/* 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;
}
return FALSE;
}
void
meta_window_end_touch (MetaWindow *window,
XEvent *event)
{
MetaTouchInfo *info;
MetaDevice *source;
guint touch_id, n_touches;
MetaDevice *device;
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);
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, &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)
{
/* 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;
meta_display_end_grab_op (window->display, device, evtime);
}
else if (n_touches == 0 &&
window->tile_mode != META_TILE_NONE)
{
meta_window_tile (window);
update_tile_mode (window);
}
}

View File

@@ -254,6 +254,7 @@ typedef void (* MetaKeyHandlerFunc) (MetaDisplay *display,
MetaWindow *window,
XEvent *event,
MetaKeyBinding *binding,
MetaDevice *device,
gpointer user_data);
typedef struct _MetaKeyHandler MetaKeyHandler;