]> Pileus Git - ~andy/gtk/blobdiff - gdk/quartz/gdkevents-quartz.c
Merge branch 'master' into client-side-windows
[~andy/gtk] / gdk / quartz / gdkevents-quartz.c
index ad0d942efcdf4a194826b8324921a40fc9ed80ee..db73a11c321f4bb954c99e5f252b497f5bbf4743 100644 (file)
@@ -40,24 +40,6 @@ static GdkWindow   *current_keyboard_window;
 static GdkEventMask current_event_mask;
 static int          current_button_state;
 
-static void get_child_coordinates_from_ancestor (GdkWindow *ancestor_window,
-                                                 gint       ancestor_x,
-                                                 gint       ancestor_y,
-                                                 GdkWindow *child_window, 
-                                                 gint      *child_x, 
-                                                 gint      *child_y);
-static void get_ancestor_coordinates_from_child (GdkWindow *child_window,
-                                                 gint       child_x,
-                                                 gint       child_y,
-                                                 GdkWindow *ancestor_window, 
-                                                 gint      *ancestor_x, 
-                                                 gint      *ancestor_y);
-static void get_converted_window_coordinates    (GdkWindow *in_window,
-                                                 gint       in_x,
-                                                 gint       in_y,
-                                                 GdkWindow *out_window, 
-                                                 gint      *out_x, 
-                                                 gint      *out_y);
 static void append_event                        (GdkEvent  *event);
 
 NSEvent *
@@ -436,190 +418,31 @@ _gdk_quartz_events_send_map_event (GdkWindow *window)
     }
 }
 
