]> Pileus Git - ~andy/gtk/commitdiff
quartz: Process motion events within windows bounds without window set
authorKristian Rietveld <kris@lanedo.com>
Sun, 6 Nov 2011 08:25:16 +0000 (09:25 +0100)
committerKristian Rietveld <kris@lanedo.com>
Sun, 6 Nov 2011 09:15:16 +0000 (10:15 +0100)
When an NSEvent does not have the window field set, we already assumed
the event was not for us and discarded it.  But for NSMouseMoved events
we now make an exception, because such events generated after
using/clicking the main menu bar have the window field set to NULL while
the application window still has focus.

We used to experience a loss of motion events after using the menu bar,
this could be seen in buttons that stopped prelighting and first
clicks often being ignored unless you clicked somewhere else first.
These issues are fixed by this patch.

gdk/quartz/gdkevents-quartz.c

index 22a8f285c51e296f3537c1f30d2ea964e5c372aa..3ef3e0f243e8e398700575db6b12e57df98b698a 100644 (file)
@@ -57,6 +57,12 @@ static GdkModifierType current_button_state;
 static void append_event                        (GdkEvent  *event,
                                                  gboolean   windowing);
 
+static GdkWindow *find_toplevel_under_pointer   (GdkDisplay *display,
+                                                 NSPoint     screen_point,
+                                                 gint       *x,
+                                                 gint       *y);
+
+
 void
 _gdk_quartz_events_init (void)
 {
@@ -329,19 +335,34 @@ get_toplevel_from_ns_event (NSEvent *nsevent,
                             gint    *x,
                             gint    *y)
 {
-  GdkQuartzView *view;
   GdkWindow *toplevel;
-  NSPoint point;
 
-  view = (GdkQuartzView *)[[nsevent window] contentView];
+  if ([nsevent window])
+    {
+      GdkQuartzView *view;
+      NSPoint point;
 
-  toplevel = [view gdkWindow];
+      view = (GdkQuartzView *)[[nsevent window] contentView];
 
-  point = [nsevent locationInWindow];
-  *screen_point = [[nsevent window] convertBaseToScreen:point];
+      toplevel = [view gdkWindow];
 
-  *x = point.x;
-  *y = toplevel->height - point.y;
+      point = [nsevent locationInWindow];
+      *screen_point = [[nsevent window] convertBaseToScreen:point];
+
+      *x = point.x;
+      *y = toplevel->height - point.y;
+    }
+  else
+    {
+      /* 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.
+       */
+      *screen_point = [NSEvent mouseLocation];
+      toplevel = find_toplevel_under_pointer (_gdk_display,
+                                              *screen_point,
+                                              x, y);
+    }
 
   return toplevel;
 }
@@ -1164,10 +1185,33 @@ gdk_event_translate (GdkEvent *event,
 
   nswindow = [nsevent window];
 
-  /* Ignore events for no window or ones not created by GDK. */
-  if (!nswindow || ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
+  /* Ignore events for windows not created by GDK. */
+  if (nswindow && ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
     return FALSE;
 
+  /* Ignore events for ones with no windows */
+  if (!nswindow)
+    {
+      GdkWindow *toplevel = NULL;
+
+      if (event_type == NSMouseMoved)
+        {
+          /* Motion events received after clicking the menu bar do not have the
+           * window field set.  Instead of giving up on the event immediately,
+           * we first check whether this event is within our window bounds.
+           */
+          NSPoint screen_point = [NSEvent mouseLocation];
+          gint x_tmp, y_tmp;
+
+          toplevel = find_toplevel_under_pointer (_gdk_display,
+                                                  screen_point,
+                                                  &x_tmp, &y_tmp);
+        }
+
+      if (!toplevel)
+        return FALSE;
+    }
+
   /* Ignore events and break grabs while the window is being
    * dragged. This is a workaround for the window getting events for
    * the window title.