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 *
}
}
-/* 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
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];
* 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;
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;
}
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;
}
}
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:
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).
*/
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.
*/
}
}
- /* 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 ||
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);