Skip to content

Commit

Permalink
quartz: filter out button press events on the window frame
Browse files Browse the repository at this point in the history
Don't try to handle button press events on the window frame, they
have out-of-window coordinates. Also, break grabs on such events
so popup menus go away.
Patch from Kristian Rietveld, fixes bug 684419.
(cherry picked from commit 43e1354)
  • Loading branch information
mitchfoo committed Nov 15, 2012
1 parent 2f8c2a3 commit ed5d7fe
Showing 1 changed file with 75 additions and 6 deletions.
81 changes: 75 additions & 6 deletions gdk/quartz/gdkevents-quartz.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,34 +401,89 @@ get_window_point_from_screen_point (GdkWindow *window,
*y = window->height - point.y;
}

static gboolean
is_mouse_button_press_event (NSEventType type)
{
switch (type)
{
case NSLeftMouseDown:
case NSRightMouseDown:
case NSOtherMouseDown:
return TRUE;
}

return FALSE;
}

static GdkWindow *
get_toplevel_from_ns_event (NSEvent *nsevent,
NSPoint *screen_point,
gint *x,
gint *y)
{
GdkWindow *toplevel;
GdkWindow *toplevel = NULL;

if ([nsevent window])
{
GdkQuartzView *view;
NSPoint point;
NSPoint point, view_point;
NSRect view_frame;

view = (GdkQuartzView *)[[nsevent window] contentView];

toplevel = [view gdkWindow];

point = [nsevent locationInWindow];
*screen_point = [[nsevent window] convertBaseToScreen:point];
view_point = [view convertPoint:point fromView:nil];
view_frame = [view frame];

/* NSEvents come in with a window set, but with window coordinates
* out of window bounds. For e.g. moved events this is fine, we use
* this information to properly handle enter/leave notify and motion
* events. For mouse button press/release, we want to avoid forwarding
* these events however, because the window they relate to is not the
* window set in the event. This situation appears to occur when button
* presses come in just before (or just after?) a window is resized and
* also when a button press occurs on the OS X window titlebar.
*
* By setting toplevel to NULL, we do another attempt to get the right
* toplevel window below.
*/
if (is_mouse_button_press_event ([nsevent type]) &&
(view_point.x < view_frame.origin.x ||
view_point.x >= view_frame.origin.x + view_frame.size.width ||
view_point.y < view_frame.origin.y ||
view_point.y >= view_frame.origin.y + view_frame.size.height))
{
toplevel = NULL;

/* This is a hack for button presses to break all grabs. E.g. if
* a menu is open and one clicks on the title bar (or anywhere
* out of window bounds), we really want to pop down the menu (by
* breaking the grabs) before OS X handles the action of the title
* bar button.
*
* Because we cannot ingest this event into GDK, we have to do it
* here, not very nice.
*/
_gdk_quartz_events_break_all_grabs (get_time_from_ns_event (nsevent));
}
else
{
*screen_point = [[nsevent window] convertBaseToScreen:point];

*x = point.x;
*y = toplevel->height - point.y;
*x = point.x;
*y = toplevel->height - point.y;
}
}
else

if (!toplevel)
{
/* Fallback used when no NSWindow set. This happens e.g. when
* we allow motion events without a window set in gdk_event_translate()
* that occur immediately after the main menu bar was clicked/used.
* This fallback will not return coordinates contained in a window's
* titlebar.
*/
*screen_point = [NSEvent mouseLocation];
toplevel = find_toplevel_under_pointer (_gdk_display,
Expand Down Expand Up @@ -600,6 +655,18 @@ find_toplevel_under_pointer (GdkDisplay *display,
if (toplevel && WINDOW_IS_TOPLEVEL (toplevel))
get_window_point_from_screen_point (toplevel, screen_point, x, y);

if (toplevel)
{
/* If the coordinates are out of window bounds, this toplevel is not
* under the pointer and we thus return NULL. This can occur when
* toplevel under pointer has not yet been updated due to a very recent
* window resize. Alternatively, we should no longer be relying on
* the toplevel_under_pointer value which is maintained in gdkwindow.c.
*/
if (*x < 0 || *y < 0 || *x >= toplevel->width || *y >= toplevel->height)
return NULL;
}

return toplevel;
}

Expand Down Expand Up @@ -772,6 +839,8 @@ find_window_for_ns_event (NSEvent *nsevent,
view = (GdkQuartzView *)[[nsevent window] contentView];

toplevel = get_toplevel_from_ns_event (nsevent, &screen_point, x, y);
if (!toplevel)
return NULL;
_gdk_quartz_window_nspoint_to_gdk_xy (screen_point, x_root, y_root);

event_type = [nsevent type];
Expand Down

0 comments on commit ed5d7fe

Please sign in to comment.