From 73b5d1837cec70db12c324ed1eaf556ae0d0bb47 Mon Sep 17 00:00:00 2001 From: Bjorn Winckler Date: Sun, 29 Mar 2009 16:35:47 +0200 Subject: [PATCH] Validate screen before constraining window If a window is on a screen that gets unplugged it may happen that [NSWindow screen] returns nil. Guard against this when constraining the window frame to the screen frame. This fixes a bug where a window could "disappear" if it was on a screen that got unplugged. --- src/MacVim/MMAppController.m | 33 +++++++++++++--------- src/MacVim/MMWindow.m | 12 +++++++- src/MacVim/MMWindowController.m | 50 ++++++++++++++++++++------------- 3 files changed, 60 insertions(+), 35 deletions(-) diff --git a/src/MacVim/MMAppController.m b/src/MacVim/MMAppController.m index 7b05074144..114eb2d3d8 100644 --- a/src/MacVim/MMAppController.m +++ b/src/MacVim/MMAppController.m @@ -676,21 +676,26 @@ fsEventCallback(ConstFSEventStreamRef streamRef, [win setFrameTopLeftPoint:topLeft]; - NSPoint screenOrigin = [[win screen] frame].origin; - if ([win frame].origin.y < screenOrigin.y) { - // Try to avoid shifting the new window downwards if it means that - // the bottom of the window will be off the screen. E.g. if the - // user has set windows to open maximized in the vertical direction - // then the new window will cascade horizontally only. - topLeft.y = oldTopLeft.y; - [win setFrameTopLeftPoint:topLeft]; - } + if ([win screen]) { + NSPoint screenOrigin = [[win screen] frame].origin; + if ([win frame].origin.y < screenOrigin.y) { + // Try to avoid shifting the new window downwards if it means + // that the bottom of the window will be off the screen. E.g. + // if the user has set windows to open maximized in the + // vertical direction then the new window will cascade + // horizontally only. + topLeft.y = oldTopLeft.y; + [win setFrameTopLeftPoint:topLeft]; + } - if ([win frame].origin.y < screenOrigin.y) { - // Move the window to the top of the screen if the bottom of the - // window is still obscured. - topLeft.y = NSMaxY([[win screen] frame]); - [win setFrameTopLeftPoint:topLeft]; + if ([win frame].origin.y < screenOrigin.y) { + // Move the window to the top of the screen if the bottom of + // the window is still obscured. + topLeft.y = NSMaxY([[win screen] frame]); + [win setFrameTopLeftPoint:topLeft]; + } + } else { + NSLog(@"[%s] WINDOW NOT ON SCREEN, don't constrain position", _cmd); } } diff --git a/src/MacVim/MMWindow.m b/src/MacVim/MMWindow.m index c3c32626f8..66b6f972c9 100644 --- a/src/MacVim/MMWindow.m +++ b/src/MacVim/MMWindow.m @@ -142,8 +142,18 @@ - (IBAction)zoom:(id)sender { + NSScreen *screen = [self screen]; + if (!screen) { + NSLog(@"[%s] WINDOW NOT ON SCREEN, zoom to main screen", _cmd); + screen = [NSScreen mainScreen]; + if (!screen) { + NSLog(@"[%s] NO MAIN SCREEN, abort zoom", _cmd); + return; + } + } + NSRect frame = [self frame]; - NSRect defaultFrame = [[self screen] visibleFrame]; + NSRect defaultFrame = [screen visibleFrame]; defaultFrame = [[self delegate] windowWillUseStandardFrame:self defaultFrame:defaultFrame]; diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index 0a2616b291..6d00d298ef 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -762,7 +762,10 @@ - (void)windowDidMove:(NSNotification *)notification { - if (setupDone && windowAutosaveKey) { + if (!setupDone) + return; + + if (windowAutosaveKey) { NSRect frame = [decoratedWindow frame]; NSPoint topLeft = { frame.origin.x, NSMaxY(frame) }; NSString *topLeftString = NSStringFromPoint(topLeft); @@ -779,6 +782,8 @@ // size in updateResizeConstraints since the screen's visible frame may // change at any time (dock could move, resolution could change, window // could be moved to another screen, ...). + if (![win screen]) + return proposedFrameSize; // NOTE: Not called in full-screen mode so use "visibleFrame" instead of // "frame". @@ -898,26 +903,28 @@ NSRect newFrame = [decoratedWindow frameRectForContentRect:contentRect]; - // Ensure that the window fits inside the visible part of the screen. - // NOTE: Not called in full-screen mode so use "visisbleFrame' instead of - // "frame". - NSRect maxFrame = [[decoratedWindow screen] visibleFrame]; - maxFrame = [self constrainFrame:maxFrame]; + if ([decoratedWindow screen]) { + // Ensure that the window fits inside the visible part of the screen. + // NOTE: Not called in full-screen mode so use "visibleFrame' instead + // of "frame". + NSRect maxFrame = [[decoratedWindow screen] visibleFrame]; + maxFrame = [self constrainFrame:maxFrame]; - if (newFrame.size.width > maxFrame.size.width) { - newFrame.size.width = maxFrame.size.width; - newFrame.origin.x = maxFrame.origin.x; - } - if (newFrame.size.height > maxFrame.size.height) { - newFrame.size.height = maxFrame.size.height; - newFrame.origin.y = maxFrame.origin.y; - } - - if (onScreen) { - if (newFrame.origin.y < maxFrame.origin.y) + if (newFrame.size.width > maxFrame.size.width) { + newFrame.size.width = maxFrame.size.width; + newFrame.origin.x = maxFrame.origin.x; + } + if (newFrame.size.height > maxFrame.size.height) { + newFrame.size.height = maxFrame.size.height; newFrame.origin.y = maxFrame.origin.y; - if (NSMaxX(newFrame) > NSMaxX(maxFrame)) - newFrame.origin.x = NSMaxX(maxFrame) - newFrame.size.width; + } + + if (onScreen) { + if (newFrame.origin.y < maxFrame.origin.y) + newFrame.origin.y = maxFrame.origin.y; + if (NSMaxX(newFrame) > NSMaxX(maxFrame)) + newFrame.origin.x = NSMaxX(maxFrame) - newFrame.size.width; + } } [decoratedWindow setFrame:newFrame display:YES]; @@ -925,10 +932,13 @@ - (NSSize)constrainContentSizeToScreenSize:(NSSize)contentSize { + NSWindow *win = [self window]; + if (![win screen]) + return contentSize; + // NOTE: This may be called in both windowed and full-screen mode. The // "visibleFrame" method does not overlap menu and dock so should not be // used in full-screen. - NSWindow *win = [self window]; NSRect screenRect = fullscreenEnabled ? [[win screen] frame] : [[win screen] visibleFrame]; NSRect rect = [win contentRectForFrameRect:screenRect];