[gtk+/client-side-windows: 47/284] New approach to motion event handling
- From: Alexander Larsson <alexl src gnome org>
- To: svn-commits-list gnome org
- Subject: [gtk+/client-side-windows: 47/284] New approach to motion event handling
- Date: Thu, 2 Apr 2009 14:03:40 -0400 (EDT)
commit b771c9924d63259bc38f46349230ce48dda953e6
Author: Alexander Larsson <alexl redhat com>
Date: Mon Dec 15 10:24:54 2008 +0100
New approach to motion event handling
---
gdk/gdkdisplay.c | 233 ++++++++++++----
gdk/gdkdisplay.h | 14 +-
gdk/gdkinternals.h | 11 +-
gdk/gdkwindow.c | 714 +++++++++++++++++++++++++++--------------------
gdk/x11/gdkevents-x11.c | 2 +-
gdk/x11/gdkwindow-x11.c | 7 +-
6 files changed, 606 insertions(+), 375 deletions(-)
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index bc515b5..d07b6a5 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -491,7 +491,7 @@ gdk_display_real_get_window_at_pointer (GdkDisplay *display,
GdkWindow *window;
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
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
_gdk_display_set_has_pointer_grab (GdkDisplay *display,
GdkWindow *window,
@@ -747,51 +758,89 @@ _gdk_display_set_has_pointer_grab (GdkDisplay *display,
guint32 time,
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 &&
display->pointer_grab.window != window)
{
generate_grab_broken_event (GDK_WINDOW (display->pointer_grab.window),
FALSE, display->pointer_grab.implicit,
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)
+
+ /* 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)
{
- _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);
+ 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;
@@ -810,10 +859,12 @@ _gdk_display_unset_has_pointer_grab (GdkDisplay *display,
gboolean do_grab_one_pointer_release_event,
guint32 time)
{
- int wx, wy;
+ 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;
@@ -821,34 +872,98 @@ _gdk_display_unset_has_pointer_grab (GdkDisplay *display,
if (do_grab_one_pointer_release_event)
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
- delivered to anything but the grab window */
+ /* Set first so crossing events get sent */
display->pointer_grab.window = NULL;
- /* Normal UNGRAB 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 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.
+ 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))
+ 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 (_gdk_windowing_window_at_pointer (display, &wx, &wy) == old_native_grab_window)
+ 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,
- display->pointer_info.window_under_pointer,
+ NULL,
GDK_CROSSING_UNGRAB,
- /* These may be stale... */
- display->pointer_info.toplevel_x,
- display->pointer_info.toplevel_y,
- display->pointer_info.state,
- time, TRUE, TRUE);
+ x, y, state,
+ time,
+ NULL, FALSE);
+ }
+ 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)
generate_grab_broken_event (old_grab_window,
diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h
index 790bc0b..e4ca845 100644
--- a/gdk/gdkdisplay.h
+++ b/gdk/gdkdisplay.h
@@ -58,14 +58,18 @@ typedef struct
GdkWindow *grab_one_pointer_release_event;
} GdkPointerGrabInfo;
-/* Tracks information about which window the pointer is in and
- * at what position the mouse is. This is useful when we need
- * to synthesize events later.
+/* 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,
+ * 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
{
- GdkWindow *window_under_pointer;
- gdouble toplevel_x, toplevel_y;
+ 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;
guint32 state;
} GdkPointerWindowInfo;
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 0acd617..51d3f7d 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -345,7 +345,12 @@ GdkWindow* _gdk_windowing_window_get_pointer (GdkDisplay *display,
GdkModifierType *mask);
GdkWindow* _gdk_windowing_window_at_pointer (GdkDisplay *display,
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. */
gint _gdk_windowing_get_bits_for_depth (GdkDisplay *display,
@@ -521,8 +526,8 @@ void _gdk_syntesize_crossing_events (GdkDisplay *display,
gint toplevel_y,
GdkModifierType mask,
guint32 time_,
- gboolean do_first,
- gboolean do_last);
+ GdkEvent *event_in_queue,
+ gboolean before_event);
void _gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window);
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index de0f463..49a58d3 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -1159,6 +1159,7 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
GdkWindowObject *temp_private;
GdkWindow *temp_window;
GdkScreen *screen;
+ GdkDisplay *display;
GList *children;
GList *tmp;
@@ -1169,11 +1170,13 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
if (GDK_WINDOW_DESTROYED (window))
return;
+ display = gdk_drawable_get_display (GDK_DRAWABLE (window));
screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
temp_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
if (temp_window == window)
g_object_set_qdata (G_OBJECT (screen), quark_pointer_window, NULL);
+
switch (GDK_WINDOW_TYPE (window))
{
case GDK_WINDOW_ROOT:
@@ -1284,6 +1287,12 @@ _gdk_window_destroy_hierarchy (GdkWindow *window,
gdk_window_redirect_free (private->redirect);
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;
}
@@ -6615,13 +6624,9 @@ static gboolean
point_in_window (GdkWindowObject *window,
double x, double y)
{
- int w, h;
-
- gdk_drawable_get_size (GDK_DRAWABLE (window), &w, &h);
-
return
- x >= 0 && x < w &&
- y >= 0 && y < h;
+ x >= 0 && x < window->width &&
+ y >= 0 && y < window->height;
}
static void
@@ -6856,22 +6861,22 @@ is_motion_type (GdkEventType type)
type == GDK_LEAVE_NOTIFY;
}
-static GdkWindow *
-find_common_ancestor (GdkWindow *win1,
- GdkWindow *win2)
+static GdkWindowObject *
+find_common_ancestor (GdkWindowObject *win1,
+ GdkWindowObject *win2)
{
GdkWindowObject *tmp;
GList *path1 = NULL, *path2 = NULL;
GList *list1, *list2;
- tmp = GDK_WINDOW_OBJECT (win1);
+ tmp = win1;
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
{
path1 = g_list_prepend (path1, tmp);
tmp = tmp->parent;
}
- tmp = GDK_WINDOW_OBJECT (win2);
+ tmp = win2;
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
{
path2 = g_list_prepend (path2, tmp);
@@ -6890,7 +6895,7 @@ find_common_ancestor (GdkWindow *win1,
g_list_free (path1);
g_list_free (path2);
- return GDK_WINDOW (tmp);
+ return tmp;
}
GdkEvent *
@@ -6995,6 +7000,54 @@ _gdk_make_event (GdkWindow *window,
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.
* 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
@@ -7009,159 +7062,134 @@ _gdk_syntesize_crossing_events (GdkDisplay *display,
gint toplevel_y,
GdkModifierType mask,
guint32 time_,
- gboolean do_first,
- gboolean do_last)
+ GdkEvent *event_in_queue,
+ gboolean before_event)
{
- GdkWindow *c;
- GdkWindow *win, *last, *next;
- GdkEvent *event;
+ GdkWindowObject *c;
+ GdkWindowObject *win, *last, *next;
GList *path, *list;
gboolean non_linear;
- GdkWindow *a;
- GdkWindow *b;
- GdkWindow *event_win;
+ GdkWindowObject *a;
+ GdkWindowObject *b;
GdkWindowObject *toplevel;
+ GdkNotifyType notify_type;
/* TODO: Don't send events to toplevel, as we get those from the windowing system */
- a = src;
- b = dest;
+ a = (GdkWindowObject *)src;
+ b = (GdkWindowObject *)dest;
if (a == b)
return; /* No crossings generated between src and dest */
c = find_common_ancestor (a, b);
+
non_linear = (c != a) && (c != b);
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 */
-
- event_win = get_target_window_for_pointer_event (display, a, GDK_LEAVE_NOTIFY, mask);
- if (do_first && event_win)
+ if (non_linear)
+ notify_type = GDK_NOTIFY_NONLINEAR;
+ else if (c == a)
+ notify_type = GDK_NOTIFY_INFERIOR;
+ else
+ notify_type = GDK_NOTIFY_ANCESTOR;
+ send_crossing_event (display, toplevel,
+ a, GDK_LEAVE_NOTIFY,
+ mode,
+ notify_type,
+ NULL,
+ toplevel_x, toplevel_y,
+ mask, time_,
+ event_in_queue, before_event);
+
+ if (c != a)
{
- event = _gdk_make_event (event_win, GDK_LEAVE_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_INFERIOR;
+ notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
else
- event->crossing.detail = GDK_NOTIFY_ANCESTOR;
- event->crossing.focus = FALSE;
- event->crossing.state = mask;
- }
-
- if (c != a)
- {
+ notify_type = GDK_NOTIFY_VIRTUAL;
+
last = a;
- win = GDK_WINDOW (GDK_WINDOW_OBJECT (a)->parent);
+ win = a->parent;
while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
{
- event_win = get_target_window_for_pointer_event (display, win, GDK_LEAVE_NOTIFY, mask);
- if (event_win)
- {
- event = _gdk_make_event (event_win, GDK_LEAVE_NOTIFY, NULL, FALSE);
- event->crossing.time = time_;
- event->crossing.subwindow = g_object_ref (last);
- 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_VIRTUAL;
- else
- event->crossing.detail = GDK_NOTIFY_VIRTUAL;
- event->crossing.focus = FALSE;
- event->crossing.state = mask;
- }
+ send_crossing_event (display, toplevel,
+ win, GDK_LEAVE_NOTIFY,
+ mode,
+ notify_type,
+ (GdkWindow *)last,
+ toplevel_x, toplevel_y,
+ mask, time_,
+ event_in_queue, before_event);
+
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 */
{
- toplevel = (GdkWindowObject *)gdk_window_get_toplevel (b);
+ toplevel = (GdkWindowObject *)gdk_window_get_toplevel ((GdkWindow *)b);
/* Traverse down from c to b */
if (c != b)
{
path = NULL;
- win = GDK_WINDOW (GDK_WINDOW_OBJECT (b)->parent);
+ win = b->parent;
while (win != c && GDK_WINDOW_TYPE (win) != GDK_WINDOW_ROOT)
{
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;
while (list)
{
- win = (GdkWindow *)list->data;
+ win = (GdkWindowObject *)list->data;
list = g_list_next (list);
if (list)
- next = (GdkWindow *)list->data;
+ next = (GdkWindowObject *)list->data;
else
next = b;
-
- event_win = get_target_window_for_pointer_event (display, win, GDK_ENTER_NOTIFY, mask);
- if (event_win)
- {
- event = _gdk_make_event (event_win, GDK_ENTER_NOTIFY, NULL, FALSE);
- event->crossing.time = time_;
- event->crossing.subwindow = g_object_ref (next);
- 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_VIRTUAL;
- else
- event->crossing.detail = GDK_NOTIFY_VIRTUAL;
- event->crossing.focus = FALSE;
- event->crossing.state = mask;
- }
+
+ send_crossing_event (display, toplevel,
+ win, GDK_ENTER_NOTIFY,
+ mode,
+ notify_type,
+ (GdkWindow *)next,
+ toplevel_x, toplevel_y,
+ mask, time_,
+ event_in_queue, before_event);
}
g_list_free (path);
}
+
+
+ if (non_linear)
+ notify_type = GDK_NOTIFY_NONLINEAR;
+ else if (c == a)
+ notify_type = GDK_NOTIFY_ANCESTOR;
+ else
+ notify_type = GDK_NOTIFY_INFERIOR;
- 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;
- }
+ 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 *
@@ -7176,146 +7204,182 @@ get_toplevel (GdkWindow *w)
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
_gdk_syntesize_crossing_events_for_geometry_change (GdkWindow *changed_window)
{
GdkDisplay *display;
GdkWindow *changed_toplevel;
- GdkWindow *pointer_toplevel;
+ GdkWindow *pointer_toplevel, *grab_toplevel;
GdkWindow *new_window_under_pointer;
changed_toplevel = get_toplevel (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)
+ {
+ new_window_under_pointer =
+ get_pointer_window (display, changed_toplevel,
+ display->pointer_info.toplevel_x,
+ display->pointer_info.toplevel_y);
+ if (new_window_under_pointer !=
+ display->pointer_info.window_under_pointer)
+ {
+ _gdk_syntesize_crossing_events (display,
+ display->pointer_info.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,
+ NULL, FALSE);
+ set_window_under_pointer (display, 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))
{
- pointer_toplevel = get_toplevel (display->pointer_info.window_under_pointer);
+ evmask = display->pointer_grab.event_mask;
+ evmask = update_evmask_for_button_motion (evmask, mask);
- if (pointer_toplevel == changed_toplevel)
+ if (type == GDK_BUTTON_RELEASE &&
+ display->pointer_grab.grab_one_pointer_release_event)
{
- new_window_under_pointer =
- _gdk_window_find_descendant_at (pointer_toplevel,
- display->pointer_info.toplevel_x,
- display->pointer_info.toplevel_y,
- NULL, NULL);
- if (new_window_under_pointer !=
- display->pointer_info.window_under_pointer)
- {
- _gdk_syntesize_crossing_events (display,
- display->pointer_info.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);
- }
+ 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
proxy_pointer_event (GdkDisplay *display,
- GdkWindow *pointer_window,
- gdouble toplevel_x,
- gdouble toplevel_y,
GdkEvent *source_event)
{
- GdkWindow *event_window;
- GdkWindow *event_win, *cursor_window;
- gboolean crossing_event;
+ GdkWindow *toplevel_window;
+ GdkWindow *pointer_window;
+ GdkWindow *cursor_window;
gboolean sent_motion;
GdkEvent *event;
guint state;
+ gdouble toplevel_x, toplevel_y;
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);
time_ = gdk_event_get_time (source_event);
- crossing_event =
- source_event->type == GDK_ENTER_NOTIFY ||
- source_event->type == GDK_LEAVE_NOTIFY;
-
- if (crossing_event)
+ pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
+ if (display->pointer_info.window_under_pointer != pointer_window)
{
- GdkEventCrossing *crossing = &source_event->crossing;
-
- if (crossing->mode == GDK_CROSSING_GRAB)
- {
- if (crossing->type == GDK_LEAVE_NOTIFY &&
- display->pointer_info.window_under_pointer != NULL)
- {
- _gdk_syntesize_crossing_events (display,
- display->pointer_info.window_under_pointer,
- event_window,
- GDK_CROSSING_GRAB,
- toplevel_x, toplevel_y, state, time_,
- TRUE, FALSE);
- }
+ /* 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->type == GDK_ENTER_NOTIFY &&
- 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);
- }
- }
+ _gdk_syntesize_crossing_events (display,
+ display->pointer_info.window_under_pointer,
+ pointer_window,
+ GDK_CROSSING_NORMAL,
+ toplevel_x, toplevel_y,
+ state, time_,
+ source_event, source_event->type == GDK_LEAVE_NOTIFY);
- 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);
- }
- }
+ set_window_under_pointer (display, pointer_window);
}
-
- 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)))
+ else if (source_event->type == GDK_MOTION_NOTIFY)
{
- /* send motion events */
- event_win = get_target_window_for_pointer_event (display, pointer_window, GDK_MOTION_NOTIFY, state);
+ GdkWindow *event_win;
+
+ event_win = get_event_window (display,
+ pointer_window,
+ source_event->type,
+ state);
+
if (event_win)
{
sent_motion = TRUE;
@@ -7334,43 +7398,52 @@ proxy_pointer_event (GdkDisplay *display,
}
}
- _gdk_syntesize_crossing_events (display,
- display->pointer_info.window_under_pointer,
- pointer_window,
- GDK_CROSSING_NORMAL,
- toplevel_x, toplevel_y,
- state, time_,
- TRUE, TRUE);
+ /* 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 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
-proxy_button_event (GdkWindow *pointer_window,
- gdouble toplevel_x,
- gdouble toplevel_y,
- GdkEvent *source_event)
+proxy_button_event (GdkEvent *source_event)
{
+ GdkWindow *toplevel_window;
GdkWindow *event_win;
+ GdkWindow *pointer_window;
GdkEvent *event;
guint state;
guint32 time_;
GdkEventType type;
+ gdouble toplevel_x, toplevel_y;
GdkDisplay *display;
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);
time_ = gdk_event_get_time (source_event);
display = gdk_drawable_get_display (source_event->any.window);
-
+
if ((type == GDK_BUTTON_PRESS || type == GDK_SCROLL) &&
- pointer_window != NULL &&
display->pointer_grab.window == source_event->any.window &&
display->pointer_grab.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,
pointer_window,
display->pointer_grab.native_window,
@@ -7382,57 +7455,51 @@ proxy_button_event (GdkWindow *pointer_window,
display->pointer_grab.converted_implicit = TRUE;
}
- event_win = get_target_window_for_pointer_event (display,
- pointer_window,
- type,
- state);
+ pointer_window = get_pointer_window (display, toplevel_window, toplevel_x, toplevel_y);
+
+ event_win = get_event_window (display,
+ pointer_window,
+ type,
+ state);
if (event_win == NULL)
return TRUE;
- if (event_win != source_event->any.window)
- {
- event = _gdk_make_event (event_win, type, source_event, FALSE);
-
- switch (type)
- {
- 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;
-
- if (type == GDK_BUTTON_PRESS)
- _gdk_event_button_generate (display, event);
- return TRUE;
-
- case GDK_SCROLL:
- 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
+ event = _gdk_make_event (event_win, type, source_event, FALSE);
+
+ switch (type)
{
- /* Same window as original window, keep the event */
- if (source_event->type == GDK_BUTTON_PRESS)
- _gdk_event_button_generate (display, source_event);
+ 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;
+
+ if (type == GDK_BUTTON_PRESS)
+ _gdk_event_button_generate (display, event);
+ return TRUE;
+
+ case GDK_SCROLL:
+ 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;
}
+
+ return TRUE; /* Always unlink original, we want to obey the emulated event mask */
}
void
@@ -7441,9 +7508,8 @@ _gdk_windowing_got_event (GdkDisplay *display,
GdkEvent *event)
{
GdkWindow *event_window;
- GdkWindow *pointer_window;
GdkWindowObject *event_private;
- gdouble x, y, child_x, child_y;
+ gdouble x, y;
gboolean unlink_event;
event_window = event->any.window;
@@ -7466,40 +7532,78 @@ _gdk_windowing_got_event (GdkDisplay *display,
event_private->window_type);
/* 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,
- window_type_value->value_name);
+ window_type_value->value_name,
+ GDK_WINDOW_TYPE (event_window));
return;
}
-
- gdk_event_get_coords (event, &x, &y);
- pointer_window = _gdk_window_find_descendant_at (event_window, x, y,
- &child_x,
- &child_y);
- unlink_event = FALSE;
- if (is_motion_type (event->type))
- unlink_event = proxy_pointer_event (display,
- pointer_window,
- x, y,
- event);
- else if (is_button_type (event->type))
- unlink_event = proxy_button_event (pointer_window, x, y,
- event);
+ if ((event->type == GDK_ENTER_NOTIFY ||
+ event->type == GDK_LEAVE_NOTIFY) &&
+ (event->crossing.mode == GDK_CROSSING_GRAB ||
+ event->crossing.mode == GDK_CROSSING_UNGRAB))
+ {
+ /* We synthesize all crossing events due to grabs are synthesized,
+ * so we ignore the native ones. This is partly to get easier non-X
+ * portability, and because of problems with race conditions due to
+ * the cached state in the client and the real state in the xserver
+ * when grabbing.
+ */
+
+ /* 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 */
+ 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_y = y;
gdk_event_get_state (event, &display->pointer_info.state);
+
- if (pointer_window != display->pointer_info.window_under_pointer)
- {
- if (display->pointer_info.window_under_pointer)
- g_object_unref (display->pointer_info.window_under_pointer);
- display->pointer_info.window_under_pointer = NULL;
- if (pointer_window)
- display->pointer_info.window_under_pointer = g_object_ref (pointer_window);
- }
+ unlink_event = FALSE;
+ if (is_motion_type (event->type))
+ unlink_event = proxy_pointer_event (display,
+ event);
+ else if (is_button_type (event->type))
+ unlink_event = proxy_button_event (event);
if (unlink_event)
{
diff --git a/gdk/x11/gdkevents-x11.c b/gdk/x11/gdkevents-x11.c
index 2a8c32c..4f02dc2 100644
--- a/gdk/x11/gdkevents-x11.c
+++ b/gdk/x11/gdkevents-x11.c
@@ -987,7 +987,7 @@ gdk_event_translate (GdkDisplay *display,
display_x11->keyboard_xgrab_window != NULL &&
(
/* 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 */
!display_x11->keyboard_xgrab_owner_events
)
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 21fe7d6..27ab045 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -3185,7 +3185,8 @@ gdk_display_warp_pointer (GdkDisplay *display,
GdkWindow*
_gdk_windowing_window_at_pointer (GdkDisplay *display,
gint *win_x,
- gint *win_y)
+ gint *win_y,
+ GdkModifierType *mask)
{
GdkWindow *window;
GdkScreen *screen;
@@ -3294,7 +3295,9 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display,
window = gdk_window_lookup_for_display (display, xwindow_last);
*win_x = window ? winx : -1;
*win_y = window ? winy : -1;
-
+ if (mask)
+ *mask = xmask;
+
return window;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]