Use consistent coordinates in get_toplevel_from_ns_event.

[NSView frame] returns a rectangle in the superview's coordinates, and the
superview of an NSWindow's content view (which is the only NSView that
GdkQuartz instantiates) is an undocumented NSThemeFrame. While it happens
to have the same origin as the content view and the same size as the
window's frame this isn't documented and so could change without notice.
Convert the window frame coordinates to the view's coordinate system to
ensure consistency.

Use the view's bounds instead of its frame: The bounds rectangle is in the
view's coordinate system. Use the parent NSWindow's frame instead of the
private NSThemeFrame's. This ensures that all coordinate comparisons have
the same reference.

Finally, the macOS coordinate systems origin is at the bottom left, so the
title bar is between the content view's height and the window's height,
not in negative y in the view's coordinates. Adjust the y comparisons
accordingly.

Fixes #6297
This commit is contained in:
John Ralls
2023-12-25 10:52:24 -08:00
parent 26336c401a
commit 345bfb494a

View File

@@ -417,12 +417,13 @@ get_toplevel_from_ns_event (NSEvent *nsevent,
gint *y)
{
GdkWindow *toplevel = NULL;
NSWindow* nswindow = [nsevent window];
if ([nsevent window])
if (nswindow)
{
GdkQuartzView *view;
NSPoint point, view_point;
NSRect view_frame;
NSRect view_bounds;
view = (GdkQuartzView *)[[nsevent window] contentView];
@@ -430,7 +431,7 @@ get_toplevel_from_ns_event (NSEvent *nsevent,
point = [nsevent locationInWindow];
view_point = [view convertPoint:point fromView:nil];
view_frame = [view frame];
view_bounds = [view bounds];
/* 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
@@ -445,10 +446,10 @@ get_toplevel_from_ns_event (NSEvent *nsevent,
* 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))
(view_point.x < view_bounds.origin.x ||
view_point.x >= view_bounds.origin.x + view_bounds.size.width ||
view_point.y < view_bounds.origin.y ||
view_point.y >= view_bounds.origin.y + view_bounds.size.height))
{
toplevel = NULL;
@@ -468,27 +469,22 @@ get_toplevel_from_ns_event (NSEvent *nsevent,
* fallback path, which could match the window that is
* directly under the titlebar.
*/
if (view_point.y < 0 &&
view_point.x >= view_frame.origin.x &&
view_point.x < view_frame.origin.x + view_frame.size.width)
if (view_point.y > view_bounds.origin.y + view_bounds.size.height &&
view_point.x >= view_bounds.origin.x &&
view_point.x < view_bounds.origin.x + view_bounds.size.width)
{
NSView *superview = [view superview];
if (superview)
NSRect window_frame = [view convertRect: [nswindow frame]
fromView: nil];
if (view_point.y <=
view_bounds.origin.y + window_frame.size.height)
{
NSRect superview_frame = [superview frame];
int titlebar_height = superview_frame.size.height -
view_frame.size.height;
if (titlebar_height > 0 && view_point.y >= -titlebar_height)
{
return NULL;
}
return NULL;
}
}
}
else
{
*screen_point = [(GdkQuartzNSWindow*)[nsevent window] convertPointToScreen:point];
*screen_point = [(GdkQuartzNSWindow*)nswindow convertPointToScreen:point];
*x = point.x;
*y = toplevel->height - point.y;
}