New approach to motion event handling
This commit is contained in:
committed by
Alexander Larsson
parent
afc81c9e64
commit
b771c9924d
233
gdk/gdkdisplay.c
233
gdk/gdkdisplay.c
@ -491,7 +491,7 @@ gdk_display_real_get_window_at_pointer (GdkDisplay *display,
|
|||||||
GdkWindow *window;
|
GdkWindow *window;
|
||||||
gint x, y;
|
gint x, y;
|
||||||
|
|
||||||
window = _gdk_windowing_window_at_pointer (display, &x, &y);
|
window = _gdk_windowing_window_at_pointer (display, &x, &y, NULL);
|
||||||
|
|
||||||
/* This might need corrections, as the native window returned
|
/* This might need corrections, as the native window returned
|
||||||
may contain client side children */
|
may contain client side children */
|
||||||
@ -737,6 +737,17 @@ generate_grab_broken_event (GdkWindow *window,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_window_under_pointer (GdkDisplay *display,
|
||||||
|
GdkWindow *window)
|
||||||
|
{
|
||||||
|
if (display->pointer_info.window_under_pointer)
|
||||||
|
g_object_unref (display->pointer_info.window_under_pointer);
|
||||||
|
display->pointer_info.window_under_pointer = window;
|
||||||
|
if (window)
|
||||||
|
g_object_ref (window);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_gdk_display_set_has_pointer_grab (GdkDisplay *display,
|
_gdk_display_set_has_pointer_grab (GdkDisplay *display,
|
||||||
GdkWindow *window,
|
GdkWindow *window,
|
||||||
@ -747,51 +758,89 @@ _gdk_display_set_has_pointer_grab (GdkDisplay *display,
|
|||||||
guint32 time,
|
guint32 time,
|
||||||
gboolean implicit)
|
gboolean implicit)
|
||||||
{
|
{
|
||||||
int wx, wy;
|
GdkWindow *pointer_window, *src_toplevel, *dest_toplevel, *src_window;
|
||||||
|
|
||||||
/* Normal GRAB events are sent by listening for enter and leave
|
|
||||||
* events on the native event window, which is then proxied
|
|
||||||
* into the virtual windows when the events are seen.
|
|
||||||
* However, there are two cases where X will not send these events:
|
|
||||||
* * When there is already a grab on the native parent of the
|
|
||||||
* virtual grab window
|
|
||||||
* * When there is no grab, but the pointer is already in the
|
|
||||||
* native parent of the virtual grab window
|
|
||||||
* In the first case we send the right GRAB events from the grab, but
|
|
||||||
* in the second case we need to generate our own UNGRAB crossing events.
|
|
||||||
*/
|
|
||||||
if (display->pointer_grab.window != NULL &&
|
if (display->pointer_grab.window != NULL &&
|
||||||
display->pointer_grab.window != window)
|
display->pointer_grab.window != window)
|
||||||
{
|
{
|
||||||
generate_grab_broken_event (GDK_WINDOW (display->pointer_grab.window),
|
generate_grab_broken_event (GDK_WINDOW (display->pointer_grab.window),
|
||||||
FALSE, display->pointer_grab.implicit,
|
FALSE, display->pointer_grab.implicit,
|
||||||
window);
|
window);
|
||||||
|
|
||||||
/* Re-grabbing. Pretend we have no grab for now so that
|
|
||||||
the GRAB events get delivered */
|
|
||||||
display->pointer_grab.window = NULL;
|
|
||||||
_gdk_syntesize_crossing_events (display,
|
|
||||||
display->pointer_grab.window,
|
|
||||||
window,
|
|
||||||
GDK_CROSSING_GRAB,
|
|
||||||
/* These may be stale... */
|
|
||||||
display->pointer_info.toplevel_x,
|
|
||||||
display->pointer_info.toplevel_y,
|
|
||||||
display->pointer_info.state,
|
|
||||||
time, TRUE, TRUE);
|
|
||||||
}
|
}
|
||||||
else if (_gdk_windowing_window_at_pointer (display, &wx, &wy) == native_window)
|
|
||||||
{
|
|
||||||
_gdk_syntesize_crossing_events (display,
|
|
||||||
display->pointer_info.window_under_pointer,
|
|
||||||
window,
|
|
||||||
GDK_CROSSING_GRAB,
|
|
||||||
/* These may be stale... */
|
|
||||||
display->pointer_info.toplevel_x,
|
|
||||||
display->pointer_info.toplevel_y,
|
|
||||||
display->pointer_info.state,
|
|
||||||
time, TRUE, TRUE);
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
GdkScreen *screen;
|
||||||
|
GdkWindowObject *w;
|
||||||
|
int x, y;
|
||||||
|
GdkModifierType state;
|
||||||
|
|
||||||
|
/* 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 (src_toplevel == NULL ||
|
||||||
|
src_toplevel == dest_toplevel)
|
||||||
|
{
|
||||||
|
_gdk_windowing_window_get_pointer (display,
|
||||||
|
dest_toplevel,
|
||||||
|
&x, &y, &state);
|
||||||
|
_gdk_syntesize_crossing_events (display,
|
||||||
|
src_window,
|
||||||
|
window,
|
||||||
|
GDK_CROSSING_GRAB,
|
||||||
|
x, y, state,
|
||||||
|
time,
|
||||||
|
NULL, FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_gdk_windowing_window_get_pointer (display,
|
||||||
|
src_toplevel,
|
||||||
|
&x, &y, &state);
|
||||||
|
_gdk_syntesize_crossing_events (display,
|
||||||
|
src_window,
|
||||||
|
NULL,
|
||||||
|
GDK_CROSSING_GRAB,
|
||||||
|
x, y, state,
|
||||||
|
time,
|
||||||
|
NULL, FALSE);
|
||||||
|
_gdk_windowing_window_get_pointer (display,
|
||||||
|
dest_toplevel,
|
||||||
|
&x, &y, &state);
|
||||||
|
_gdk_syntesize_crossing_events (display,
|
||||||
|
NULL,
|
||||||
|
window,
|
||||||
|
GDK_CROSSING_GRAB,
|
||||||
|
x, y, state,
|
||||||
|
time,
|
||||||
|
NULL, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* !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)
|
||||||
|
set_window_under_pointer (display, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
display->pointer_grab.window = window;
|
display->pointer_grab.window = window;
|
||||||
@ -810,10 +859,12 @@ _gdk_display_unset_has_pointer_grab (GdkDisplay *display,
|
|||||||
gboolean do_grab_one_pointer_release_event,
|
gboolean do_grab_one_pointer_release_event,
|
||||||
guint32 time)
|
guint32 time)
|
||||||
{
|
{
|
||||||
int wx, wy;
|
GdkWindow *pointer_window, *src_toplevel, *dest_toplevel;
|
||||||
GdkWindow *old_grab_window;
|
GdkWindow *old_grab_window;
|
||||||
GdkWindow *old_native_grab_window;
|
GdkWindow *old_native_grab_window;
|
||||||
|
int x, y;
|
||||||
|
GdkModifierType state;
|
||||||
|
GdkWindowObject *w;
|
||||||
|
|
||||||
old_grab_window = display->pointer_grab.window;
|
old_grab_window = display->pointer_grab.window;
|
||||||
old_native_grab_window = display->pointer_grab.native_window;
|
old_native_grab_window = display->pointer_grab.native_window;
|
||||||
@ -821,34 +872,98 @@ _gdk_display_unset_has_pointer_grab (GdkDisplay *display,
|
|||||||
if (do_grab_one_pointer_release_event)
|
if (do_grab_one_pointer_release_event)
|
||||||
display->pointer_grab.grab_one_pointer_release_event = display->pointer_grab.window;
|
display->pointer_grab.grab_one_pointer_release_event = display->pointer_grab.window;
|
||||||
|
|
||||||
/* We need to set this to null befor syntesizing events to make sure they get
|
/* Set first so crossing events get sent */
|
||||||
delivered to anything but the grab window */
|
|
||||||
display->pointer_grab.window = NULL;
|
display->pointer_grab.window = NULL;
|
||||||
|
|
||||||
/* Normal UNGRAB events are sent by listening for enter and leave
|
pointer_window = _gdk_windowing_window_at_pointer (display, &x, &y, &state);
|
||||||
* events on the native event window, which is then proxied
|
|
||||||
* into the virtual windows when the events are seen.
|
|
||||||
* However, there are two cases where X will not send these events:
|
|
||||||
* * When this ungrab is due to a new grab on the native window that
|
|
||||||
* is a parent of the currently grabbed virtual window
|
|
||||||
* * When there is no new grab, and the pointer is already in the
|
|
||||||
* grabbed virtual windows parent native window
|
|
||||||
* In the first case we send the right GRAB events from the grab, but
|
|
||||||
* in the second case we need to generate our own UNGRAB crossing events.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (_gdk_windowing_window_at_pointer (display, &wx, &wy) == old_native_grab_window)
|
if (pointer_window != NULL &&
|
||||||
|
(GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_ROOT ||
|
||||||
|
GDK_WINDOW_TYPE (pointer_window) == GDK_WINDOW_FOREIGN))
|
||||||
|
pointer_window = NULL;
|
||||||
|
|
||||||
|
/* We force checked what window we're in, so we need to
|
||||||
|
* update the toplevel_under_pointer info, as that won't get told of
|
||||||
|
* this change.
|
||||||
|
*/
|
||||||
|
if (display->pointer_info.toplevel_under_pointer)
|
||||||
|
g_object_unref (display->pointer_info.toplevel_under_pointer);
|
||||||
|
display->pointer_info.toplevel_under_pointer = NULL;
|
||||||
|
|
||||||
|
if (pointer_window)
|
||||||
|
{
|
||||||
|
/* Convert to toplevel */
|
||||||
|
w = (GdkWindowObject *)pointer_window;
|
||||||
|
while (w->parent->window_type != GDK_WINDOW_ROOT)
|
||||||
|
{
|
||||||
|
x += w->x;
|
||||||
|
y += w->y;
|
||||||
|
w = w->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* w is now toplevel and x,y in toplevel coords */
|
||||||
|
|
||||||
|
display->pointer_info.toplevel_under_pointer = g_object_ref (w);
|
||||||
|
|
||||||
|
/* Find child window */
|
||||||
|
pointer_window =
|
||||||
|
_gdk_window_find_descendant_at ((GdkWindow *)w,
|
||||||
|
x, y,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (pointer_window == NULL)
|
||||||
{
|
{
|
||||||
_gdk_syntesize_crossing_events (display,
|
_gdk_syntesize_crossing_events (display,
|
||||||
old_grab_window,
|
old_grab_window,
|
||||||
display->pointer_info.window_under_pointer,
|
NULL,
|
||||||
GDK_CROSSING_UNGRAB,
|
GDK_CROSSING_UNGRAB,
|
||||||
/* These may be stale... */
|
x, y, state,
|
||||||
display->pointer_info.toplevel_x,
|
time,
|
||||||
display->pointer_info.toplevel_y,
|
NULL, FALSE);
|
||||||
display->pointer_info.state,
|
|
||||||
time, TRUE, TRUE);
|
|
||||||
}
|
}
|
||||||
|
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, FALSE);
|
||||||
|
}
|
||||||
|
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, FALSE);
|
||||||
|
_gdk_syntesize_crossing_events (display,
|
||||||
|
NULL,
|
||||||
|
pointer_window,
|
||||||
|
GDK_CROSSING_UNGRAB,
|
||||||
|
x, y, state,
|
||||||
|
time,
|
||||||
|
NULL, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're now ungrabbed, update the window_under_pointer */
|
||||||
|
set_window_under_pointer (display, pointer_window);
|
||||||
|
|
||||||
if (implicit)
|
if (implicit)
|
||||||
generate_grab_broken_event (old_grab_window,
|
generate_grab_broken_event (old_grab_window,
|
||||||
|
|||||||
@ -58,13 +58,17 @@ typedef struct
|
|||||||
GdkWindow *grab_one_pointer_release_event;
|
GdkWindow *grab_one_pointer_release_event;
|
||||||
} GdkPointerGrabInfo;
|
} GdkPointerGrabInfo;
|
||||||
|
|
||||||
/* Tracks information about which window the pointer is in and
|
/* Tracks information about which window and position the pointer last was in.
|
||||||
* at what position the mouse is. This is useful when we need
|
* This is useful when we need to synthesize events later.
|
||||||
* to synthesize events later.
|
* Note that we track toplevel_under_pointer using enter/leave events,
|
||||||
|
* so in the case of a grab, either with owner_events==FALSE or with the
|
||||||
|
* pointer in no clients window the x/y coordinates may actually be outside
|
||||||
|
* the window.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
GdkWindow *window_under_pointer;
|
GdkWindow *toplevel_under_pointer; /* The toplevel window with mouse inside, tracked via native events */
|
||||||
|
GdkWindow *window_under_pointer; /* The window that last got sent a normal enter event */
|
||||||
gdouble toplevel_x, toplevel_y;
|
gdouble toplevel_x, toplevel_y;
|
||||||
guint32 state;
|
guint32 state;
|
||||||
} GdkPointerWindowInfo;
|
} GdkPointerWindowInfo;
|
||||||
|
|||||||
@ -345,7 +345,12 @@ GdkWindow* _gdk_windowing_window_get_pointer (GdkDisplay *display,
|
|||||||
GdkModifierType *mask);
|
GdkModifierType *mask);
|
||||||
GdkWindow* _gdk_windowing_window_at_pointer (GdkDisplay *display,
|
GdkWindow* _gdk_windowing_window_at_pointer (GdkDisplay *display,
|
||||||
gint *win_x,
|
gint *win_x,
|
||||||
gint *win_y);
|
gint *win_y,
|
||||||
|
GdkModifierType *mask);
|
||||||
|
void _gdk_windowing_got_event (GdkDisplay *display,
|
||||||
|
GList *event_link,
|
||||||
|
GdkEvent *event);
|
||||||
|
|
||||||
|
|
||||||
/* Return the number of bits-per-pixel for images of the specified depth. */
|
/* Return the number of bits-per-pixel for images of the specified depth. */
|
||||||
gint _gdk_windowing_get_bits_for_depth (GdkDisplay *display,
|
gint _gdk_windowing_get_bits_for_depth (GdkDisplay *display,
|
||||||
@ -521,8 +526,8 @@ void _gdk_syntesize_crossing_events (GdkDisplay *display,
|
|||||||
gint toplevel_y,
|
gint toplevel_y,
|
||||||
GdkModifierType mask,
|
GdkModifierType mask,
|
||||||
guint32 time_,
|
guint32 time_,
|
||||||
gboolean do_first,
|
GdkEvent *event_in_queue,
|
||||||
gboolean do_last);
|
gboolean before_event);
|
||||||
|
|
||||||
void _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window);
|
void _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window);
|
||||||
|
|
||||||
|
|||||||
704
gdk/gdkwindow.c
704
gdk/gdkwindow.c
@ -1159,6 +1159,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
|
|||||||
GdkWindowObject *temp_private;
|
GdkWindowObject *temp_private;
|
||||||
GdkWindow *temp_window;
|
GdkWindow *temp_window;
|
||||||
GdkScreen *screen;
|
GdkScreen *screen;
|
||||||
|
GdkDisplay *display;
|
||||||
GList *children;
|
GList *children;
|
||||||
GList *tmp;
|
GList *tmp;
|
||||||
|
|
||||||
@ -1169,11 +1170,13 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
|
|||||||
if (GDK_WINDOW_DESTROYED (window))
|
if (GDK_WINDOW_DESTROYED (window))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
display = gdk_drawable_get_display (GDK_DRAWABLE (window));
|
||||||
screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
|
screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
|
||||||
temp_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
|
temp_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
|
||||||
if (temp_window == window)
|
if (temp_window == window)
|
||||||
g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL);
|
g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL);
|
||||||
|
|
||||||
|
|
||||||
switch (GDK_WINDOW_TYPE (window))
|
switch (GDK_WINDOW_TYPE (window))
|
||||||
{
|
{
|
||||||
case GDK_WINDOW_ROOT:
|
case GDK_WINDOW_ROOT:
|
||||||
@ -1284,6 +1287,12 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
|
|||||||
gdk_window_redirect_free (private->redirect);
|
gdk_window_redirect_free (private->redirect);
|
||||||
|
|
||||||
private->redirect = NULL;
|
private->redirect = NULL;
|
||||||
|
|
||||||
|
if (display->pointer_info.toplevel_under_pointer == window)
|
||||||
|
{
|
||||||
|
g_object_unref (display->pointer_info.toplevel_under_pointer);
|
||||||
|
display->pointer_info.toplevel_under_pointer = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6615,13 +6624,9 @@ static gboolean
|
|||||||
point_in_window (GdkWindowObject *window,
|
point_in_window (GdkWindowObject *window,
|
||||||
double x, double y)
|
double x, double y)
|
||||||
{
|
{
|
||||||
int w, h;
|
|
||||||
|
|
||||||
gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
|
|
||||||
|
|
||||||
return
|
return
|
||||||
x >= 0 && x < w &&
|
x >= 0 && x < window->width &&
|
||||||
y >= 0 && y < h;
|
y >= 0 && y < window->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -6856,22 +6861,22 @@ is_motion_type (GdkEventType type)
|
|||||||
type == GDK_LEAVE_NOTIFY;
|
type == GDK_LEAVE_NOTIFY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdkWindow *
|
static GdkWindowObject *
|
||||||
find_common_ancestor (GdkWindow *win1,
|
find_common_ancestor (GdkWindowObject *win1,
|
||||||
GdkWindow *win2)
|
GdkWindowObject *win2)
|
||||||
{
|
{
|
||||||
GdkWindowObject *tmp;
|
GdkWindowObject *tmp;
|
||||||
GList *path1 = NULL, *path2 = NULL;
|
GList *path1 = NULL, *path2 = NULL;
|
||||||
GList *list1, *list2;
|
GList *list1, *list2;
|
||||||
|
|
||||||
tmp = GDK_WINDOW_OBJECT (win1);
|
tmp = win1;
|
||||||
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
|
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
|
||||||
{
|
{
|
||||||
path1 = g_list_prepend (path1, tmp);
|
path1 = g_list_prepend (path1, tmp);
|
||||||
tmp = tmp->parent;
|
tmp = tmp->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = GDK_WINDOW_OBJECT (win2);
|
tmp = win2;
|
||||||
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
|
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
|
||||||
{
|
{
|
||||||
path2 = g_list_prepend (path2, tmp);
|
path2 = g_list_prepend (path2, tmp);
|
||||||
@ -6890,7 +6895,7 @@ find_common_ancestor (GdkWindow *win1,
|
|||||||
g_list_free (path1);
|
g_list_free (path1);
|
||||||
g_list_free (path2);
|
g_list_free (path2);
|
||||||
|
|
||||||
return GDK_WINDOW (tmp);
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
GdkEvent *
|
GdkEvent *
|
||||||
@ -6995,6 +7000,54 @@ _gdk_make_event (GdkWindow *window,
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_crossing_event (GdkDisplay *display,
|
||||||
|
GdkWindowObject *toplevel,
|
||||||
|
GdkWindowObject *window,
|
||||||
|
GdkEventType type,
|
||||||
|
GdkCrossingMode mode,
|
||||||
|
GdkNotifyType notify_type,
|
||||||
|
GdkWindow *subwindow,
|
||||||
|
gint toplevel_x,
|
||||||
|
gint toplevel_y,
|
||||||
|
GdkModifierType mask,
|
||||||
|
guint32 time_,
|
||||||
|
GdkEvent *event_in_queue,
|
||||||
|
gboolean before_event)
|
||||||
|
{
|
||||||
|
GdkEvent *event;
|
||||||
|
guint32 event_mask;
|
||||||
|
|
||||||
|
if (display->pointer_grab.window != NULL &&
|
||||||
|
!display->pointer_grab.owner_events &&
|
||||||
|
(GdkWindow *)window != display->pointer_grab.window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (type == GDK_LEAVE_NOTIFY)
|
||||||
|
event_mask = GDK_LEAVE_NOTIFY_MASK;
|
||||||
|
else
|
||||||
|
event_mask = GDK_ENTER_NOTIFY_MASK;
|
||||||
|
|
||||||
|
if (window->event_mask & event_mask)
|
||||||
|
{
|
||||||
|
event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, before_event);
|
||||||
|
event->crossing.time = time_;
|
||||||
|
event->crossing.subwindow = subwindow;
|
||||||
|
if (subwindow)
|
||||||
|
g_object_ref (subwindow);
|
||||||
|
convert_toplevel_coords_to_window ((GdkWindow *)window,
|
||||||
|
toplevel_x, toplevel_y,
|
||||||
|
&event->crossing.x, &event->crossing.y);
|
||||||
|
event->crossing.x_root = toplevel_x + toplevel->x;
|
||||||
|
event->crossing.y_root = toplevel_y + toplevel->y;
|
||||||
|
event->crossing.mode = mode;
|
||||||
|
event->crossing.detail = notify_type;
|
||||||
|
event->crossing.focus = FALSE;
|
||||||
|
event->crossing.state = mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The coordinates are in the toplevel window that src/dest are in.
|
/* The coordinates are in the toplevel window that src/dest are in.
|
||||||
* src and dest are always (if != NULL) in the same toplevel, as
|
* src and dest are always (if != NULL) in the same toplevel, as
|
||||||
* we get a leave-notify and set the window_under_pointer to null
|
* we get a leave-notify and set the window_under_pointer to null
|
||||||
@ -7009,159 +7062,134 @@ _gdk_syntesize_crossing_events (GdkDisplay *display,
|
|||||||
gint toplevel_y,
|
gint toplevel_y,
|
||||||
GdkModifierType mask,
|
GdkModifierType mask,
|
||||||
guint32 time_,
|
guint32 time_,
|
||||||
gboolean do_first,
|
GdkEvent *event_in_queue,
|
||||||
gboolean do_last)
|
gboolean before_event)
|
||||||
{
|
{
|
||||||
GdkWindow *c;
|
GdkWindowObject *c;
|
||||||
GdkWindow *win, *last, *next;
|
GdkWindowObject *win, *last, *next;
|
||||||
GdkEvent *event;
|
|
||||||
GList *path, *list;
|
GList *path, *list;
|
||||||
gboolean non_linear;
|
gboolean non_linear;
|
||||||
GdkWindow *a;
|
GdkWindowObject *a;
|
||||||
GdkWindow *b;
|
GdkWindowObject *b;
|
||||||
GdkWindow *event_win;
|
|
||||||
GdkWindowObject *toplevel;
|
GdkWindowObject *toplevel;
|
||||||
|
GdkNotifyType notify_type;
|
||||||
|
|
||||||
/* TODO: Don't send events to toplevel, as we get those from the windowing system */
|
/* TODO: Don't send events to toplevel, as we get those from the windowing system */
|
||||||
|
|
||||||
a = src;
|
a = (GdkWindowObject *)src;
|
||||||
b = dest;
|
b = (GdkWindowObject *)dest;
|
||||||
if (a == b)
|
if (a == b)
|
||||||
return; /* No crossings generated between src and dest */
|
return; /* No crossings generated between src and dest */
|
||||||
|
|
||||||
c = find_common_ancestor (a, b);
|
c = find_common_ancestor (a, b);
|
||||||
|
|
||||||
non_linear = (c != a) && (c != b);
|
non_linear = (c != a) && (c != b);
|
||||||
|
|
||||||
if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
|
if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
|
||||||
{
|
{
|
||||||
toplevel = (GdkWindowObject *)gdk_window_get_toplevel (a);
|
toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)a);
|
||||||
|
|
||||||
/* Traverse up from a to (excluding) c sending leave events */
|
/* Traverse up from a to (excluding) c sending leave events */
|
||||||
|
if (non_linear)
|
||||||
event_win = get_target_window_for_pointer_event (display, a, GDK_LEAVE_NOTIFY, mask);
|
notify_type = GDK_NOTIFY_NONLINEAR;
|
||||||
if (do_first && event_win)
|
else if (c == a)
|
||||||
{
|
notify_type = GDK_NOTIFY_INFERIOR;
|
||||||
event = _gdk_make_event (event_win, GDK_LEAVE_NOTIFY, NULL, FALSE);
|
else
|
||||||
event->crossing.time = time_;
|
notify_type = GDK_NOTIFY_ANCESTOR;
|
||||||
event->crossing.subwindow = NULL;
|
send_crossing_event (display, toplevel,
|
||||||
convert_toplevel_coords_to_window (event_win,
|
a, GDK_LEAVE_NOTIFY,
|
||||||
toplevel_x, toplevel_y,
|
mode,
|
||||||
&event->crossing.x, &event->crossing.y);
|
notify_type,
|
||||||
event->crossing.x_root = toplevel_x + toplevel->x;
|
NULL,
|
||||||
event->crossing.y_root = toplevel_y + toplevel->y;
|
toplevel_x, toplevel_y,
|
||||||
event->crossing.mode = mode;
|
mask, time_,
|
||||||
if (non_linear)
|
event_in_queue, before_event);
|
||||||
event->crossing.detail = GDK_NOTIFY_NONLINEAR;
|
|
||||||
else if (c == a)
|
|
||||||
event->crossing.detail = GDK_NOTIFY_INFERIOR;
|
|
||||||
else
|
|
||||||
event->crossing.detail = GDK_NOTIFY_ANCESTOR;
|
|
||||||
event->crossing.focus = FALSE;
|
|
||||||
event->crossing.state = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c != a)
|
if (c != a)
|
||||||
{
|
{
|
||||||
|
if (non_linear)
|
||||||
|
notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
|
||||||
|
else
|
||||||
|
notify_type = GDK_NOTIFY_VIRTUAL;
|
||||||
|
|
||||||
last = a;
|
last = a;
|
||||||
win = GDK_WINDOW (GDK_WINDOW_OBJECT (a)->parent);
|
win = a->parent;
|
||||||
while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
|
while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
|
||||||
{
|
{
|
||||||
event_win = get_target_window_for_pointer_event (display, win, GDK_LEAVE_NOTIFY, mask);
|
send_crossing_event (display, toplevel,
|
||||||
if (event_win)
|
win, GDK_LEAVE_NOTIFY,
|
||||||
{
|
mode,
|
||||||
event = _gdk_make_event (event_win, GDK_LEAVE_NOTIFY, NULL, FALSE);
|
notify_type,
|
||||||
event->crossing.time = time_;
|
(GdkWindow *)last,
|
||||||
event->crossing.subwindow = g_object_ref (last);
|
toplevel_x, toplevel_y,
|
||||||
convert_toplevel_coords_to_window (event_win,
|
mask, time_,
|
||||||
toplevel_x, toplevel_y,
|
event_in_queue, before_event);
|
||||||
&event->crossing.x, &event->crossing.y);
|
|
||||||
event->crossing.x_root = toplevel_x + toplevel->x;
|
|
||||||
event->crossing.y_root = toplevel_y + toplevel->y;
|
|
||||||
event->crossing.mode = mode;
|
|
||||||
if (non_linear)
|
|
||||||
event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
|
|
||||||
else
|
|
||||||
event->crossing.detail = GDK_NOTIFY_VIRTUAL;
|
|
||||||
event->crossing.focus = FALSE;
|
|
||||||
event->crossing.state = mask;
|
|
||||||
}
|
|
||||||
last = win;
|
last = win;
|
||||||
win = GDK_WINDOW (GDK_WINDOW_OBJECT (win)->parent);
|
win = win->parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b) /* Might not be a dest, e.g. if we're moving out of the window */
|
if (b) /* Might not be a dest, e.g. if we're moving out of the window */
|
||||||
{
|
{
|
||||||
toplevel = (GdkWindowObject *)gdk_window_get_toplevel (b);
|
toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)b);
|
||||||
|
|
||||||
/* Traverse down from c to b */
|
/* Traverse down from c to b */
|
||||||
if (c != b)
|
if (c != b)
|
||||||
{
|
{
|
||||||
path = NULL;
|
path = NULL;
|
||||||
win = GDK_WINDOW (GDK_WINDOW_OBJECT (b)->parent);
|
win = b->parent;
|
||||||
while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
|
while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
|
||||||
{
|
{
|
||||||
path = g_list_prepend (path, win);
|
path = g_list_prepend (path, win);
|
||||||
win = GDK_WINDOW( GDK_WINDOW_OBJECT (win)->parent);
|
win = win->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (non_linear)
|
||||||
|
notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
|
||||||
|
else
|
||||||
|
notify_type = GDK_NOTIFY_VIRTUAL;
|
||||||
|
|
||||||
list = path;
|
list = path;
|
||||||
while (list)
|
while (list)
|
||||||
{
|
{
|
||||||
win = (GdkWindow *)list->data;
|
win = (GdkWindowObject *)list->data;
|
||||||
list = g_list_next (list);
|
list = g_list_next (list);
|
||||||
if (list)
|
if (list)
|
||||||
next = (GdkWindow *)list->data;
|
next = (GdkWindowObject *)list->data;
|
||||||
else
|
else
|
||||||
next = b;
|
next = b;
|
||||||
|
|
||||||
event_win = get_target_window_for_pointer_event (display, win, GDK_ENTER_NOTIFY, mask);
|
send_crossing_event (display, toplevel,
|
||||||
if (event_win)
|
win, GDK_ENTER_NOTIFY,
|
||||||
{
|
mode,
|
||||||
event = _gdk_make_event (event_win, GDK_ENTER_NOTIFY, NULL, FALSE);
|
notify_type,
|
||||||
event->crossing.time = time_;
|
(GdkWindow *)next,
|
||||||
event->crossing.subwindow = g_object_ref (next);
|
toplevel_x, toplevel_y,
|
||||||
convert_toplevel_coords_to_window (event_win,
|
mask, time_,
|
||||||
toplevel_x, toplevel_y,
|
event_in_queue, before_event);
|
||||||
&event->crossing.x, &event->crossing.y);
|
|
||||||
event->crossing.x_root = toplevel_x + toplevel->x;
|
|
||||||
event->crossing.y_root = toplevel_y + toplevel->y;
|
|
||||||
event->crossing.mode = mode;
|
|
||||||
if (non_linear)
|
|
||||||
event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
|
|
||||||
else
|
|
||||||
event->crossing.detail = GDK_NOTIFY_VIRTUAL;
|
|
||||||
event->crossing.focus = FALSE;
|
|
||||||
event->crossing.state = mask;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g_list_free (path);
|
g_list_free (path);
|
||||||
}
|
}
|
||||||
|
|
||||||
event_win = get_target_window_for_pointer_event (display, b, GDK_ENTER_NOTIFY, mask);
|
|
||||||
if (do_last && event_win)
|
|
||||||
{
|
|
||||||
event = _gdk_make_event (event_win, GDK_ENTER_NOTIFY, NULL, FALSE);
|
|
||||||
event->crossing.time = time_;
|
|
||||||
event->crossing.subwindow = NULL;
|
|
||||||
convert_toplevel_coords_to_window (event_win,
|
|
||||||
toplevel_x, toplevel_y,
|
|
||||||
&event->crossing.x, &event->crossing.y);
|
|
||||||
event->crossing.x_root = toplevel_x + toplevel->x;
|
|
||||||
event->crossing.y_root = toplevel_y + toplevel->y;
|
|
||||||
event->crossing.mode = mode;
|
|
||||||
if (non_linear)
|
|
||||||
event->crossing.detail = GDK_NOTIFY_NONLINEAR;
|
|
||||||
else if (c == a)
|
|
||||||
event->crossing.detail = GDK_NOTIFY_ANCESTOR;
|
|
||||||
else
|
|
||||||
event->crossing.detail = GDK_NOTIFY_INFERIOR;
|
|
||||||
event->crossing.focus = FALSE;
|
|
||||||
event->crossing.state = mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (non_linear)
|
||||||
|
notify_type = GDK_NOTIFY_NONLINEAR;
|
||||||
|
else if (c == a)
|
||||||
|
notify_type = GDK_NOTIFY_ANCESTOR;
|
||||||
|
else
|
||||||
|
notify_type = GDK_NOTIFY_INFERIOR;
|
||||||
|
|
||||||
|
send_crossing_event (display, toplevel,
|
||||||
|
b, GDK_ENTER_NOTIFY,
|
||||||
|
mode,
|
||||||
|
notify_type,
|
||||||
|
NULL,
|
||||||
|
toplevel_x, toplevel_y,
|
||||||
|
mask, time_,
|
||||||
|
event_in_queue, before_event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdkWindow *
|
static GdkWindow *
|
||||||
@ -7176,146 +7204,182 @@ get_toplevel (GdkWindow *w)
|
|||||||
return GDK_WINDOW (private);
|
return GDK_WINDOW (private);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the window inside the event window with the pointer in it
|
||||||
|
* at the specified coordinates, or NULL if its not in any child of
|
||||||
|
* the toplevel. It also takes into account !owner_events grabs.
|
||||||
|
*/
|
||||||
|
static GdkWindow *
|
||||||
|
get_pointer_window (GdkDisplay *display,
|
||||||
|
GdkWindow *event_window,
|
||||||
|
gdouble toplevel_x,
|
||||||
|
gdouble toplevel_y)
|
||||||
|
{
|
||||||
|
GdkWindow *pointer_window;
|
||||||
|
|
||||||
|
if (event_window == display->pointer_info.toplevel_under_pointer)
|
||||||
|
pointer_window =
|
||||||
|
_gdk_window_find_descendant_at (event_window,
|
||||||
|
toplevel_x, toplevel_y,
|
||||||
|
NULL, NULL);
|
||||||
|
else
|
||||||
|
pointer_window = NULL;
|
||||||
|
|
||||||
|
if (display->pointer_grab.window != NULL &&
|
||||||
|
!display->pointer_grab.owner_events &&
|
||||||
|
pointer_window != display->pointer_grab.window)
|
||||||
|
pointer_window = NULL;
|
||||||
|
|
||||||
|
return pointer_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_window_under_pointer (GdkDisplay *display,
|
||||||
|
GdkWindow *window)
|
||||||
|
{
|
||||||
|
if (display->pointer_info.window_under_pointer)
|
||||||
|
g_object_unref (display->pointer_info.window_under_pointer);
|
||||||
|
display->pointer_info.window_under_pointer = window;
|
||||||
|
if (window)
|
||||||
|
g_object_ref (window);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
|
_gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
|
||||||
{
|
{
|
||||||
GdkDisplay *display;
|
GdkDisplay *display;
|
||||||
GdkWindow *changed_toplevel;
|
GdkWindow *changed_toplevel;
|
||||||
GdkWindow *pointer_toplevel;
|
GdkWindow *pointer_toplevel, *grab_toplevel;
|
||||||
GdkWindow *new_window_under_pointer;
|
GdkWindow *new_window_under_pointer;
|
||||||
|
|
||||||
changed_toplevel = get_toplevel (changed_window);
|
changed_toplevel = get_toplevel (changed_window);
|
||||||
|
|
||||||
display = gdk_drawable_get_display (changed_window);
|
display = gdk_drawable_get_display (changed_window);
|
||||||
if (display->pointer_info.window_under_pointer)
|
if (changed_toplevel == display->pointer_info.toplevel_under_pointer)
|
||||||
{
|
{
|
||||||
pointer_toplevel = get_toplevel (display->pointer_info.window_under_pointer);
|
new_window_under_pointer =
|
||||||
|
get_pointer_window (display, changed_toplevel,
|
||||||
if (pointer_toplevel == changed_toplevel)
|
display->pointer_info.toplevel_x,
|
||||||
|
display->pointer_info.toplevel_y);
|
||||||
|
if (new_window_under_pointer !=
|
||||||
|
display->pointer_info.window_under_pointer)
|
||||||
{
|
{
|
||||||
new_window_under_pointer =
|
_gdk_syntesize_crossing_events (display,
|
||||||
_gdk_window_find_descendant_at (pointer_toplevel,
|
display->pointer_info.window_under_pointer,
|
||||||
display->pointer_info.toplevel_x,
|
new_window_under_pointer,
|
||||||
display->pointer_info.toplevel_y,
|
GDK_CROSSING_NORMAL,
|
||||||
NULL, NULL);
|
display->pointer_info.toplevel_x,
|
||||||
if (new_window_under_pointer !=
|
display->pointer_info.toplevel_y,
|
||||||
display->pointer_info.window_under_pointer)
|
display->pointer_info.state,
|
||||||
{
|
GDK_CURRENT_TIME,
|
||||||
_gdk_syntesize_crossing_events (display,
|
NULL, FALSE);
|
||||||
display->pointer_info.window_under_pointer,
|
set_window_under_pointer (display, new_window_under_pointer);
|
||||||
new_window_under_pointer,
|
|
||||||
GDK_CROSSING_NORMAL,
|
|
||||||
display->pointer_info.toplevel_x,
|
|
||||||
display->pointer_info.toplevel_y,
|
|
||||||
display->pointer_info.state,
|
|
||||||
GDK_CURRENT_TIME,
|
|
||||||
TRUE, TRUE);
|
|
||||||
|
|
||||||
if (display->pointer_info.window_under_pointer)
|
|
||||||
g_object_unref (display->pointer_info.window_under_pointer);
|
|
||||||
display->pointer_info.window_under_pointer = NULL;
|
|
||||||
if (new_window_under_pointer)
|
|
||||||
display->pointer_info.window_under_pointer = g_object_ref (new_window_under_pointer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Don't use for crossing events */
|
||||||
|
static GdkWindow *
|
||||||
|
get_event_window (GdkDisplay *display,
|
||||||
|
GdkWindow *pointer_window,
|
||||||
|
GdkEventType type,
|
||||||
|
GdkModifierType mask)
|
||||||
|
{
|
||||||
|
guint evmask;
|
||||||
|
GdkWindow *grab_window;
|
||||||
|
GdkWindowObject *w;
|
||||||
|
|
||||||
|
if ((display->pointer_grab.window != NULL && !display->pointer_grab.owner_events) ||
|
||||||
|
(type == GDK_BUTTON_RELEASE && display->pointer_grab.grab_one_pointer_release_event))
|
||||||
|
{
|
||||||
|
evmask = display->pointer_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;
|
||||||
|
|
||||||
|
if (evmask & type_masks[type])
|
||||||
|
return grab_window;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
w = (GdkWindowObject *)pointer_window;
|
||||||
|
while (w != NULL)
|
||||||
|
{
|
||||||
|
evmask = w->event_mask;
|
||||||
|
evmask = update_evmask_for_button_motion (evmask, mask);
|
||||||
|
|
||||||
|
if (evmask & type_masks[type])
|
||||||
|
return (GdkWindow *)w;
|
||||||
|
|
||||||
|
w = w->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display->pointer_grab.window != NULL &&
|
||||||
|
display->pointer_grab.owner_events)
|
||||||
|
{
|
||||||
|
evmask = display->pointer_grab.event_mask;
|
||||||
|
evmask = update_evmask_for_button_motion (evmask, mask);
|
||||||
|
|
||||||
|
if (evmask & type_masks[type])
|
||||||
|
return display->pointer_grab.window;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
proxy_pointer_event (GdkDisplay *display,
|
proxy_pointer_event (GdkDisplay *display,
|
||||||
GdkWindow *pointer_window,
|
|
||||||
gdouble toplevel_x,
|
|
||||||
gdouble toplevel_y,
|
|
||||||
GdkEvent *source_event)
|
GdkEvent *source_event)
|
||||||
{
|
{
|
||||||
GdkWindow *event_window;
|
GdkWindow *toplevel_window;
|
||||||
GdkWindow *event_win, *cursor_window;
|
GdkWindow *pointer_window;
|
||||||
gboolean crossing_event;
|
GdkWindow *cursor_window;
|
||||||
gboolean sent_motion;
|
gboolean sent_motion;
|
||||||
GdkEvent *event;
|
GdkEvent *event;
|
||||||
guint state;
|
guint state;
|
||||||
|
gdouble toplevel_x, toplevel_y;
|
||||||
guint32 time_;
|
guint32 time_;
|
||||||
|
|
||||||
event_window = source_event->any.window;
|
toplevel_window = source_event->any.window;
|
||||||
|
gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
|
||||||
gdk_event_get_state (source_event, &state);
|
gdk_event_get_state (source_event, &state);
|
||||||
time_ = gdk_event_get_time (source_event);
|
time_ = gdk_event_get_time (source_event);
|
||||||
|
|
||||||
crossing_event =
|
pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
|
||||||
source_event->type == GDK_ENTER_NOTIFY ||
|
if (display->pointer_info.window_under_pointer != pointer_window)
|
||||||
source_event->type == GDK_LEAVE_NOTIFY;
|
|
||||||
|
|
||||||
if (crossing_event)
|
|
||||||
{
|
{
|
||||||
GdkEventCrossing *crossing = &source_event->crossing;
|
/* Either a toplevel crossing notify that ended up inside a child window,
|
||||||
|
or a motion notify that got into another child window */
|
||||||
|
/* Different than last time, send crossing events */
|
||||||
|
|
||||||
if (crossing->mode == GDK_CROSSING_GRAB)
|
_gdk_syntesize_crossing_events (display,
|
||||||
{
|
display->pointer_info.window_under_pointer,
|
||||||
if (crossing->type == GDK_LEAVE_NOTIFY &&
|
pointer_window,
|
||||||
display->pointer_info.window_under_pointer != NULL)
|
GDK_CROSSING_NORMAL,
|
||||||
{
|
toplevel_x, toplevel_y,
|
||||||
_gdk_syntesize_crossing_events (display,
|
state, time_,
|
||||||
display->pointer_info.window_under_pointer,
|
source_event, source_event->type == GDK_LEAVE_NOTIFY);
|
||||||
event_window,
|
|
||||||
GDK_CROSSING_GRAB,
|
|
||||||
toplevel_x, toplevel_y, state, time_,
|
|
||||||
TRUE, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crossing->type == GDK_ENTER_NOTIFY &&
|
set_window_under_pointer (display, pointer_window);
|
||||||
display->pointer_grab.window != NULL)
|
|
||||||
{
|
|
||||||
_gdk_syntesize_crossing_events (display,
|
|
||||||
event_window,
|
|
||||||
display->pointer_grab.window,
|
|
||||||
GDK_CROSSING_GRAB,
|
|
||||||
toplevel_x, toplevel_y, state, time_,
|
|
||||||
FALSE, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crossing->mode == GDK_CROSSING_UNGRAB)
|
|
||||||
{
|
|
||||||
if (crossing->type == GDK_LEAVE_NOTIFY &&
|
|
||||||
display->pointer_grab.window != NULL)
|
|
||||||
{
|
|
||||||
_gdk_syntesize_crossing_events (display,
|
|
||||||
display->pointer_grab.window,
|
|
||||||
event_window,
|
|
||||||
GDK_CROSSING_UNGRAB,
|
|
||||||
toplevel_x, toplevel_y, state, time_,
|
|
||||||
TRUE, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crossing->type == GDK_ENTER_NOTIFY &&
|
|
||||||
display->pointer_info.window_under_pointer != NULL)
|
|
||||||
{
|
|
||||||
_gdk_syntesize_crossing_events (display,
|
|
||||||
event_window,
|
|
||||||
display->pointer_info.window_under_pointer,
|
|
||||||
GDK_CROSSING_UNGRAB,
|
|
||||||
toplevel_x, toplevel_y, state, time_,
|
|
||||||
FALSE, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (source_event->type == GDK_MOTION_NOTIFY)
|
||||||
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;
|
|
||||||
|
|
||||||
/* TODO: set cursor from cursor_window, or grab cursor */
|
|
||||||
|
|
||||||
sent_motion = FALSE;
|
|
||||||
if (!crossing_event &&
|
|
||||||
(display->pointer_info.window_under_pointer == pointer_window ||
|
|
||||||
(display->pointer_grab.window != NULL &&
|
|
||||||
!display->pointer_grab.owner_events)))
|
|
||||||
{
|
{
|
||||||
/* send motion events */
|
GdkWindow *event_win;
|
||||||
event_win = get_target_window_for_pointer_event (display, pointer_window, GDK_MOTION_NOTIFY, state);
|
|
||||||
|
event_win = get_event_window (display,
|
||||||
|
pointer_window,
|
||||||
|
source_event->type,
|
||||||
|
state);
|
||||||
|
|
||||||
if (event_win)
|
if (event_win)
|
||||||
{
|
{
|
||||||
sent_motion = TRUE;
|
sent_motion = TRUE;
|
||||||
@ -7334,43 +7398,52 @@ proxy_pointer_event (GdkDisplay *display,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_gdk_syntesize_crossing_events (display,
|
/* TODO: set cursor from cursor_window, or grab cursor */
|
||||||
display->pointer_info.window_under_pointer,
|
cursor_window = pointer_window;
|
||||||
pointer_window,
|
if (display->pointer_grab.window &&
|
||||||
GDK_CROSSING_NORMAL,
|
(pointer_window == NULL ||
|
||||||
toplevel_x, toplevel_y,
|
!is_parent_of (display->pointer_grab.window, pointer_window)))
|
||||||
state, time_,
|
cursor_window = display->pointer_grab.window;
|
||||||
TRUE, TRUE);
|
/* Actually, this should probably happen in synthesize crossing so it works with geometry changes */
|
||||||
|
|
||||||
/* unlink move event from parent if we sent a motion event */
|
|
||||||
return source_event->type == GDK_MOTION_NOTIFY && sent_motion;
|
/* unlink all move events from queue.
|
||||||
|
We handle our own, including our emulated masks. */
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
proxy_button_event (GdkWindow *pointer_window,
|
proxy_button_event (GdkEvent *source_event)
|
||||||
gdouble toplevel_x,
|
|
||||||
gdouble toplevel_y,
|
|
||||||
GdkEvent *source_event)
|
|
||||||
{
|
{
|
||||||
|
GdkWindow *toplevel_window;
|
||||||
GdkWindow *event_win;
|
GdkWindow *event_win;
|
||||||
|
GdkWindow *pointer_window;
|
||||||
GdkEvent *event;
|
GdkEvent *event;
|
||||||
guint state;
|
guint state;
|
||||||
guint32 time_;
|
guint32 time_;
|
||||||
GdkEventType type;
|
GdkEventType type;
|
||||||
|
gdouble toplevel_x, toplevel_y;
|
||||||
GdkDisplay *display;
|
GdkDisplay *display;
|
||||||
|
|
||||||
type = source_event->any.type;
|
type = source_event->any.type;
|
||||||
|
toplevel_window = source_event->any.window;
|
||||||
|
gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
|
||||||
gdk_event_get_state (source_event, &state);
|
gdk_event_get_state (source_event, &state);
|
||||||
time_ = gdk_event_get_time (source_event);
|
time_ = gdk_event_get_time (source_event);
|
||||||
display = gdk_drawable_get_display (source_event->any.window);
|
display = gdk_drawable_get_display (source_event->any.window);
|
||||||
|
|
||||||
if ((type == GDK_BUTTON_PRESS || type == GDK_SCROLL) &&
|
if ((type == GDK_BUTTON_PRESS || type == GDK_SCROLL) &&
|
||||||
pointer_window != NULL &&
|
|
||||||
display->pointer_grab.window == source_event->any.window &&
|
display->pointer_grab.window == source_event->any.window &&
|
||||||
display->pointer_grab.implicit &&
|
display->pointer_grab.implicit &&
|
||||||
!display->pointer_grab.converted_implicit)
|
!display->pointer_grab.converted_implicit)
|
||||||
{
|
{
|
||||||
if (pointer_window != source_event->any.window)
|
pointer_window =
|
||||||
|
_gdk_window_find_descendant_at (toplevel_window,
|
||||||
|
toplevel_x, toplevel_y,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
|
if (pointer_window != NULL &&
|
||||||
|
pointer_window != source_event->any.window)
|
||||||
_gdk_display_set_has_pointer_grab (display,
|
_gdk_display_set_has_pointer_grab (display,
|
||||||
pointer_window,
|
pointer_window,
|
||||||
display->pointer_grab.native_window,
|
display->pointer_grab.native_window,
|
||||||
@ -7382,57 +7455,51 @@ proxy_button_event (GdkWindow *pointer_window,
|
|||||||
display->pointer_grab.converted_implicit = TRUE;
|
display->pointer_grab.converted_implicit = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
event_win = get_target_window_for_pointer_event (display,
|
pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
|
||||||
pointer_window,
|
|
||||||
type,
|
event_win = get_event_window (display,
|
||||||
state);
|
pointer_window,
|
||||||
|
type,
|
||||||
|
state);
|
||||||
|
|
||||||
if (event_win == NULL)
|
if (event_win == NULL)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (event_win != source_event->any.window)
|
event = _gdk_make_event (event_win, type, source_event, FALSE);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
event = _gdk_make_event (event_win, type, source_event, FALSE);
|
case GDK_BUTTON_PRESS:
|
||||||
|
case GDK_BUTTON_RELEASE:
|
||||||
|
event->button.button = source_event->button.button;
|
||||||
|
convert_toplevel_coords_to_window (event_win,
|
||||||
|
toplevel_x, toplevel_y,
|
||||||
|
&event->button.x, &event->button.y);
|
||||||
|
event->button.x_root = source_event->button.x_root;
|
||||||
|
event->button.y_root = source_event->button.y_root;
|
||||||
|
event->button.state = state;
|
||||||
|
event->button.device = source_event->button.device;
|
||||||
|
|
||||||
switch (type)
|
if (type == GDK_BUTTON_PRESS)
|
||||||
{
|
_gdk_event_button_generate (display, event);
|
||||||
case GDK_BUTTON_PRESS:
|
return TRUE;
|
||||||
case GDK_BUTTON_RELEASE:
|
|
||||||
event->button.button = source_event->button.button;
|
|
||||||
convert_toplevel_coords_to_window (event_win,
|
|
||||||
toplevel_x, toplevel_y,
|
|
||||||
&event->button.x, &event->button.y);
|
|
||||||
event->button.x_root = source_event->button.x_root;
|
|
||||||
event->button.y_root = source_event->button.y_root;
|
|
||||||
event->button.state = state;
|
|
||||||
event->button.device = source_event->button.device;
|
|
||||||
|
|
||||||
if (type == GDK_BUTTON_PRESS)
|
case GDK_SCROLL:
|
||||||
_gdk_event_button_generate (display, event);
|
event->scroll.direction = source_event->scroll.direction;
|
||||||
return TRUE;
|
convert_toplevel_coords_to_window (event_win,
|
||||||
|
toplevel_x, toplevel_y,
|
||||||
|
&event->scroll.x, &event->scroll.y);
|
||||||
|
event->scroll.x_root = source_event->scroll.x_root;
|
||||||
|
event->scroll.y_root = source_event->scroll.y_root;
|
||||||
|
event->scroll.state = state;
|
||||||
|
event->scroll.device = source_event->scroll.device;
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
case GDK_SCROLL:
|
default:
|
||||||
event->scroll.direction = source_event->scroll.direction;
|
|
||||||
convert_toplevel_coords_to_window (event_win,
|
|
||||||
toplevel_x, toplevel_y,
|
|
||||||
&event->scroll.x, &event->scroll.y);
|
|
||||||
event->scroll.x_root = source_event->scroll.x_root;
|
|
||||||
event->scroll.y_root = source_event->scroll.y_root;
|
|
||||||
event->scroll.state = state;
|
|
||||||
event->scroll.device = source_event->scroll.device;
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Same window as original window, keep the event */
|
|
||||||
if (source_event->type == GDK_BUTTON_PRESS)
|
|
||||||
_gdk_event_button_generate (display, source_event);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TRUE; /* Always unlink original, we want to obey the emulated event mask */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -7441,9 +7508,8 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
|||||||
GdkEvent *event)
|
GdkEvent *event)
|
||||||
{
|
{
|
||||||
GdkWindow *event_window;
|
GdkWindow *event_window;
|
||||||
GdkWindow *pointer_window;
|
|
||||||
GdkWindowObject *event_private;
|
GdkWindowObject *event_private;
|
||||||
gdouble x, y, child_x, child_y;
|
gdouble x, y;
|
||||||
gboolean unlink_event;
|
gboolean unlink_event;
|
||||||
|
|
||||||
event_window = event->any.window;
|
event_window = event->any.window;
|
||||||
@ -7466,40 +7532,78 @@ _gdk_windowing_got_event (GdkDisplay *display,
|
|||||||
event_private->window_type);
|
event_private->window_type);
|
||||||
|
|
||||||
/* We should only get these events on toplevel windows */
|
/* We should only get these events on toplevel windows */
|
||||||
g_warning ("got unexpected event of type %s on non-toplevel window (type %s)",
|
g_warning ("got unexpected event of type %s on non-toplevel window (gtype %s, type %d)",
|
||||||
event_type_value->value_name,
|
event_type_value->value_name,
|
||||||
window_type_value->value_name);
|
window_type_value->value_name,
|
||||||
|
GDK_WINDOW_TYPE (event_window));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gdk_event_get_coords (event, &x, &y);
|
if ((event->type == GDK_ENTER_NOTIFY ||
|
||||||
pointer_window = _gdk_window_find_descendant_at (event_window, x, y,
|
event->type == GDK_LEAVE_NOTIFY) &&
|
||||||
&child_x,
|
(event->crossing.mode == GDK_CROSSING_GRAB ||
|
||||||
&child_y);
|
event->crossing.mode == GDK_CROSSING_UNGRAB))
|
||||||
unlink_event = FALSE;
|
{
|
||||||
if (is_motion_type (event->type))
|
/* We synthesize all crossing events due to grabs are synthesized,
|
||||||
unlink_event = proxy_pointer_event (display,
|
* so we ignore the native ones. This is partly to get easier non-X
|
||||||
pointer_window,
|
* portability, and because of problems with race conditions due to
|
||||||
x, y,
|
* the cached state in the client and the real state in the xserver
|
||||||
event);
|
* when grabbing.
|
||||||
else if (is_button_type (event->type))
|
*/
|
||||||
unlink_event = proxy_button_event (pointer_window, x, y,
|
|
||||||
event);
|
/* Some grab in another window (by perhaps another client) did a grab.
|
||||||
|
* The pointer is still in this window, but we won't get told if it
|
||||||
|
* moves out, so NULL this now and set it back to the right value at
|
||||||
|
* ungrab time.
|
||||||
|
*/
|
||||||
|
if (event->type == GDK_LEAVE_NOTIFY &&
|
||||||
|
event->crossing.mode == GDK_CROSSING_GRAB)
|
||||||
|
{
|
||||||
|
g_assert (display->pointer_info.toplevel_under_pointer == event_window);
|
||||||
|
g_object_unref (display->pointer_info.toplevel_under_pointer);
|
||||||
|
display->pointer_info.toplevel_under_pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We ended up in this window after some (perhaps other clients)
|
||||||
|
grab, so update the toplevel_under_window state */
|
||||||
|
if (event->type == GDK_ENTER_NOTIFY &&
|
||||||
|
event->crossing.mode == GDK_CROSSING_UNGRAB)
|
||||||
|
{
|
||||||
|
if (display->pointer_info.toplevel_under_pointer)
|
||||||
|
g_object_unref (display->pointer_info.toplevel_under_pointer);
|
||||||
|
display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Store last pointer window and position/state */
|
/* Store last pointer window and position/state */
|
||||||
|
if (event->type == GDK_ENTER_NOTIFY &&
|
||||||
|
event->crossing.detail != GDK_NOTIFY_INFERIOR)
|
||||||
|
{
|
||||||
|
g_assert (display->pointer_info.toplevel_under_pointer == NULL);
|
||||||
|
display->pointer_info.toplevel_under_pointer = g_object_ref (event_window);
|
||||||
|
}
|
||||||
|
else if (event->type == GDK_LEAVE_NOTIFY &&
|
||||||
|
event->crossing.detail != GDK_NOTIFY_INFERIOR)
|
||||||
|
{
|
||||||
|
g_assert (display->pointer_info.toplevel_under_pointer == event_window);
|
||||||
|
g_object_unref (display->pointer_info.toplevel_under_pointer);
|
||||||
|
display->pointer_info.toplevel_under_pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdk_event_get_coords (event, &x, &y);
|
||||||
display->pointer_info.toplevel_x = x;
|
display->pointer_info.toplevel_x = x;
|
||||||
display->pointer_info.toplevel_y = y;
|
display->pointer_info.toplevel_y = y;
|
||||||
gdk_event_get_state (event, &display->pointer_info.state);
|
gdk_event_get_state (event, &display->pointer_info.state);
|
||||||
|
|
||||||
if (pointer_window != display->pointer_info.window_under_pointer)
|
|
||||||
{
|
unlink_event = FALSE;
|
||||||
if (display->pointer_info.window_under_pointer)
|
if (is_motion_type (event->type))
|
||||||
g_object_unref (display->pointer_info.window_under_pointer);
|
unlink_event = proxy_pointer_event (display,
|
||||||
display->pointer_info.window_under_pointer = NULL;
|
event);
|
||||||
if (pointer_window)
|
else if (is_button_type (event->type))
|
||||||
display->pointer_info.window_under_pointer = g_object_ref (pointer_window);
|
unlink_event = proxy_button_event (event);
|
||||||
}
|
|
||||||
|
|
||||||
if (unlink_event)
|
if (unlink_event)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -987,7 +987,7 @@ gdk_event_translate (GdkDisplay *display,
|
|||||||
display_x11->keyboard_xgrab_window != NULL &&
|
display_x11->keyboard_xgrab_window != NULL &&
|
||||||
(
|
(
|
||||||
/* The window is not a descendant of the grabbed window */
|
/* The window is not a descendant of the grabbed window */
|
||||||
!is_parent_of (display_x11->keyboard_xgrab_window, window) ||
|
!is_parent_of ((GdkWindow *)display_x11->keyboard_xgrab_window, window) ||
|
||||||
/* Or owner event is false */
|
/* Or owner event is false */
|
||||||
!display_x11->keyboard_xgrab_owner_events
|
!display_x11->keyboard_xgrab_owner_events
|
||||||
)
|
)
|
||||||
|
|||||||
@ -3185,7 +3185,8 @@ gdk_display_warp_pointer (GdkDisplay *display,
|
|||||||
GdkWindow*
|
GdkWindow*
|
||||||
_gdk_windowing_window_at_pointer (GdkDisplay *display,
|
_gdk_windowing_window_at_pointer (GdkDisplay *display,
|
||||||
gint *win_x,
|
gint *win_x,
|
||||||
gint *win_y)
|
gint *win_y,
|
||||||
|
GdkModifierType *mask)
|
||||||
{
|
{
|
||||||
GdkWindow *window;
|
GdkWindow *window;
|
||||||
GdkScreen *screen;
|
GdkScreen *screen;
|
||||||
@ -3294,6 +3295,8 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
|
|||||||
window = gdk_window_lookup_for_display (display, xwindow_last);
|
window = gdk_window_lookup_for_display (display, xwindow_last);
|
||||||
*win_x = window ? winx : -1;
|
*win_x = window ? winx : -1;
|
||||||
*win_y = window ? winy : -1;
|
*win_y = window ? winy : -1;
|
||||||
|
if (mask)
|
||||||
|
*mask = xmask;
|
||||||
|
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user