-/* Translates coordinates from an ancestor window + coords, to
- * coordinates that are relative the child window.
- */
-static void
-get_child_coordinates_from_ancestor (GdkWindow *ancestor_window,
-                                    gint       ancestor_x,
-                                    gint       ancestor_y,
-                                    GdkWindow *child_window, 
-                                    gint      *child_x, 
-                                    gint      *child_y)
-{
-  GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window);
-  GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window);
-
-  while (child_private != ancestor_private)
-    {
-      ancestor_x -= child_private->x;
-      ancestor_y -= child_private->y;
-
-      child_private = child_private->parent;
-    }
-
-  *child_x = ancestor_x;
-  *child_y = ancestor_y;
-}
-
-/* Translates coordinates from a child window + coords, to
- * coordinates that are relative the ancestor window.
- */
-static void
-get_ancestor_coordinates_from_child (GdkWindow *child_window,
-                                    gint       child_x,
-                                    gint       child_y,
-                                    GdkWindow *ancestor_window, 
-                                    gint      *ancestor_x, 
-                                    gint      *ancestor_y)
-{
-  GdkWindowObject *child_private = GDK_WINDOW_OBJECT (child_window);
-  GdkWindowObject *ancestor_private = GDK_WINDOW_OBJECT (ancestor_window);
-
-  while (child_private != ancestor_private)
-    {
-      child_x += child_private->x;
-      child_y += child_private->y;
-
-      child_private = child_private->parent;
-    }
-
-  *ancestor_x = child_x;
-  *ancestor_y = child_y;
-}
-
-/* Translates coordinates relative to one window (in_window) into
- * coordinates relative to another window (out_window).
- */
-static void
-get_converted_window_coordinates (GdkWindow *in_window,
-                                  gint       in_x,
-                                  gint       in_y,
-                                  GdkWindow *out_window, 
-                                  gint      *out_x, 
-                                  gint      *out_y)
-{
-  GdkWindow *in_toplevel;
-  GdkWindow *out_toplevel;
-  int in_origin_x, in_origin_y;
-  int out_origin_x, out_origin_y;
-
-  if (in_window == out_window)
-    {
-      *out_x = in_x;
-      *out_y = in_y;
-      return;
-    }
-
-  /* First translate to "in" toplevel coordinates, then on to "out"
-   * toplevel coordinates, and finally to "out" child (the passed in
-   * window) coordinates.
-   */
-
-  in_toplevel = gdk_window_get_toplevel (in_window);
-  out_toplevel  = gdk_window_get_toplevel (out_window);
-
-  /* Translate in_x, in_y to "in" toplevel coordinates. */
-  get_ancestor_coordinates_from_child (in_window, in_x, in_y,
-                                       in_toplevel, &in_x, &in_y);
-
-  gdk_window_get_origin (in_toplevel, &in_origin_x, &in_origin_y);
-  gdk_window_get_origin (out_toplevel, &out_origin_x, &out_origin_y);
-
-  /* Translate in_x, in_y to "out" toplevel coordinates. */
-  in_x -= out_origin_x - in_origin_x;
-  in_y -= out_origin_y - in_origin_y;
-
-  get_child_coordinates_from_ancestor (out_toplevel, 
-                                       in_x, in_y,
-                                       out_window,
-                                       out_x, out_y);
-}
-
-/* Trigger crossing events if necessary. This is used when showing a new
- * window, since the tracking rect API doesn't work reliably when a window
- * shows up under the mouse cursor. It's done by finding the topmost window
- * under the mouse pointer and synthesizing crossing events into that
- * window.
- */
-void
-_gdk_quartz_events_trigger_crossing_events (gboolean defer_to_mainloop)
+static GdkWindow *
+find_toplevel_under_pointer (GdkDisplay *display,
+                             NSPoint     screen_point,
+                             gint       *x,
+                             gint       *y)
 {
-  NSPoint point;
-  gint x, y; 
-  gint x_toplevel, y_toplevel;
-  GdkWindow *mouse_window;
   GdkWindow *toplevel;
-  GdkWindowImplQuartz *impl;
-  GdkWindowObject *private;
-  guint flags = 0;
-  NSTimeInterval timestamp = 0;
-  NSEvent *current_event;
-  NSEvent *nsevent;
 
-  if (defer_to_mainloop)
+  toplevel = display->pointer_info.toplevel_under_pointer;
+  if (toplevel)
     {
-      nsevent = [NSEvent otherEventWithType:NSApplicationDefined
-                                   location:NSZeroPoint
-                              modifierFlags:0
-                                  timestamp:0
-                               windowNumber:0
-                                    context:nil
-                                    subtype:GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING
-                                      data1:0
-                                      data2:0];
-      [NSApp postEvent:nsevent atStart:NO];
-      return;
-    }
-
-  point = [NSEvent mouseLocation];
-  x = point.x;
-  y = _gdk_quartz_window_get_inverted_screen_y (point.y);
+      GdkWindowObject *private;
+      NSWindow *nswindow;
+      NSPoint point;
 
-  mouse_window = _gdk_quartz_window_find_child (_gdk_root, x, y);
-  if (!mouse_window || mouse_window == _gdk_root)
-    return;
-
-  toplevel = gdk_window_get_toplevel (mouse_window);
-
-  get_converted_window_coordinates (_gdk_root,
-                                    x, y,
-                                    toplevel,
-                                    &x_toplevel, &y_toplevel);
+      private = (GdkWindowObject *)toplevel;
+      nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
 
-  get_converted_window_coordinates (_gdk_root,
-                                    x, y,
-                                    mouse_window,
-                                    &x, &y);
+      point = [nswindow convertScreenToBase:screen_point];
 
-  /* Fix up the event to be less fake if possible. */
-  current_event = [NSApp currentEvent];
-  if (current_event)
-    {
-      flags = [current_event modifierFlags];
-      timestamp = [current_event timestamp];
+      *x = point.x;
+      *y = private->height - point.y;
     }
 
-  if (timestamp == 0)
-    timestamp = GetCurrentEventTime ();
-
-  impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
-  private = GDK_WINDOW_OBJECT (toplevel);
-  nsevent = [NSEvent otherEventWithType:NSApplicationDefined
-                               location:NSMakePoint (x_toplevel, private->height - y_toplevel)
-                          modifierFlags:flags
-                              timestamp:timestamp
-                           windowNumber:[impl->toplevel windowNumber]
-                                context:nil
-                                subtype:GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING
-                                  data1:0
-                                  data2:0];
-
-#ifdef G_ENABLE_DEBUG
-  /*_gdk_quartz_window_debug_highlight (mouse_window, 0);*/
-#endif
-
-  /* FIXME: create an event, fill it, put on the queue... */
+  return toplevel;
 }
 
 /* This function finds the correct window to send an event to, taking
@@ -632,16 +455,17 @@ find_window_for_ns_event (NSEvent *nsevent,
                           gint    *x_root,
                           gint    *y_root)
 {
+  GdkQuartzView *view;
   GdkWindow *toplevel;
   GdkWindowObject *private;
-  GdkWindowImplQuartz *impl;
   NSPoint point;
   NSPoint screen_point;
   NSEventType event_type;
 
-  toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
+  view = (GdkQuartzView *)[[nsevent window] contentView];
+
+  toplevel = [view gdkWindow];
   private = GDK_WINDOW_OBJECT (toplevel);
-  impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
 
   point = [nsevent locationInWindow];
   screen_point = [[nsevent window] convertBaseToScreen:point];
@@ -681,19 +505,38 @@ find_window_for_ns_event (NSEvent *nsevent,
         * the grab_window and is reported only if selected by
         * event_mask. For either value of owner_events, unreported
         * events are discarded.
-        *
-        * This means we first try the owner, then the grab window,
-        * then give up.
         */
         grab = _gdk_display_get_last_pointer_grab (display);
