Rework how we get the event window: don't get the window from the NSEvent,

2007-06-06  Richard Hult  <richard@imendio.com>

	* gdk/quartz/gdkevents-quartz.c (find_mouse_window_for_ns_event)
	(find_window_for_ns_event): Rework how we get the event window:
	don't get the window from the NSEvent, always use the mouse window
	instead. Fix mouse window tracking by only using MouseExited for
	non-gdk windows, and to always use the NSEvent window to get the
	right gdk window in MouseEntered. Add comments to the code. Fixes bug
	#350460.

svn path=/trunk/; revision=18065
This commit is contained in:
Richard Hult 2007-06-06 18:42:07 +00:00 committed by Richard Hult
parent ed8d0fc691
commit ec32b2aaa3
2 changed files with 138 additions and 42 deletions

View File

@ -1,3 +1,13 @@
2007-06-06 Richard Hult <richard@imendio.com>
* gdk/quartz/gdkevents-quartz.c (find_mouse_window_for_ns_event)
(find_window_for_ns_event): Rework how we get the event window:
don't get the window from the NSEvent, always use the mouse window
instead. Fix mouse window tracking by only using MouseExited for
non-gdk windows, and to always use the NSEvent window to get the
right gdk window in MouseEntered. Add comments to the code. Fixes bug
#350460.
2007-06-06 Richard Hult <richard@imendio.com>
* gdk/quartz/gdkevents-quartz.c (get_converted_window_coordinates):

View File

@ -937,54 +937,67 @@ get_converted_window_coordinates (GdkWindow *in_window,
out_x, out_y);
}
/* Given a mouse NSEvent, returns the window in which the pointer
* position from the event is. The returned coordinates are relative
* to the found window, and normal GDK coordinates, not Quartz.
*/
/* Given a mouse NSEvent (must be a mouse event for a GDK window),
* finds the subwindow over which the pointer is located. Returns
* coordinates relative to the found window. If no window is found,
* returns NULL.
*/
static GdkWindow *
find_window_for_mouse_ns_event (NSEvent *nsevent,
find_mouse_window_for_ns_event (NSEvent *nsevent,
gint *x_ret,
gint *y_ret)
{
NSWindow *nswindow;
GdkWindow *toplevel;
GdkWindow *event_toplevel;
GdkWindow *mouse_toplevel;
GdkWindow *mouse_window;
NSPoint point;
gint x_tmp, y_tmp;
GdkWindow *found_window;
nswindow = [nsevent window];
toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
point = [nsevent locationInWindow];
x_tmp = point.x;
/* Flip the y coordinate. */
if (toplevel == _gdk_root)
if (event_toplevel == _gdk_root)
y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
else
{
GdkWindowImplQuartz *impl;
impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
y_tmp = impl->height - point.y;
}
found_window = _gdk_quartz_window_find_child (toplevel, x_tmp, y_tmp);
if (!current_mouse_window)
return NULL;
/* Translate the coordinates so they are relative to the found
* window.
*/
if (found_window)
get_child_coordinates_from_ancestor (toplevel,
mouse_toplevel = gdk_window_get_toplevel (current_mouse_window);
get_converted_window_coordinates (event_toplevel,
x_tmp, y_tmp,
mouse_toplevel,
&x_tmp, &y_tmp);
mouse_window = _gdk_quartz_window_find_child (mouse_toplevel, x_tmp, y_tmp);
if (!mouse_window)
{
/* This happens for events on the window title and window
* buttons (and the desktop).
*/
return NULL;
}
if (mouse_window != mouse_toplevel)
get_child_coordinates_from_ancestor (mouse_toplevel,
x_tmp, y_tmp,
found_window,
mouse_window,
&x_tmp, &y_tmp);
*x_ret = x_tmp;
*y_ret = y_tmp;
return found_window;
return mouse_window;
}
/* This function finds the correct window to send an event to, taking
@ -1016,24 +1029,22 @@ find_window_for_ns_event (NSEvent *nsevent,
{
GdkWindow *mouse_window;
mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
if (!mouse_window)
mouse_window = _gdk_root;
/* We don't need to handle the case where we don't find a mouse
* window (i.e. after leaving a gdk toplevel and not entering a
* new one) here, it's covered by NSMouseExited events.
*/
if (mouse_window && mouse_window != current_mouse_window)
synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
if (_gdk_quartz_pointer_grab_window)
{
if (mouse_window != current_mouse_window)
synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
}
else
{
if (current_mouse_window != mouse_window)
{
synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
_gdk_quartz_events_update_cursor (mouse_window);
}
}
/* FIXME: Does this check really work as intended? It seems like
* we sometimes get a cursor update when we shouldn't, for
* example during an implicit grab on a GtkButton, and dragging
* the mouse over a link button.
*/
if (mouse_window && !_gdk_quartz_pointer_grab_window)
_gdk_quartz_events_update_cursor (mouse_window);
}
switch (event_type)
@ -1070,7 +1081,7 @@ find_window_for_ns_event (NSEvent *nsevent,
{
if (pointer_grab_owner_events)
{
mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
event_mask = get_event_mask_from_ns_event (nsevent);
real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
@ -1116,7 +1127,7 @@ find_window_for_ns_event (NSEvent *nsevent,
else
{
/* The non-grabbed case. */
mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
event_mask = get_event_mask_from_ns_event (nsevent);
real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
@ -1136,15 +1147,90 @@ find_window_for_ns_event (NSEvent *nsevent,
case NSMouseEntered:
{
GdkWindow *mouse_window;
GdkWindow *event_toplevel;
GdkWindow *mouse_window;
NSPoint point;
gint x_tmp, y_tmp;
event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
point = [nsevent locationInWindow];
x_tmp = point.x;
/* Flip the y coordinate. */
if (event_toplevel == _gdk_root)
y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
else
{
GdkWindowImplQuartz *impl;
impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
y_tmp = impl->height - point.y;
}
/* This is the only case where we actually use the window from
* the event since we need to know which toplevel we entered
* so it can be tracked properly.
*/
mouse_window = _gdk_quartz_window_find_child (event_toplevel, x_tmp, y_tmp);
/* Treat unknown windows (including title bar/buttons,
* desktop) as the root.
*/
if (!mouse_window)
mouse_window = _gdk_root;
mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
}
break;
case NSMouseExited:
synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, *x, *y);
{
GdkWindow *event_toplevel;
GdkWindow *mouse_window;
NSPoint point;
gint x_tmp, y_tmp;
gint x_orig, y_orig;
/* We get mouse exited when leaving toplevels. We only use
* this when leaving from a window to the root window. The
* other case is handled above by checking the motion/button
* events, or getting a MouseEntered for another GDK window.
*
* The reason we don't use MouseExited for other windows is
* that quartz first delivers the entered event and then the
* exited which is the opposite from what we need.
*/
/* Check if the root window has a child at this position, if
* so ignore the event.
*/
event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
point = [nsevent locationInWindow];
x_tmp = point.x;
/* Flip the y coordinate. */
if (event_toplevel == _gdk_root)
y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
else
{
GdkWindowImplQuartz *impl;
impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
y_tmp = impl->height - point.y;
}
if (gdk_window_get_origin (event_toplevel, &x_orig, &y_orig))
{
x_tmp += x_orig;
y_tmp += y_orig;
}
mouse_window = _gdk_quartz_window_find_child (_gdk_root, x_tmp, y_tmp);
if (mouse_window == _gdk_root)
synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, *x, *y);
}
break;
case NSKeyDown: