New approach for grab tracking code

We try to track the exact grab state, i.e. whats valid on the client
now and whats comming soon via the xserver roundtrip (and when).
This commit is contained in:
Alexander Larsson 2009-01-31 19:42:44 +01:00 committed by Alexander Larsson
parent 526ff6dd68
commit 26cbf87d7d
10 changed files with 643 additions and 398 deletions

View File

@ -750,69 +750,150 @@ generate_grab_broken_event (GdkWindow *window,
}
}
void
_gdk_display_set_has_pointer_grab (GdkDisplay *display,
/* Get the pointer grab in effects for events we just sent */
GdkPointerGrabInfo *
_gdk_display_get_active_pointer_grab (GdkDisplay *display)
{
GdkPointerGrabInfo *info;
if (display->pointer_grabs == NULL)
return NULL;
info = display->pointer_grabs->data;
if (info->activated)
return info;
return NULL;
}
GdkPointerGrabInfo *
_gdk_display_get_last_pointer_grab (GdkDisplay *display)
{
GList *l;
l = display->pointer_grabs;
if (l == NULL)
return NULL;
while (l->next != NULL)
l = l->next;
return (GdkPointerGrabInfo *)l->data;
}
GdkPointerGrabInfo *
_gdk_display_add_pointer_grab (GdkDisplay *display,
GdkWindow *window,
GdkWindow *native_window,
gboolean owner_events,
GdkEventMask event_mask,
unsigned long serial,
unsigned long serial_start,
guint32 time,
gboolean implicit)
{
GdkWindow *src_toplevel, *dest_toplevel, *src_window;
GdkPointerGrabInfo *info, *other_info;
GList *l;
if (display->pointer_grab.window != NULL &&
display->pointer_grab.window != window)
info = g_new0 (GdkPointerGrabInfo, 1);
info->window = g_object_ref (window);
info->native_window = g_object_ref (native_window);
info->serial_start = serial_start;
info->serial_end = G_MAXULONG;
info->owner_events = owner_events;
info->event_mask = event_mask;
info->time = time;
info->implicit = implicit;
info->converted_implicit = FALSE;
/* Find the first grab that has a larger start time (if any) and insert
* before that. I.E we insert after already existing grabs with same
* start time */
for (l = display->pointer_grabs; l != NULL; l = l->next)
{
generate_grab_broken_event (GDK_WINDOW (display->pointer_grab.window),
FALSE, display->pointer_grab.implicit,
window);
other_info = l->data;
if (info->serial_start < other_info->serial_start)
break;
}
display->pointer_grabs =
g_list_insert_before (display->pointer_grabs, l, info);
/* Make sure the new grab end before next grab */
if (l)
{
other_info = l->data;
info->serial_end = other_info->serial_start;
}
/* We need to generate crossing events for the grab.
* However, there are never any crossing events for implicit grabs
* TODO: ... Actually, this could happen if the pointer window doesn't have button mask so a parent gets the event...
*/
if (!implicit)
/* Find any previous grab and update its end time */
l = g_list_find (display->pointer_grabs, info);
l = l->prev;
if (l)
{
int x, y;
other_info = l->data;
other_info->serial_end = serial_start;
}
return info;
}
static void
free_pointer_grab (GdkPointerGrabInfo *info)
{
g_object_unref (info->window);
g_object_unref (info->native_window);
g_free (info);
}
/* _gdk_syntesize_crossing_events only works inside one toplevel.
This function splits things into two calls if needed, converting the
coordinates to the right toplevel */
static void
synthesize_crossing_events (GdkDisplay *display,
GdkWindow *src_window,
GdkWindow *dest_window,
GdkCrossingMode crossing_mode,
guint32 time,
gulong serial)
{
GdkWindow *src_toplevel, *dest_toplevel;
GdkModifierType state;
int x, y;
/* We send GRAB crossing events from the window under the pointer to the
grab window. Except if there is an old grab then we start from that */
if (display->pointer_grab.window)
src_window = display->pointer_grab.window;
else
src_window = display->pointer_info.window_under_pointer;
/* Unset any current grab to make sure we send the events */
display->pointer_grab.window = NULL;
if (src_window != window)
{
/* _gdk_syntesize_crossing_events only works inside one toplevel, split into two calls if needed */
if (src_window)
src_toplevel = gdk_window_get_toplevel (src_window);
else
src_toplevel = NULL;
dest_toplevel = gdk_window_get_toplevel (window);
if (dest_window)
dest_toplevel = gdk_window_get_toplevel (dest_window);
else
dest_toplevel = NULL;
if (src_toplevel == NULL && dest_toplevel == NULL)
return;
if (src_toplevel == NULL ||
src_toplevel == dest_toplevel)
{
/* Same toplevels */
_gdk_windowing_window_get_pointer (display,
dest_toplevel,
&x, &y, &state);
_gdk_syntesize_crossing_events (display,
src_window,
window,
GDK_CROSSING_GRAB,
dest_window,
crossing_mode,
x, y, state,
time,
NULL);
NULL,
serial);
}
else
else if (dest_toplevel == NULL)
{
_gdk_windowing_window_get_pointer (display,
src_toplevel,
@ -820,66 +901,94 @@ _gdk_display_set_has_pointer_grab (GdkDisplay *display,
_gdk_syntesize_crossing_events (display,
src_window,
NULL,
GDK_CROSSING_GRAB,
crossing_mode,
x, y, state,
time,
NULL);
NULL,
serial);
}
else
{
/* Different toplevels */
_gdk_windowing_window_get_pointer (display,
src_toplevel,
&x, &y, &state);
_gdk_syntesize_crossing_events (display,
src_window,
NULL,
crossing_mode,
x, y, state,
time,
NULL,
serial);
_gdk_windowing_window_get_pointer (display,
dest_toplevel,
&x, &y, &state);
_gdk_syntesize_crossing_events (display,
NULL,
window,
GDK_CROSSING_GRAB,
dest_window,
crossing_mode,
x, y, state,
time,
NULL);
NULL,
serial);
}
}
static void
switch_to_pointer_grab (GdkDisplay *display,
GdkPointerGrabInfo *grab,
GdkPointerGrabInfo *last_grab,
guint32 time,
gulong serial)
{
GdkWindow *src_window, *pointer_window;
GdkWindowObject *w;
GList *old_grabs;
GdkModifierType state;
int x, y;
/* Temporarily unset pointer to make sure we send the crossing events below */
old_grabs = display->pointer_grabs;
display->pointer_grabs = NULL;
if (grab)
{
/* New grab is in effect */
/* We need to generate crossing events for the grab.
* However, there are never any crossing events for implicit grabs
* TODO: ... Actually, this could happen if the pointer window
* doesn't have button mask so a parent gets the event...
*/
if (!grab->implicit)
{
/* We send GRAB crossing events from the window under the pointer to the
grab window. Except if there is an old grab then we start from that */
if (last_grab)
src_window = last_grab->window;
else
src_window = display->pointer_info.window_under_pointer;
if (src_window != grab->window)
{
synthesize_crossing_events (display,
src_window, grab->window,
GDK_CROSSING_GRAB, time, serial);
}
/* !owner_event Grabbing a window that we're not inside, current status is
now NULL (i.e. outside grabbed window) */
if (!owner_events && display->pointer_info.window_under_pointer != window)
if (!grab->owner_events && display->pointer_info.window_under_pointer != grab->window)
_gdk_display_set_window_under_pointer (display, NULL);
}
display->pointer_grab.window = window;
display->pointer_grab.native_window = native_window;
display->pointer_grab.serial = serial;
display->pointer_grab.owner_events = owner_events;
display->pointer_grab.event_mask = event_mask;
display->pointer_grab.time = time;
display->pointer_grab.implicit = implicit;
display->pointer_grab.converted_implicit = FALSE;
}
void
_gdk_display_unset_has_pointer_grab (GdkDisplay *display,
gboolean implicit,
gboolean do_grab_one_pointer_release_event,
guint32 time)
{
GdkWindow *pointer_window, *src_toplevel, *dest_toplevel;
GdkWindow *old_grab_window;
GdkWindow *old_native_grab_window;
int x, y;
GdkModifierType state;
GdkWindowObject *w;
old_grab_window = display->pointer_grab.window;
old_native_grab_window = display->pointer_grab.native_window;
if (old_grab_window == NULL)
return; /* This happens in the gdk_window_hide case */
if (do_grab_one_pointer_release_event)
display->pointer_grab.grab_one_pointer_release_event = display->pointer_grab.window;
/* Set first so crossing events get sent */
display->pointer_grab.window = NULL;
grab->activated = TRUE;
}
else if (last_grab)
{
pointer_window = _gdk_windowing_window_at_pointer (display, &x, &y, &state);
if (pointer_window != NULL &&
(GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
@ -905,73 +1014,170 @@ _gdk_display_unset_has_pointer_grab (GdkDisplay *display,
}
/* w is now toplevel and x,y in toplevel coords */
display->pointer_info.toplevel_under_pointer = g_object_ref (w);
/* Find child window */
/* Find (possibly virtual) child window */
pointer_window =
_gdk_window_find_descendant_at ((GdkWindow *)w,
x, y,
NULL, NULL);
}
if (pointer_window == NULL)
{
_gdk_syntesize_crossing_events (display,
old_grab_window,
NULL,
GDK_CROSSING_UNGRAB,
x, y, state,
time,
NULL);
}
else
{
if (pointer_window != old_grab_window)
{
/* _gdk_syntesize_crossing_events only works inside one toplevel, split into two calls if needed */
src_toplevel = gdk_window_get_toplevel (old_grab_window);
dest_toplevel = gdk_window_get_toplevel (pointer_window);
if (src_toplevel == dest_toplevel)
{
_gdk_syntesize_crossing_events (display,
display->pointer_info.window_under_pointer,
pointer_window,
GDK_CROSSING_UNGRAB,
x, y, state,
time,
NULL);
}
else
{
/* TODO: We're reporting the wrong coords here. They are in pointer_window toplevel coords */
_gdk_syntesize_crossing_events (display,
display->pointer_info.window_under_pointer,
NULL,
GDK_CROSSING_UNGRAB,
x, y, state,
time,
NULL);
_gdk_syntesize_crossing_events (display,
NULL,
pointer_window,
GDK_CROSSING_UNGRAB,
x, y, state,
time,
NULL);
}
}
}
if (pointer_window != last_grab->window)
synthesize_crossing_events (display,
last_grab->window, pointer_window,
GDK_CROSSING_UNGRAB, time, serial);
/* We're now ungrabbed, update the window_under_pointer */
_gdk_display_set_window_under_pointer (display, pointer_window);
if (implicit)
generate_grab_broken_event (old_grab_window,
FALSE, implicit,
if (last_grab->implicit_ungrab)
generate_grab_broken_event (last_grab->window,
FALSE, TRUE,
NULL);
}
display->pointer_grabs = old_grabs;
}
void
_gdk_display_pointer_grab_update (GdkDisplay *display,
gulong current_serial)
{
GdkPointerGrabInfo *current_grab, *next_grab;
guint32 time;
time = display->last_event_time;
while (display->pointer_grabs != NULL)
{
current_grab = display->pointer_grabs->data;
if (current_grab->serial_start > current_serial)
return; /* Hasn't started yet */
if (current_grab->serial_end > current_serial ||
(current_grab->serial_end == current_serial &&
current_grab->grab_one_pointer_release_event))
{
/* This one hasn't ended yet.
its the currently active one or scheduled to be active */
if (!current_grab->activated)
switch_to_pointer_grab (display, current_grab, NULL, time, current_serial);
break;
}
next_grab = NULL;
if (display->pointer_grabs->next)
{
/* This is the next active grab */
next_grab = display->pointer_grabs->next->data;
if (next_grab->serial_start > current_serial)
next_grab = NULL; /* Actually its not yet active */
}
if (next_grab == NULL ||
current_grab->window != next_grab->window)
generate_grab_broken_event (GDK_WINDOW (current_grab->window),
FALSE, current_grab->implicit,
next_grab? next_grab->window : NULL);
/* Remove old grab */
display->pointer_grabs =
g_list_delete_link (display->pointer_grabs,
display->pointer_grabs);
switch_to_pointer_grab (display,
next_grab, current_grab,
time, current_serial);
free_pointer_grab (current_grab);
}
}
static gboolean
is_parent_of (GdkWindow *parent,
GdkWindow *child)
{
GdkWindow *w;
w = child;
while (w != NULL)
{
if (w == parent)
return TRUE;
w = gdk_window_get_parent (w);
}
return FALSE;
}
static GList *
find_pointer_grab (GdkDisplay *display,
gulong serial)
{
GdkPointerGrabInfo *grab;
GList *l;
for (l = display->pointer_grabs; l != NULL; l = l->next)
{
grab = l->data;
if (serial >= grab->serial_start && serial < grab->serial_end)
return l;
}
return NULL;
}
GdkPointerGrabInfo *
_gdk_display_has_pointer_grab (GdkDisplay *display,
gulong serial)
{
GList *l;
l = find_pointer_grab (display, serial);
if (l)
return l->data;
return NULL;
}
/* Returns true if last grab was ended */
gboolean
_gdk_display_end_pointer_grab (GdkDisplay *display,
gulong serial,
GdkWindow *if_child,
gboolean implicit)
{
GdkPointerGrabInfo *grab;
GList *l;
l = find_pointer_grab (display, serial);
if (l == NULL)
return FALSE;
grab = l->data;
if (grab &&
(if_child == NULL ||
is_parent_of (grab->window, if_child)))
{
grab->serial_end = serial;
grab->implicit_ungrab = implicit;
return l->next == NULL;
}
return FALSE;
}
void
@ -1055,14 +1261,18 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
GdkWindow **grab_window,
gboolean *owner_events)
{
GdkPointerGrabInfo *info;
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
if (display->pointer_grab.window)
info = _gdk_display_get_active_pointer_grab (display);
if (info)
{
if (grab_window)
*grab_window = (GdkWindow *)display->pointer_grab.window;
*grab_window = info->window;
if (owner_events)
*owner_events = display->pointer_grab.owner_events;
*owner_events = info->owner_events;
return TRUE;
}
@ -1084,10 +1294,13 @@ gdk_pointer_grab_info_libgtk_only (GdkDisplay *display,
gboolean
gdk_display_pointer_is_grabbed (GdkDisplay *display)
{
GdkPointerGrabInfo *info;
g_return_val_if_fail (GDK_IS_DISPLAY (display), TRUE);
return (display->pointer_grab.window != NULL &&
!display->pointer_grab.implicit);
info = _gdk_display_get_active_pointer_grab (display);
return (info && !info->implicit);
}
#define __GDK_DISPLAY_C__

View File

@ -43,21 +43,6 @@ typedef struct _GdkDisplayPointerHooks GdkDisplayPointerHooks;
#define GDK_IS_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_DISPLAY))
#define GDK_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_DISPLAY, GdkDisplayClass))
/* Tracks information about the pointer grab on this display */
typedef struct
{
GdkWindow *window;
GdkWindow *native_window;
gulong serial;
gboolean owner_events;
guint event_mask;
gboolean implicit;
gboolean converted_implicit;
guint32 time;
GdkWindow *grab_one_pointer_release_event;
} GdkPointerGrabInfo;
/* Tracks information about the keyboard grab on this display */
typedef struct
{
@ -68,7 +53,6 @@ typedef struct
guint32 time;
} GdkKeyboardGrabInfo;
/* Tracks information about which window and position the pointer last was in.
* This is useful when we need to synthesize events later.
* Note that we track toplevel_under_pointer using enter/leave events,
@ -112,9 +96,12 @@ struct _GdkDisplay
gint button_x[2]; /* The last 2 button click positions. */
gint button_y[2];
GdkPointerGrabInfo pointer_grab;
GList *pointer_grabs;
GdkKeyboardGrabInfo keyboard_grab;
GdkPointerWindowInfo pointer_info;
/* Last reported event time from server */
guint32 last_event_time;
};
struct _GdkDisplayClass

View File

@ -170,6 +170,24 @@ struct _GdkEventPrivate
gpointer windowing_data;
};
/* Tracks information about the pointer grab on this display */
typedef struct
{
GdkWindow *window;
GdkWindow *native_window;
gulong serial_start;
gulong serial_end; /* exclusive, i.e. not active on serial_end */
gboolean owner_events;
guint event_mask;
gboolean implicit;
gboolean converted_implicit;
guint32 time;
gboolean activated;
gboolean implicit_ungrab;
gboolean grab_one_pointer_release_event;
} GdkPointerGrabInfo;
extern GdkEventFunc _gdk_event_func; /* Callback for events */
extern gpointer _gdk_event_data;
extern GDestroyNotify _gdk_event_notify;
@ -464,18 +482,24 @@ char *_gdk_windowing_get_startup_notify_id (GAppLaunchContext *context,
void _gdk_windowing_launch_failed (GAppLaunchContext *context,
const char *startup_notify_id);
void _gdk_display_set_has_pointer_grab (GdkDisplay *display,
GdkPointerGrabInfo *_gdk_display_get_active_pointer_grab (GdkDisplay *display);
void _gdk_display_pointer_grab_update (GdkDisplay *display,
gulong current_serial);
GdkPointerGrabInfo *_gdk_display_get_last_pointer_grab (GdkDisplay *display);
GdkPointerGrabInfo *_gdk_display_add_pointer_grab (GdkDisplay *display,
GdkWindow *window,
GdkWindow *native_window,
gboolean owner_events,
GdkEventMask event_mask,
unsigned long serial,
unsigned long serial_start,
guint32 time,
gboolean implicit);
void _gdk_display_unset_has_pointer_grab (GdkDisplay *display,
gboolean implicit,
gboolean do_grab_one_pointer_release_event,
guint32 time);
GdkPointerGrabInfo * _gdk_display_has_pointer_grab (GdkDisplay *display,
gulong serial);
gboolean _gdk_display_end_pointer_grab (GdkDisplay *display,
gulong serial,
GdkWindow *if_child,
gboolean implicit);
void _gdk_display_set_has_keyboard_grab (GdkDisplay *display,
GdkWindow *window,
GdkWindow *native_window,
@ -518,7 +542,8 @@ void _gdk_syntesize_crossing_events (GdkDisplay *display,
gint toplevel_y,
GdkModifierType mask,
guint32 time_,
GdkEvent *event_in_queue);
GdkEvent *event_in_queue,
gulong serial);
void _gdk_display_set_window_under_pointer (GdkDisplay *display,
GdkWindow *window);

View File

@ -852,6 +852,8 @@ gdk_offscreen_window_hide (GdkWindow *window)
/* May need to break grabs on children */
display = gdk_drawable_get_display (window);
/* TODO: This needs updating to the new grab world */
#if 0
if (display->pointer_grab.window != NULL)
{
if (is_parent_of (window, display->pointer_grab.window))
@ -866,6 +868,7 @@ gdk_offscreen_window_hide (GdkWindow *window)
gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
}
}
#endif
}
static void

View File

@ -5725,20 +5725,11 @@ gdk_window_hide (GdkWindow *window)
/* May need to break grabs on children */
display = gdk_drawable_get_display (window);
if (display->pointer_grab.window != NULL)
{
if (is_parent_of (window, display->pointer_grab.window))
{
/* Call this ourselves, even though gdk_display_pointer_ungrab
does so too, since we want to pass implicit == TRUE so the
broken grab event is generated */
_gdk_display_unset_has_pointer_grab (display,
TRUE,
FALSE,
GDK_CURRENT_TIME);
if (_gdk_display_end_pointer_grab (display,
_gdk_windowing_window_get_next_serial (display),
window,
TRUE))
gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
}
}
if (display->keyboard_grab.window != NULL)
{
@ -6561,6 +6552,7 @@ static void
update_cursor (GdkDisplay *display)
{
GdkWindowObject *pointer_window, *cursor_window;
GdkPointerGrabInfo *grab;
pointer_window = (GdkWindowObject *)display->pointer_info.window_under_pointer;
@ -6570,13 +6562,17 @@ update_cursor (GdkDisplay *display)
cursor_window->parent->window_type != GDK_WINDOW_ROOT)
cursor_window = cursor_window->parent;
if (display->pointer_grab.window != NULL &&
!is_parent_of (display->pointer_grab.window, (GdkWindow *)cursor_window))
cursor_window = (GdkWindowObject *)display->pointer_grab.window;
/* We ignore the serials here and just pick the last grab
we've sent, as that would shortly be used anyway. */
grab = _gdk_display_get_last_pointer_grab (display);
if (grab != NULL &&
!is_parent_of (grab->window, (GdkWindow *)cursor_window))
cursor_window = (GdkWindowObject *)grab->window;
/* Set all cursors on toplevel, otherwise its tricky to keep track of
* which native window has what cursor set. */
GDK_WINDOW_IMPL_GET_IFACE (pointer_window->impl)->set_cursor (gdk_window_get_toplevel ((GdkWindow *)pointer_window),
GDK_WINDOW_IMPL_GET_IFACE (pointer_window->impl)->set_cursor
(gdk_window_get_toplevel ((GdkWindow *)pointer_window),
cursor_window->cursor);
}
@ -7869,14 +7865,18 @@ send_crossing_event (GdkDisplay *display,
gint toplevel_y,
GdkModifierType mask,
guint32 time_,
GdkEvent *event_in_queue)
GdkEvent *event_in_queue,
gulong serial)
{
GdkEvent *event;
guint32 event_mask;
GdkPointerGrabInfo *grab;
if (display->pointer_grab.window != NULL &&
!display->pointer_grab.owner_events &&
(GdkWindow *)window != display->pointer_grab.window)
grab = _gdk_display_has_pointer_grab (display, serial);
if (grab != NULL &&
!grab->owner_events &&
(GdkWindow *)window != grab->window)
return;
if (type == GDK_LEAVE_NOTIFY)
@ -7918,7 +7918,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display,
gint toplevel_y,
GdkModifierType mask,
guint32 time_,
GdkEvent *event_in_queue)
GdkEvent *event_in_queue,
gulong serial)
{
GdkWindowObject *c;
GdkWindowObject *win, *last, *next;
@ -7958,7 +7959,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display,
NULL,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue);
event_in_queue,
serial);
if (c != a)
{
@ -7978,7 +7980,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display,
(GdkWindow *)last,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue);
event_in_queue,
serial);
last = win;
win = win->parent;
@ -8023,7 +8026,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display,
(GdkWindow *)next,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue);
event_in_queue,
serial);
}
g_list_free (path);
}
@ -8043,7 +8047,8 @@ _gdk_syntesize_crossing_events (GdkDisplay *display,
NULL,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue);
event_in_queue,
serial);
}
}
@ -8067,9 +8072,11 @@ static GdkWindow *
get_pointer_window (GdkDisplay *display,
GdkWindow *event_window,
gdouble toplevel_x,
gdouble toplevel_y)
gdouble toplevel_y,
gulong serial)
{
GdkWindow *pointer_window;
GdkPointerGrabInfo *grab;
if (event_window == display->pointer_info.toplevel_under_pointer)
pointer_window =
@ -8079,9 +8086,10 @@ get_pointer_window (GdkDisplay *display,
else
pointer_window = NULL;
if (display->pointer_grab.window != NULL &&
!display->pointer_grab.owner_events &&
pointer_window != display->pointer_grab.window)
grab = _gdk_display_has_pointer_grab (display, serial);
if (grab != NULL &&
!grab->owner_events &&
pointer_window != grab->window)
pointer_window = NULL;
return pointer_window;
@ -8113,16 +8121,20 @@ _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
GdkDisplay *display;
GdkWindow *changed_toplevel;
GdkWindow *new_window_under_pointer;
changed_toplevel = get_toplevel (changed_window);
gulong serial;
display = gdk_drawable_get_display (changed_window);
serial = _gdk_windowing_window_get_next_serial (display);
changed_toplevel = get_toplevel (changed_window);
if (changed_toplevel == display->pointer_info.toplevel_under_pointer)
{
new_window_under_pointer =
get_pointer_window (display, changed_toplevel,
display->pointer_info.toplevel_x,
display->pointer_info.toplevel_y);
display->pointer_info.toplevel_y,
serial);
if (new_window_under_pointer !=
display->pointer_info.window_under_pointer)
{
@ -8134,7 +8146,8 @@ _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
display->pointer_info.toplevel_y,
display->pointer_info.state,
GDK_CURRENT_TIME,
NULL);
NULL,
serial);
_gdk_display_set_window_under_pointer (display, new_window_under_pointer);
}
}
@ -8146,27 +8159,22 @@ get_event_window (GdkDisplay *display,
GdkWindow *pointer_window,
GdkEventType type,
GdkModifierType mask,
guint *evmask_out)
guint *evmask_out,
gulong serial)
{
guint evmask;
GdkWindow *grab_window;
GdkWindowObject *w;
GdkPointerGrabInfo *grab;
if ((display->pointer_grab.window != NULL && !display->pointer_grab.owner_events) ||
(type == GDK_BUTTON_RELEASE && display->pointer_grab.grab_one_pointer_release_event))
grab = _gdk_display_has_pointer_grab (display, serial);
if (grab != NULL && !grab->owner_events)
{
evmask = display->pointer_grab.event_mask;
evmask = grab->event_mask;
evmask = update_evmask_for_button_motion (evmask, mask);
if (type == GDK_BUTTON_RELEASE &&
display->pointer_grab.grab_one_pointer_release_event)
{
grab_window = display->pointer_grab.grab_one_pointer_release_event;
display->pointer_grab.grab_one_pointer_release_event = NULL;
}
else
grab_window = display->pointer_grab.window;
grab_window = grab->window;
if (evmask & type_masks[type])
{
@ -8194,17 +8202,17 @@ get_event_window (GdkDisplay *display,
w = w->parent;
}
if (display->pointer_grab.window != NULL &&
display->pointer_grab.owner_events)
if (grab != NULL &&
grab->owner_events)
{
evmask = display->pointer_grab.event_mask;
evmask = grab->event_mask;
evmask = update_evmask_for_button_motion (evmask, mask);
if (evmask & type_masks[type])
{
if (evmask_out)
*evmask_out = evmask;
return display->pointer_grab.window;
return grab->window;
}
else
return NULL;
@ -8220,7 +8228,6 @@ proxy_pointer_event (GdkDisplay *display,
{
GdkWindow *toplevel_window;
GdkWindow *pointer_window;
GdkWindow *cursor_window;
GdkEvent *event;
guint state;
gdouble toplevel_x, toplevel_y;
@ -8231,7 +8238,7 @@ proxy_pointer_event (GdkDisplay *display,
gdk_event_get_state (source_event, &state);
time_ = gdk_event_get_time (source_event);
pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y, serial);
if (display->pointer_info.window_under_pointer != pointer_window)
{
/* Either a toplevel crossing notify that ended up inside a child window,
@ -8244,7 +8251,8 @@ proxy_pointer_event (GdkDisplay *display,
GDK_CROSSING_NORMAL,
toplevel_x, toplevel_y,
state, time_,
source_event);
source_event,
serial);
_gdk_display_set_window_under_pointer (display, pointer_window);
}
@ -8258,7 +8266,8 @@ proxy_pointer_event (GdkDisplay *display,
pointer_window,
source_event->type,
state,
&evmask);
&evmask,
serial);
is_hint = FALSE;
@ -8291,22 +8300,14 @@ proxy_pointer_event (GdkDisplay *display,
}
}
/* TODO: set cursor from cursor_window, or grab cursor */
cursor_window = pointer_window;
if (display->pointer_grab.window &&
(pointer_window == NULL ||
!is_parent_of (display->pointer_grab.window, pointer_window)))
cursor_window = display->pointer_grab.window;
/* Actually, this should probably happen in synthesize crossing so it works with geometry changes */
/* unlink all move events from queue.
We handle our own, including our emulated masks. */
return TRUE;
}
static gboolean
proxy_button_event (GdkEvent *source_event)
proxy_button_event (GdkEvent *source_event,
gulong serial)
{
GdkWindow *toplevel_window;
GdkWindow *event_win;
@ -8318,6 +8319,7 @@ proxy_button_event (GdkEvent *source_event)
gdouble toplevel_x, toplevel_y;
GdkDisplay *display;
GdkWindowObject *w;
GdkPointerGrabInfo *grab;
type = source_event->any.type;
toplevel_window = source_event->any.window;
@ -8326,10 +8328,11 @@ proxy_button_event (GdkEvent *source_event)
time_ = gdk_event_get_time (source_event);
display = gdk_drawable_get_display (source_event->any.window);
grab = _gdk_display_get_active_pointer_grab (display);
if ((type == GDK_BUTTON_PRESS || type == GDK_SCROLL) &&
display->pointer_grab.window == source_event->any.window &&
display->pointer_grab.implicit &&
!display->pointer_grab.converted_implicit)
grab && grab->window == toplevel_window &&
grab->implicit && !grab->converted_implicit)
{
pointer_window =
_gdk_window_find_descendant_at (toplevel_window,
@ -8347,25 +8350,25 @@ proxy_button_event (GdkEvent *source_event)
pointer_window = (GdkWindow *)w;
if (pointer_window != NULL &&
pointer_window != source_event->any.window)
_gdk_display_set_has_pointer_grab (display,
pointer_window,
display->pointer_grab.native_window,
display->pointer_grab.owner_events,
gdk_window_get_events (pointer_window),
display->pointer_grab.serial,
display->pointer_grab.time,
display->pointer_grab.implicit);
display->pointer_grab.converted_implicit = TRUE;
pointer_window != toplevel_window)
{
g_object_ref (pointer_window);
g_object_unref (grab->window);
grab->window = pointer_window;
grab->event_mask = gdk_window_get_events (pointer_window);
}
pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
grab->converted_implicit = TRUE;
}
pointer_window = get_pointer_window (display, toplevel_window,
toplevel_x, toplevel_y,
serial);
event_win = get_event_window (display,
pointer_window,
type,
state,
NULL);
type, state,
NULL, serial);
if (event_win == NULL)
return TRUE;
@ -8478,6 +8481,13 @@ _gdk_windowing_got_event (GdkDisplay *display,
gdouble x, y;
gboolean unlink_event;
guint old_state, old_button;
GdkPointerGrabInfo *button_release_grab;
if (gdk_event_get_time (event) != GDK_CURRENT_TIME)
display->last_event_time = gdk_event_get_time (event);
_gdk_display_pointer_grab_update (display,
serial);
event_window = event->any.window;
if (!event_window)
@ -8559,7 +8569,22 @@ _gdk_windowing_got_event (GdkDisplay *display,
event,
serial);
else if (is_button_type (event->type))
unlink_event = proxy_button_event (event);
unlink_event = proxy_button_event (event,
serial);
if (event->type == GDK_BUTTON_RELEASE)
{
button_release_grab =
_gdk_display_has_pointer_grab (display, serial);
if (button_release_grab &&
button_release_grab->grab_one_pointer_release_event)
{
button_release_grab->grab_one_pointer_release_event = FALSE;
button_release_grab->serial_end = serial;
button_release_grab->implicit_ungrab = TRUE;
_gdk_display_pointer_grab_update (display, serial);
}
}
if (unlink_event)
{

View File

@ -118,6 +118,7 @@ struct _RoundtripState
Display *dpy;
_XAsyncHandler async;
gulong get_input_focus_req;
GdkDisplay *display;
GdkRoundTripCallback callback;
gpointer data;
};
@ -758,7 +759,7 @@ roundtrip_callback_idle (gpointer data)
{
RoundtripState *state = (RoundtripState *)data;
state->callback (state->data);
state->callback (state->display, state->data, state->get_input_focus_req);
g_free (state);
@ -790,6 +791,7 @@ roundtrip_handler (Display *dpy,
True);
}
if (state->callback)
gdk_threads_add_idle (roundtrip_callback_idle, state);
@ -813,6 +815,7 @@ _gdk_x11_roundtrip_async (GdkDisplay *display,
state = g_new (RoundtripState, 1);
state->display = display;
state->dpy = dpy;
state->callback = callback;
state->data = data;

View File

@ -31,8 +31,9 @@ typedef struct _GdkChildInfoX11 GdkChildInfoX11;
typedef void (*GdkSendXEventCallback) (Window window,
gboolean success,
gpointer data);
typedef void (*GdkRoundTripCallback) (gpointer data);
typedef void (*GdkRoundTripCallback) (GdkDisplay *display,
gpointer data,
gulong serial);
struct _GdkChildInfoX11
{

View File

@ -598,16 +598,11 @@ struct XPointerUngrabInfo {
};
static void
pointer_ungrab_callback (gpointer _data)
pointer_ungrab_callback (GdkDisplay *display,
gpointer data,
gulong serial)
{
struct XPointerUngrabInfo *data = _data;
_gdk_display_unset_has_pointer_grab (data->display,
FALSE,
FALSE,
data->time);
g_free (data);
_gdk_display_pointer_grab_update (display, serial);
}
@ -631,30 +626,30 @@ gdk_display_pointer_ungrab (GdkDisplay *display,
{
Display *xdisplay;
GdkDisplayX11 *display_x11;
GdkPointerGrabInfo *grab;
unsigned long serial;
g_return_if_fail (GDK_IS_DISPLAY (display));
display_x11 = GDK_DISPLAY_X11 (display);
xdisplay = GDK_DISPLAY_XDISPLAY (display);
serial = NextRequest (xdisplay);
_gdk_input_ungrab_pointer (display, time_);
XUngrabPointer (xdisplay, time_);
XFlush (xdisplay);
if (time_ == GDK_CURRENT_TIME ||
display->pointer_grab.time == GDK_CURRENT_TIME ||
!XSERVER_TIME_IS_LATER (display->pointer_grab.time, time_))
grab = _gdk_display_get_last_pointer_grab (display);
if (grab &&
(time_ == GDK_CURRENT_TIME ||
grab->time == GDK_CURRENT_TIME ||
!XSERVER_TIME_IS_LATER (grab->time, time_)))
{
struct XPointerUngrabInfo *data;
data = g_new (struct XPointerUngrabInfo, 1);
data->display = GDK_DISPLAY_OBJECT (display_x11);
data->time = time_;
_gdk_x11_roundtrip_async (data->display,
grab->serial_end = serial;
_gdk_x11_roundtrip_async (display,
pointer_ungrab_callback,
data);
NULL);
}
}

View File

@ -149,22 +149,11 @@ struct XPointerGrabInfo {
};
static void
has_pointer_grab_callback (gpointer _data)
has_pointer_grab_callback (GdkDisplay *display,
gpointer data,
gulong serial)
{
struct XPointerGrabInfo *data = _data;
_gdk_display_set_has_pointer_grab (data->display,
data->window,
data->native_window,
data->owner_events,
data->event_mask,
data->serial,
data->time,
FALSE);
g_object_unref (data->window);
g_object_unref (data->native_window);
g_free (data);
_gdk_display_pointer_grab_update (display, serial);
}
/*
@ -215,10 +204,18 @@ gdk_pointer_grab (GdkWindow * window,
native = gdk_window_get_toplevel (window);
/* We need a native window for confine to to work, ensure we have one */
if (confine_to)
gdk_window_set_has_native (confine_to, TRUE);
/* TODO: What do we do for offscreens and their children? We need to proxy the grab somehow */
if (!GDK_IS_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (native)->impl))
return GDK_GRAB_SUCCESS;
if (!_gdk_window_has_impl (window) &&
!gdk_window_is_viewable (window))
return GDK_GRAB_NOT_VIEWABLE;
if (confine_to)
confine_to = _gdk_window_get_impl_window (confine_to);
@ -285,21 +282,18 @@ gdk_pointer_grab (GdkWindow * window,
if (return_val == GrabSuccess)
{
struct XPointerGrabInfo *data;
_gdk_display_add_pointer_grab (GDK_DISPLAY_OBJECT (display_x11),
window,
native,
owner_events,
event_mask,
serial,
time,
FALSE);
data = g_new (struct XPointerGrabInfo, 1);
data->display = GDK_DISPLAY_OBJECT (display_x11);
data->window = g_object_ref (window);
data->native_window = g_object_ref (native);
data->owner_events = owner_events;
data->event_mask = event_mask;
data->serial = serial;
data->time = time;
_gdk_x11_roundtrip_async (data->display,
_gdk_x11_roundtrip_async (GDK_DISPLAY_OBJECT (display_x11),
has_pointer_grab_callback,
data);
NULL);
}
return gdk_x11_convert_grab_status (return_val);
@ -395,18 +389,7 @@ _gdk_xgrab_check_unmap (GdkWindow *window,
{
GdkDisplay *display = gdk_drawable_get_display (window);
if (display->pointer_grab.window &&
serial >= display->pointer_grab.serial)
{
GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
GdkWindowObject *tmp = GDK_WINDOW_OBJECT (display->pointer_grab.native_window);
while (tmp && tmp != private)
tmp = tmp->parent;
if (tmp)
_gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME);
}
_gdk_display_end_pointer_grab (display, serial, window, TRUE);
if (display->keyboard_grab.window &&
serial >= display->keyboard_grab.serial)
@ -433,10 +416,20 @@ void
_gdk_xgrab_check_destroy (GdkWindow *window)
{
GdkDisplay *display = gdk_drawable_get_display (window);
GdkPointerGrabInfo *grab;
if (window == display->pointer_grab.native_window &&
display->pointer_grab.window != NULL)
_gdk_display_unset_has_pointer_grab (display, TRUE, FALSE, GDK_CURRENT_TIME);
/* Make sure there is no lasting grab in this native
window */
grab = _gdk_display_get_last_pointer_grab (display);
if (grab && grab->native_window == window)
{
/* We don't know the actual serial to end, but it
doesn't really matter as this only happens
after we get told of the destroy from the
server so we know its ended in the server,
just make sure its ended. */
grab->serial_end = grab->serial_start;
}
if (window == display->keyboard_grab.native_window &&
display->keyboard_grab.window != NULL)
@ -461,31 +454,31 @@ _gdk_xgrab_check_button_event (GdkWindow *window,
XEvent *xevent)
{
GdkDisplay *display = gdk_drawable_get_display (window);
gulong serial = xevent->xany.serial;
GdkPointerGrabInfo *grab;
/* track implicit grabs for button presses */
switch (xevent->type)
{
case ButtonPress:
if (!display->pointer_grab.window)
if (!_gdk_display_has_pointer_grab (display, serial))
{
_gdk_display_set_has_pointer_grab (display,
_gdk_display_add_pointer_grab (display,
window,
window,
FALSE,
gdk_window_get_events (window),
xevent->xany.serial,
serial,
xevent->xbutton.time,
TRUE);
}
break;
case ButtonRelease:
if (display->pointer_grab.window &&
display->pointer_grab.implicit &&
serial = serial;
grab = _gdk_display_has_pointer_grab (display, serial);
if (grab && grab->implicit &&
(xevent->xbutton.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (xevent->xbutton.button - 1))) == 0)
{
_gdk_display_unset_has_pointer_grab (display, TRUE, TRUE,
xevent->xbutton.time);
}
grab->grab_one_pointer_release_event = TRUE;
break;
default:
g_assert_not_reached ();