-       if (grab && grab->window)
+       if (grab)
          {
-           if (grab->owner_events)
-              return toplevel;
+           if ((grab->event_mask & get_event_mask_from_ns_event (nsevent)) == 0)
+              return NULL;
 
-           /* Finally check the grab window. */
-           if (grab->event_mask & get_event_mask_from_ns_event (nsevent))
-             {
+            if (grab->owner_events)
+              {
+                /* For owner events, we need to use the toplevel under the
+                 * pointer, not the window from the NSEvent, since that is
+                 * reported with respect to the key window, which could be
+                 * wrong.
+                 */
+                GdkWindow *toplevel_under_pointer;
+                gint x_tmp, y_tmp;
+
+                toplevel_under_pointer = find_toplevel_under_pointer (display,
+                                                                      screen_point,
+                                                                      &x_tmp, &y_tmp);
+                if (toplevel_under_pointer)
+                  {
+                    toplevel = toplevel_under_pointer;
+                    *x = x_tmp;
+                    *y = y_tmp;
+                  }
+
+                return toplevel;
+              }
+            else
+              {
+                /* Finally check the grab window. */
                GdkWindow *grab_toplevel;
                 GdkWindowObject *grab_private;
                 NSWindow *grab_nswindow;
@@ -701,16 +544,13 @@ find_window_for_ns_event (NSEvent *nsevent,
                grab_toplevel = gdk_window_get_toplevel (grab->window);
                 grab_private = (GdkWindowObject *)grab_toplevel;
 
-                point = [[nsevent window] convertBaseToScreen:[nsevent locationInWindow]];
-
-                grab_nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
-                point = [grab_nswindow convertScreenToBase:point];
+                grab_nswindow = ((GdkWindowImplQuartz *)grab_private->impl)->toplevel;
+                point = [grab_nswindow convertScreenToBase:screen_point];
 
+                /* Note: x_root and y_root are already right. */
                 *x = point.x;
                 *y = grab_private->height - point.y;
 
-                /* Note: x_root and y_root are already right. */
-
                return grab_toplevel;
              }
 
@@ -719,15 +559,33 @@ find_window_for_ns_event (NSEvent *nsevent,
        else 
          {
            /* The non-grabbed case. */
+            GdkWindow *toplevel_under_pointer;
+            gint x_tmp, y_tmp;
 
-            /* Leave events above the window (e.g. possibly on the titlebar)
-             * to cocoa.
+            /* Ignore all events but mouse moved that might be on the title
+             * bar (above the content view). The reason is that otherwise
+             * gdk gets confused about getting e.g. button presses with no
+             * window (the title bar is not known to it).
              */
-            if (*y < 0)
-              return NULL;
+            if (event_type != NSMouseMoved)
+              if (*y < 0)
+                return NULL;
 
             /* FIXME: Also need to leave resize events to cocoa somehow? */
 
+            /* As for owner events, we need to use the toplevel under the
+             * pointer, not the window from the NSEvent.
+             */
+            toplevel_under_pointer = find_toplevel_under_pointer (display,
+                                                                  screen_point,
+                                                                  &x_tmp, &y_tmp);
+            if (toplevel_under_pointer)
+              {
+                toplevel = toplevel_under_pointer;
+                *x = x_tmp;
+                *y = y_tmp;
+              }
+
             return toplevel;
          }
       }
@@ -735,7 +593,13 @@ find_window_for_ns_event (NSEvent *nsevent,
       
     case NSMouseEntered:
     case NSMouseExited:
-      return toplevel;
+      /* Only handle our own entered/exited events, not the ones for the
+       * titlebar buttons.
+       */
+      if ([view trackingRect] == [nsevent trackingNumber])
+        return toplevel;
+      else
+        return NULL;
 
     case NSKeyDown:
     case NSKeyUp:
@@ -1081,12 +945,6 @@ gdk_event_translate (GdkEvent *event,
   int x_root, y_root;
   gboolean return_val;
 
-  /* Ignore events altogether when we're not active, otherwise we get
-   * tooltips etc for inactive apps.
-   */
-  if (![NSApp isActive])
-    return FALSE;
-
   /* There is no support for real desktop wide grabs, so we break
    * grabs when the application loses focus (gets deactivated).
    */
@@ -1105,15 +963,6 @@ gdk_event_translate (GdkEvent *event,
       return FALSE;
     }
 
-  /* Handle our generated "fake" crossing events. */
-  if (event_type == NSApplicationDefined &&
-      [nsevent subtype] == GDK_QUARTZ_EVENT_SUBTYPE_FAKE_CROSSING)
-    {
-      /* FIXME: This needs to actually fill in the event we have... */
-      _gdk_quartz_events_trigger_crossing_events (FALSE);
-      return FALSE; /* ...and return TRUE instead. */
-    }
-
   /* Keep track of button state, since we don't get that information
    * for key events. 
    */
@@ -1191,9 +1040,10 @@ gdk_event_translate (GdkEvent *event,
        }
     }
 
-  /* We only activate the application on click if it's not already active,
-   * or if it's active but the window isn't focused. This matches most use
-   * cases of native apps (no click-through).
+  /* If the app is not active leave the event to AppKit so the window gets
+   * focused correctly and don't do click-through (so we behave like most
+   * native apps). If the app is active, we focus the window and then handle
+   * the event, also to match native apps.
    */
   if ((event_type == NSRightMouseDown ||
        event_type == NSOtherMouseDown ||
@@ -1203,9 +1053,18 @@ gdk_event_translate (GdkEvent *event,
       GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
 
       if (![NSApp isActive])
-        return FALSE;
+        {
+          [NSApp activateIgnoringOtherApps:YES];
+          return FALSE;
+        }
       else if (![impl->toplevel isKeyWindow])
-        return FALSE;
+        {
+          GdkPointerGrabInfo *grab;
+
+          grab = _gdk_display_get_last_pointer_grab (_gdk_display);
+          if (!grab)
+            [impl->toplevel makeKeyWindow];
+        }
     }
 
   current_event_mask = get_event_mask_from_ns_event (nsevent);