gdk,csw: handle implicit touch grabs

If the touch sequence happens on a window with GDK_TOUCH_MASK set,
a GdkTouchGrabInfo is created to back it up. Else a device grab is
only created if the sequence emulates the pointer.

If both a device and a touch grab are present on a window, the later
of them both is obeyed, Any grab on the device happening after a
touch grab generates grab broken on all the windows an implicit
touch grab was going on, and all touches would be automatically
removed from every touch cluster.
This commit is contained in:
Carlos Garnacho
2011-12-29 00:06:45 +01:00
parent 61e625d9a6
commit f2d71d3da5
3 changed files with 156 additions and 39 deletions

View File

@@ -697,6 +697,33 @@ _gdk_display_add_device_grab (GdkDisplay *display,
return info;
}
static void
_gdk_display_break_touch_grabs (GdkDisplay *display,
GdkDevice *device,
GdkWindow *new_grab_window)
{
guint i = 0;
while (i < display->touch_implicit_grabs->len)
{
GdkTouchGrabInfo *info;
info = &g_array_index (display->touch_implicit_grabs,
GdkTouchGrabInfo, i);
if (info->device == device &&
info->window != new_grab_window)
{
generate_grab_broken_event (GDK_WINDOW (info->window),
device, TRUE, new_grab_window);
_gdk_window_finish_touch_id (info->window, device, info->touch_id);
g_array_remove_index_fast (display->touch_implicit_grabs, i);
}
else
i++;
}
}
void
_gdk_display_add_touch_grab (GdkDisplay *display,
GdkDevice *device,
@@ -1025,12 +1052,15 @@ _gdk_display_device_grab_update (GdkDisplay *display,
next_grab = NULL; /* Actually its not yet active */
}
if (next_grab)
_gdk_display_break_touch_grabs (display, device, next_grab->window);
if ((next_grab == NULL && current_grab->implicit_ungrab) ||
(next_grab != NULL && current_grab->window != next_grab->window))
generate_grab_broken_event (GDK_WINDOW (current_grab->window),
(next_grab != NULL && current_grab->window != next_grab->window))
generate_grab_broken_event (GDK_WINDOW (current_grab->window),
device,
current_grab->implicit,
next_grab? next_grab->window : NULL);
current_grab->implicit,
next_grab? next_grab->window : NULL);
/* Remove old grab */
grabs = g_list_delete_link (grabs, grabs);

View File

@@ -334,6 +334,9 @@ gboolean _gdk_window_update_viewable (GdkWindow *window);
void _gdk_window_process_updates_recurse (GdkWindow *window,
cairo_region_t *expose_region);
gboolean _gdk_window_finish_touch_id (GdkWindow *window,
GdkDevice *device,
guint touch_id);
void _gdk_screen_close (GdkScreen *screen);

View File

@@ -9206,18 +9206,37 @@ _gdk_synthesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
static GdkWindow *
get_event_window (GdkDisplay *display,
GdkDevice *device,
GdkWindow *pointer_window,
GdkEventType type,
GdkModifierType mask,
guint *evmask_out,
gulong serial)
guint touch_id,
GdkWindow *pointer_window,
GdkEventType type,
GdkModifierType mask,
guint *evmask_out,
gulong serial)
{
guint evmask;
GdkWindow *grab_window;
GdkDeviceGrabInfo *grab;
GdkTouchGrabInfo *touch_grab;
touch_grab = _gdk_display_has_touch_grab (display, device, touch_id, serial);
grab = _gdk_display_has_device_grab (display, device, serial);
if (touch_grab != NULL &&
(!grab || grab->implicit || touch_grab->serial >= grab->serial_start))
{
evmask = touch_grab->event_mask;
evmask = update_evmask_for_button_motion (evmask, mask);
if (evmask & type_masks[type])
{
if (evmask_out)
*evmask_out = evmask;
return touch_grab->window;
}
else
return NULL;
}
if (grab != NULL && !grab->owner_events)
{
evmask = grab->event_mask;
@@ -9390,6 +9409,24 @@ _gdk_window_lookup_touch_cluster (GdkWindow *window,
return info->cluster;
}
gboolean
_gdk_window_finish_touch_id (GdkWindow *window,
GdkDevice *device,
guint touch_id)
{
TouchEventInfo *info;
info = touch_event_info_lookup (window, device, touch_id, FALSE);
if (info)
{
gdk_touch_cluster_remove_touch (info->cluster, touch_id);
return TRUE;
}
return FALSE;
}
static gboolean
proxy_pointer_event (GdkDisplay *display,
GdkEvent *source_event,
@@ -9542,9 +9579,14 @@ proxy_pointer_event (GdkDisplay *display,
GdkWindow *event_win;
guint evmask;
gboolean is_hint;
guint touch_id;
if (!gdk_event_get_touch_id (source_event, &touch_id))
touch_id = 0;
event_win = get_event_window (display,
device,
touch_id,
pointer_window,
source_event->type,
state,
@@ -9676,6 +9718,7 @@ proxy_button_event (GdkEvent *source_event,
GdkWindow *w;
GdkDevice *device, *source_device;
GdkEventMask evmask;
guint touch_id;
type = source_event->any.type;
event_window = source_event->any.window;
@@ -9689,10 +9732,14 @@ proxy_button_event (GdkEvent *source_event,
toplevel_x, toplevel_y,
&toplevel_x, &toplevel_y);
if (!gdk_event_get_touch_id (source_event, &touch_id))
touch_id = 0;
pointer_info = _gdk_display_get_pointer_info (display, device);
*handle_ungrab = TRUE;
if (type == GDK_BUTTON_PRESS &&
if ((type == GDK_BUTTON_PRESS ||
type == GDK_TOUCH_PRESS) &&
!source_event->any.send_event &&
_gdk_display_has_device_grab (display, device, serial) == NULL)
{
@@ -9707,23 +9754,49 @@ proxy_button_event (GdkEvent *source_event,
(parent = get_event_parent (w)) != NULL &&
parent->window_type != GDK_WINDOW_ROOT)
{
if (w->event_mask & GDK_BUTTON_PRESS_MASK)
if (w->event_mask & GDK_BUTTON_PRESS_MASK &&
(type == GDK_BUTTON_PRESS ||
_gdk_event_get_pointer_emulated (source_event)))
break;
if (type == GDK_TOUCH_PRESS &&
w->event_mask & GDK_TOUCH_MASK)
break;
w = parent;
}
pointer_window = (GdkWindow *)w;
pointer_window = w;
_gdk_display_add_device_grab (display,
device,
pointer_window,
event_window,
GDK_OWNERSHIP_NONE,
FALSE,
gdk_window_get_events (pointer_window),
serial,
time_,
TRUE);
_gdk_display_device_grab_update (display, device, source_device, serial);
if (pointer_window)
{
if (type == GDK_TOUCH_PRESS &&
pointer_window->event_mask & GDK_TOUCH_MASK)
{
guint touch_id;
gdk_event_get_touch_id (source_event, &touch_id);
_gdk_display_add_touch_grab (display, device, touch_id,
pointer_window, event_window,
gdk_window_get_events (pointer_window),
serial, time_);
}
else if (type == GDK_BUTTON_PRESS ||
_gdk_event_get_pointer_emulated (source_event))
{
_gdk_display_add_device_grab (display,
device,
pointer_window,
event_window,
GDK_OWNERSHIP_NONE,
FALSE,
gdk_window_get_events (pointer_window),
serial,
time_,
TRUE);
_gdk_display_device_grab_update (display, device,
source_device, serial);
}
}
}
pointer_window = get_pointer_window (display, toplevel_window, device,
@@ -9732,9 +9805,10 @@ proxy_button_event (GdkEvent *source_event,
event_win = get_event_window (display,
device,
pointer_window,
type, state,
&evmask, serial);
touch_id,
pointer_window,
type, state,
&evmask, serial);
if (event_win == NULL || display->ignore_core_events)
return TRUE;
@@ -9844,9 +9918,6 @@ proxy_button_event (GdkEvent *source_event,
if (by_touch)
g_hash_table_remove (by_touch, GUINT_TO_POINTER (touch_id));
/* Only remove the grab if it was the last pending touch on the window */
*handle_ungrab = (g_hash_table_size (by_touch) == 0);
}
else if (type == GDK_TOUCH_PRESS)
store_touch_event (event_win, gdk_event_copy (event),
@@ -10104,16 +10175,29 @@ _gdk_windowing_got_event (GdkDisplay *display,
event->type == GDK_TOUCH_RELEASE) &&
!event->any.send_event)
{
button_release_grab =
_gdk_display_has_device_grab (display, device, serial);
if (button_release_grab &&
button_release_grab->implicit &&
(event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
{
button_release_grab->serial_end = serial;
button_release_grab->implicit_ungrab = FALSE;
_gdk_display_device_grab_update (display, device, source_device, serial);
}
guint touch_id;
if (event->type == GDK_TOUCH_RELEASE &&
gdk_event_get_touch_id (event, &touch_id))
{
_gdk_display_end_touch_grab (display, device, touch_id);
}
if (event->type == GDK_BUTTON_RELEASE ||
_gdk_event_get_pointer_emulated (event))
{
button_release_grab =
_gdk_display_has_device_grab (display, device, serial);
if (button_release_grab &&
button_release_grab->implicit &&
(event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
{
button_release_grab->serial_end = serial;
button_release_grab->implicit_ungrab = FALSE;
_gdk_display_device_grab_update (display, device, source_device, serial);
}
}
}
out: