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:
parent
ed8d0fc691
commit
ec32b2aaa3
10
ChangeLog
10
ChangeLog
@ -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):
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user