[gtk+/gtk-2-24] quartz: filter out button press events on the window frame
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/gtk-2-24] quartz: filter out button press events on the window frame
- Date: Thu, 15 Nov 2012 10:39:30 +0000 (UTC)
commit 43e1354b71640d3fb7a47b997a436dc65bbd922f
Author: Michael Natterer <mitch gimp org>
Date: Thu Nov 15 11:34:15 2012 +0100
quartz: filter out button press events on the window frame
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.
gdk/quartz/gdkevents-quartz.c | 84 +++++++++++++++++++++++++++++++++++++---
1 files changed, 77 insertions(+), 7 deletions(-)
---
diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
index 0810962..e7fd3cd 100644
--- a/gdk/quartz/gdkevents-quartz.c
+++ b/gdk/quartz/gdkevents-quartz.c
@@ -455,19 +455,34 @@ get_window_point_from_screen_point (GdkWindow *window,
*y = private->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;
GdkWindowObject *private;
- NSPoint point;
+ NSPoint point, view_point;
+ NSRect view_frame;
view = (GdkQuartzView *)[[nsevent window] contentView];
@@ -475,16 +490,56 @@ get_toplevel_from_ns_event (NSEvent *nsevent,
private = GDK_WINDOW_OBJECT (toplevel);
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 = private->height - point.y;
+ *x = point.x;
+ *y = private->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,
@@ -649,6 +704,19 @@ 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.
+ */
+ GdkWindowObject *private = GDK_WINDOW_OBJECT (toplevel);
+ if (*x < 0 || *y < 0 || *x >= private->width || *y >= private->height)
+ return NULL;
+ }
+
return toplevel;
}
@@ -670,6 +738,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];
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]