From e643977b6b99466bfa872b61a4101d9937615876 Mon Sep 17 00:00:00 2001 From: Anders Lindgren Date: Tue, 22 Mar 2016 20:18:33 +0100 Subject: [PATCH] Make `toggle-frame-maximized' respect the dock on OS X (bug#22988). * src/nsterm.m (ns_screen_margins): New function. (ns_screen_margins_ignoring_hidden_dock): New function. (ns_menu_bar_height): Reimplement in terms of `ns_screen_margins'. ([EmacsWindow zoom:]): Take all screen margins (except those originating from a hidden dock) into account. --- src/nsterm.m | 142 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 120 insertions(+), 22 deletions(-) diff --git a/src/nsterm.m b/src/nsterm.m index b796193af7..4048ac4654 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -646,42 +646,129 @@ ns_release_autorelease_pool (void *pool) } -/* True, if the menu bar should be hidden. */ - static BOOL ns_menu_bar_should_be_hidden (void) +/* True, if the menu bar should be hidden. */ { return !NILP (ns_auto_hide_menu_bar) && [NSApp respondsToSelector:@selector(setPresentationOptions:)]; } -static CGFloat -ns_menu_bar_height (NSScreen *screen) -/* The height of the menu bar, if visible. +struct EmacsMargins +{ + CGFloat top; + CGFloat bottom; + CGFloat left; + CGFloat right; +}; - Note: Don't use this when fullscreen is enabled -- the screen - sometimes includes, sometimes excludes the menu bar area. */ + +static struct EmacsMargins +ns_screen_margins (NSScreen *screen) +/* The parts of SCREEN used by the operating system. */ { - CGFloat res; + NSTRACE ("ns_screen_margins"); + + struct EmacsMargins margins; + + NSRect screenFrame = [screen frame]; + NSRect screenVisibleFrame = [screen visibleFrame]; + /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden + menu bar, check this explicitly. */ if (ns_menu_bar_should_be_hidden()) { - res = 0; + margins.top = 0; } else { - NSRect screenFrame = [screen frame]; - NSRect screenVisibleFrame = [screen visibleFrame]; - CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height; CGFloat visibleFrameTop = (screenVisibleFrame.origin.y + screenVisibleFrame.size.height); - res = frameTop - visibleFrameTop; + margins.top = frameTop - visibleFrameTop; + } + + { + CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width; + CGFloat visibleFrameRight = (screenVisibleFrame.origin.x + + screenVisibleFrame.size.width); + margins.right = frameRight - visibleFrameRight; + } + + margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y; + margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x; + NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g", + margins.left, + margins.right, + margins.top, + margins.bottom); + + return margins; +} + + +/* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is + assumed to contain a hidden dock. OS X currently use 4 pixels for + this, however, to be future compatible, a larger value is used. */ +#define DOCK_IGNORE_LIMIT 6 + +static struct EmacsMargins +ns_screen_margins_ignoring_hidden_dock (NSScreen *screen) +/* The parts of SCREEN used by the operating system, excluding the parts +reserved for an hidden dock. */ +{ + NSTRACE ("ns_screen_margins_ignoring_hidden_dock"); + + struct EmacsMargins margins = ns_screen_margins(screen); + + /* OS X (currently) reserved 4 pixels along the edge where a hidden + dock is located. Unfortunately, it's not possible to find the + location and information about if the dock is hidden. Instead, + it is assumed that if the margin of an edge is less than + DOCK_IGNORE_LIMIT, it contains a hidden dock. */ + if (margins.left <= DOCK_IGNORE_LIMIT) + { + margins.left = 0; + } + if (margins.right <= DOCK_IGNORE_LIMIT) + { + margins.right = 0; + } + if (margins.top <= DOCK_IGNORE_LIMIT) + { + margins.top = 0; + } + /* Note: This doesn't occur in current versions of OS X, but + included for completeness and future compatibility. */ + if (margins.bottom <= DOCK_IGNORE_LIMIT) + { + margins.bottom = 0; } + NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g", + margins.left, + margins.right, + margins.top, + margins.bottom); + + return margins; +} + + +static CGFloat +ns_menu_bar_height (NSScreen *screen) +/* The height of the menu bar, if visible. + + Note: Don't use this when fullscreen is enabled -- the screen + sometimes includes, sometimes excludes the menu bar area. */ +{ + struct EmacsMargins margins = ns_screen_margins(screen); + + CGFloat res = margins.top; + NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res); return res; @@ -7867,9 +7954,10 @@ not_in_argv (NSString *arg) // the menu-bar. [super zoom:sender]; -#elsif 0 +#elif 0 // Native zoom done using the standard zoom animation, plus an - // explicit resize to cover the full screen. + // explicit resize to cover the full screen, except the menu-bar and + // dock, if present. [super zoom:sender]; // After the native zoom, resize the resulting frame to fill the @@ -7889,6 +7977,9 @@ not_in_argv (NSString *arg) NSTRACE_FSTYPE ("fullscreenState", fs_state); NSRect sr = [screen frame]; + struct EmacsMargins margins + = ns_screen_margins_ignoring_hidden_dock(screen); + NSRect wr = [self frame]; NSTRACE_RECT ("Rect after zoom", wr); @@ -7897,15 +7988,15 @@ not_in_argv (NSString *arg) if (fs_state == FULLSCREEN_MAXIMIZED || fs_state == FULLSCREEN_HEIGHT) { - newWr.origin.x = 0; - newWr.size.height = sr.size.height - ns_menu_bar_height(screen); + newWr.origin.y = sr.origin.y + margins.bottom; + newWr.size.height = sr.size.height - margins.top - margins.bottom; } if (fs_state == FULLSCREEN_MAXIMIZED || fs_state == FULLSCREEN_WIDTH) { - newWr.origin.y = 0; - newWr.size.width = sr.size.width; + newWr.origin.x = sr.origin.x + margins.left; + newWr.size.width = sr.size.width - margins.right - margins.left; } if (newWr.size.width != wr.size.width @@ -7918,13 +8009,20 @@ not_in_argv (NSString *arg) } } #else - // Non-native zoom which is done instantaneously. The resulting frame - // covers the entire screen, except the menu-bar, if present. + // Non-native zoom which is done instantaneously. The resulting + // frame covers the entire screen, except the menu-bar and dock, if + // present. NSScreen * screen = [self screen]; if (screen != nil) { NSRect sr = [screen frame]; - sr.size.height -= ns_menu_bar_height (screen); + struct EmacsMargins margins + = ns_screen_margins_ignoring_hidden_dock(screen); + + sr.size.height -= (margins.top + margins.bottom); + sr.size.width -= (margins.left + margins.right); + sr.origin.x += margins.left; + sr.origin.y += margins.bottom; sr = [[self delegate] windowWillUseStandardFrame:self defaultFrame:sr]; -- 2.39.2