From 0e4db3d79ebd4ee7b6b54fb8920ea1a57c8e1951 Mon Sep 17 00:00:00 2001 From: Yee Cheng Chin Date: Sun, 8 Jul 2018 02:49:37 -0700 Subject: [PATCH 1/3] Support guioptions 'k' flag in MacVim, prevents unnecessary window resize Adds support for native GVim's 'k' flag. Adding/removing tabs/scrollbars and setting 'linespace'/'columnspace' would now cause the number of lines and columns in the buffer change to keep the window size constant, instead of the other way round of resizing the window to keep the view size constant. This helps prevent the window from resizing itself unncessarily, which could be especially annoying when the window is pinned/maximized. Manually setting 'lines'/'columns', going to full screen, dragging the window corner to resize would still resize the window. Also removed misc calls within MMWindowController.m that were setting shouldResizeVimView. Those calls were already handled by native Vim's gui.c's gui_set_shellsize so it's redundant. rebased from 1333bc6c2 --- src/MacVim/MMBackend.h | 1 + src/MacVim/MMBackend.m | 8 ++++++ src/MacVim/MMVimController.m | 6 ++++ src/MacVim/MMVimView.h | 1 + src/MacVim/MMVimView.m | 21 ++++++++++---- src/MacVim/MMWindowController.h | 3 ++ src/MacVim/MMWindowController.m | 49 +++++++++++++++++++++------------ src/MacVim/MacVim.h | 2 ++ src/MacVim/MacVim.m | 2 ++ src/MacVim/gui_macvim.m | 12 ++++++++ src/gui.c | 10 +++++++ src/proto/gui_macvim.pro | 2 ++ 12 files changed, 95 insertions(+), 22 deletions(-) diff --git a/src/MacVim/MMBackend.h b/src/MacVim/MMBackend.h index 733578af76..bbebc7e24e 100644 --- a/src/MacVim/MMBackend.h +++ b/src/MacVim/MMBackend.h @@ -105,6 +105,7 @@ extern NSTimeInterval MMBalloonEvalInternalDelay; - (BOOL)tabBarVisible; - (void)showTabBar:(BOOL)enable; - (void)setRows:(int)rows columns:(int)cols; +- (void)resizeView; - (void)setWindowTitle:(char *)title; - (void)setDocumentFilename:(char *)filename; - (char *)browseForFileWithAttributes:(NSDictionary *)attr; diff --git a/src/MacVim/MMBackend.m b/src/MacVim/MMBackend.m index 5b5dd2a3d2..2146fb53ee 100644 --- a/src/MacVim/MMBackend.m +++ b/src/MacVim/MMBackend.m @@ -836,6 +836,11 @@ - (void)setRows:(int)rows columns:(int)cols [self queueMessage:SetTextDimensionsMsgID data:data]; } +- (void)resizeView +{ + [self queueMessage:ResizeViewMsgID data:nil]; +} + - (void)setWindowTitle:(char *)title { NSMutableData *data = [NSMutableData data]; @@ -1997,6 +2002,7 @@ - (void)handleInputEvent:(int)msgid data:(NSData *)data tabpage_move(idx); } else if (SetTextDimensionsMsgID == msgid || LiveResizeMsgID == msgid + || SetTextDimensionsNoResizeWindowMsgID == msgid || SetTextRowsMsgID == msgid || SetTextColumnsMsgID == msgid) { if (!data) return; const void *bytes = [data bytes]; @@ -2028,6 +2034,8 @@ - (void)handleInputEvent:(int)msgid data:(NSData *)data [self queueMessage:msgid data:d]; gui_resize_shell(cols, rows); + } else if (ResizeViewMsgID == msgid) { + [self queueMessage:msgid data:data]; } else if (ExecuteMenuMsgID == msgid) { NSDictionary *attrs = [NSDictionary dictionaryWithData:data]; if (attrs) { diff --git a/src/MacVim/MMVimController.m b/src/MacVim/MMVimController.m index 4f496d9d50..ea3311a8c7 100644 --- a/src/MacVim/MMVimController.m +++ b/src/MacVim/MMVimController.m @@ -629,6 +629,7 @@ - (void)handleMessage:(int)msgid data:(NSData *)data [windowController showTabBar:NO]; [self sendMessage:BackingPropertiesChangedMsgID data:nil]; } else if (SetTextDimensionsMsgID == msgid || LiveResizeMsgID == msgid || + SetTextDimensionsNoResizeWindowMsgID == msgid || SetTextDimensionsReplyMsgID == msgid) { const void *bytes = [data bytes]; int rows = *((int*)bytes); bytes += sizeof(int); @@ -638,11 +639,16 @@ - (void)handleMessage:(int)msgid data:(NSData *)data // acknowledges it with a reply message. When this happens the window // should not move (the frontend would already have moved the window). BOOL onScreen = SetTextDimensionsReplyMsgID!=msgid; + + BOOL keepGUISize = SetTextDimensionsNoResizeWindowMsgID == msgid; [windowController setTextDimensionsWithRows:rows columns:cols isLive:(LiveResizeMsgID==msgid) + keepGUISize:keepGUISize keepOnScreen:onScreen]; + } else if (ResizeViewMsgID == msgid) { + [windowController resizeView]; } else if (SetWindowTitleMsgID == msgid) { const void *bytes = [data bytes]; int len = *((int*)bytes); bytes += sizeof(int); diff --git a/src/MacVim/MMVimView.h b/src/MacVim/MMVimView.h index 5a8335ed1e..8ecaa24b2c 100644 --- a/src/MacVim/MMVimView.h +++ b/src/MacVim/MMVimView.h @@ -55,6 +55,7 @@ - (void)viewWillStartLiveResize; - (void)viewDidEndLiveResize; - (void)setFrameSize:(NSSize)size; +- (void)setFrameSizeKeepGUISize:(NSSize)size; - (void)setFrame:(NSRect)frame; @end diff --git a/src/MacVim/MMVimView.m b/src/MacVim/MMVimView.m index fd04c47e5b..6202a186f3 100644 --- a/src/MacVim/MMVimView.m +++ b/src/MacVim/MMVimView.m @@ -60,7 +60,7 @@ - (MMScroller *)scrollbarForIdentifier:(int32_t)ident index:(unsigned *)idx; - (NSSize)vimViewSizeForTextViewSize:(NSSize)textViewSize; - (NSRect)textViewRectForVimViewSize:(NSSize)contentSize; - (NSTabView *)tabView; -- (void)frameSizeMayHaveChanged; +- (void)frameSizeMayHaveChanged:(BOOL)keepGUISize; @end @@ -610,14 +610,25 @@ - (void)setFrameSize:(NSSize)size // row will result in the vim view holding more rows than the can fit // inside the window.) [super setFrameSize:size]; - [self frameSizeMayHaveChanged]; + [self frameSizeMayHaveChanged:NO]; +} + +- (void)setFrameSizeKeepGUISize:(NSSize)size +{ + // NOTE: Instead of only acting when a frame was resized, we do some + // updating each time a frame may be resized. (At the moment, if we only + // respond to actual frame changes then typing ":set lines=1000" twice in a + // row will result in the vim view holding more rows than the can fit + // inside the window.) + [super setFrameSize:size]; + [self frameSizeMayHaveChanged:YES]; } - (void)setFrame:(NSRect)frame { // See comment in setFrameSize: above. [super setFrame:frame]; - [self frameSizeMayHaveChanged]; + [self frameSizeMayHaveChanged:NO]; } @end // MMVimView @@ -867,7 +878,7 @@ - (NSTabView *)tabView return tabView; } -- (void)frameSizeMayHaveChanged +- (void)frameSizeMayHaveChanged:(BOOL)keepGUISize { // NOTE: Whenever a call is made that may have changed the frame size we // take the opportunity to make sure all subviews are in place and that the @@ -903,7 +914,7 @@ - (void)frameSizeMayHaveChanged if (constrained[0] != rows || constrained[1] != cols) { NSData *data = [NSData dataWithBytes:constrained length:2*sizeof(int)]; int msgid = [self inLiveResize] ? LiveResizeMsgID - : SetTextDimensionsMsgID; + : (keepGUISize ? SetTextDimensionsNoResizeWindowMsgID : SetTextDimensionsMsgID); ASLogDebug(@"Notify Vim that text dimensions changed from %dx%d to " "%dx%d (%s)", cols, rows, constrained[1], constrained[0], diff --git a/src/MacVim/MMWindowController.h b/src/MacVim/MMWindowController.h index 8c92ed537d..5e97478f9a 100644 --- a/src/MacVim/MMWindowController.h +++ b/src/MacVim/MMWindowController.h @@ -24,6 +24,7 @@ BOOL setupDone; BOOL windowPresented; BOOL shouldResizeVimView; + BOOL shouldKeepGUISize; BOOL shouldRestoreUserTopLeft; BOOL shouldMaximizeWindow; int updateToolbarFlag; @@ -59,7 +60,9 @@ - (void)updateTabsWithData:(NSData *)data; - (void)selectTabWithIndex:(int)idx; - (void)setTextDimensionsWithRows:(int)rows columns:(int)cols isLive:(BOOL)live + keepGUISize:(BOOL)keepGUISize keepOnScreen:(BOOL)onScreen; +- (void)resizeView; - (void)zoomWithRows:(int)rows columns:(int)cols state:(int)state; - (void)setTitle:(NSString *)title; - (void)setDocumentFilename:(NSString *)filename; diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index ae335811f4..a9437379ef 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -174,7 +174,7 @@ - (id)initWithVimController:(MMVimController *)controller [win setDelegate:self]; [win setInitialFirstResponder:[vimView textView]]; - + if ([win styleMask] & NSWindowStyleMaskTexturedBackground) { // On Leopard, we want to have a textured window to have nice // looking tabs. But the textured window look implies rounded @@ -381,6 +381,7 @@ - (void)selectTabWithIndex:(int)idx } - (void)setTextDimensionsWithRows:(int)rows columns:(int)cols isLive:(BOOL)live + keepGUISize:(BOOL)keepGUISize keepOnScreen:(BOOL)onScreen { ASLogDebug(@"setTextDimensionsWithRows:%d columns:%d isLive:%d " @@ -399,7 +400,7 @@ - (void)setTextDimensionsWithRows:(int)rows columns:(int)cols isLive:(BOOL)live [vimView setDesiredRows:rows columns:cols]; - if (setupDone && !live) { + if (setupDone && !live && !keepGUISize) { shouldResizeVimView = YES; keepOnScreen = onScreen; } @@ -428,6 +429,15 @@ - (void)setTextDimensionsWithRows:(int)rows columns:(int)cols isLive:(BOOL)live } } +- (void)resizeView +{ + if (setupDone) + { + shouldResizeVimView = YES; + shouldKeepGUISize = YES; + } +} + - (void)zoomWithRows:(int)rows columns:(int)cols state:(int)state { [self setTextDimensionsWithRows:rows @@ -503,9 +513,6 @@ - (void)createScrollbarWithIdentifier:(int32_t)ident type:(int)type - (BOOL)destroyScrollbarWithIdentifier:(int32_t)ident { BOOL scrollbarHidden = [vimView destroyScrollbarWithIdentifier:ident]; - shouldResizeVimView = shouldResizeVimView || scrollbarHidden; - shouldMaximizeWindow = shouldMaximizeWindow || scrollbarHidden; - return scrollbarHidden; } @@ -513,9 +520,6 @@ - (BOOL)showScrollbarWithIdentifier:(int32_t)ident state:(BOOL)visible { BOOL scrollbarToggled = [vimView showScrollbarWithIdentifier:ident state:visible]; - shouldResizeVimView = shouldResizeVimView || scrollbarToggled; - shouldMaximizeWindow = shouldMaximizeWindow || scrollbarToggled; - return scrollbarToggled; } @@ -600,7 +604,18 @@ - (void)processInputQueueDidFinish fullScreenWindow ? [fullScreenWindow frame].size : fullScreenEnabled ? desiredWindowSize : [self constrainContentSizeToScreenSize:[vimView desiredSize]]]; - [vimView setFrameSize:contentSize]; + + // Setting 'guioptions+=k' will make shouldKeepGUISize true, which + // means avoid resizing the window. Instead, resize the view instead + // to keep the GUI window's size consistent. + bool avoidWindowResize = shouldKeepGUISize && !fullScreenEnabled; + + if (!avoidWindowResize) { + [vimView setFrameSize:contentSize]; + } + else { + [vimView setFrameSizeKeepGUISize:originalSize]; + } if (fullScreenWindow) { // NOTE! Don't mark the full-screen content view as needing an @@ -613,12 +628,15 @@ - (void)processInputQueueDidFinish [fullScreenWindow centerView]; } } else { - [self resizeWindowToFitContentSize:contentSize - keepOnScreen:keepOnScreen]; + if (!avoidWindowResize) { + [self resizeWindowToFitContentSize:contentSize + keepOnScreen:keepOnScreen]; + } } } keepOnScreen = NO; + shouldKeepGUISize = NO; } } @@ -657,7 +675,6 @@ - (void)adjustLinespace:(int)linespace { if (vimView && [vimView textView]) { [[vimView textView] setLinespace:(float)linespace]; - shouldMaximizeWindow = shouldResizeVimView = YES; } } @@ -665,7 +682,6 @@ - (void)adjustColumnspace:(int)columnspace { if (vimView && [vimView textView]) { [[vimView textView] setColumnspace:(float)columnspace]; - shouldMaximizeWindow = shouldResizeVimView = YES; } } @@ -1187,7 +1203,7 @@ - (void)window:(NSWindow *)window [[window animator] setAlphaValue:0]; } completionHandler:^{ [self maximizeWindow:fullScreenOptions]; - + // Fade in [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) { [context setDuration:0.5*duration]; @@ -1206,7 +1222,7 @@ - (void)windowWillEnterFullScreen:(NSNotification *)notification // The separator should never be visible in fullscreen or split-screen. [decoratedWindow hideTablineSeparator:YES]; - + // ASSUMPTION: fullScreenEnabled always reflects the state of Vim's 'fu'. if (!fullScreenEnabled) { ASLogDebug(@"Full-screen out of sync, tell Vim to set 'fu'"); @@ -1308,7 +1324,7 @@ - (void)windowDidExitFullScreen:(NSNotification *)notification // full-screen by moving the window out from Split View. [vimController sendMessage:BackingPropertiesChangedMsgID data:nil]; } - + [self updateTablineSeparator]; } @@ -1536,7 +1552,6 @@ - (void)hideTablineSeparator:(BOOL)hide // The tabline separator was toggled so the content view must change // size. [self updateResizeConstraints]; - shouldResizeVimView = YES; } } diff --git a/src/MacVim/MacVim.h b/src/MacVim/MacVim.h index 904acf7015..118dac889c 100644 --- a/src/MacVim/MacVim.h +++ b/src/MacVim/MacVim.h @@ -176,8 +176,10 @@ enum { SetTextRowsMsgID, SetTextColumnsMsgID, SetTextDimensionsMsgID, + SetTextDimensionsNoResizeWindowMsgID, LiveResizeMsgID, SetTextDimensionsReplyMsgID, + ResizeViewMsgID, SetWindowTitleMsgID, ScrollWheelMsgID, MouseDownMsgID, diff --git a/src/MacVim/MacVim.m b/src/MacVim/MacVim.m index b9fdeb43c9..6390a29139 100644 --- a/src/MacVim/MacVim.m +++ b/src/MacVim/MacVim.m @@ -30,8 +30,10 @@ "SetTextRowsMsgID", "SetTextColumnsMsgID", "SetTextDimensionsMsgID", + "SetTextDimensionsNoResizeWindowMsgID", "LiveResizeMsgID", "SetTextDimensionsReplyMsgID", + "ResizeViewMsgID", "SetWindowTitleMsgID", "ScrollWheelMsgID", "MouseDownMsgID", diff --git a/src/MacVim/gui_macvim.m b/src/MacVim/gui_macvim.m index 4c7c8b3701..ce2239122f 100644 --- a/src/MacVim/gui_macvim.m +++ b/src/MacVim/gui_macvim.m @@ -1739,6 +1739,18 @@ } +/* + * Re-calculates size of the Vim view to fit within the window without having + * to resize the window. Usually happens after UI elements have changed (e.g. + * adding / removing a toolbar) when guioptions 'k' is set. + */ + void +gui_mch_resize_view() +{ + [[MMBackend sharedInstance] resizeView]; +} + + /* * Set the position of the top left corner of the window to the given * coordinates. diff --git a/src/gui.c b/src/gui.c index e4a874589d..323dd6e362 100644 --- a/src/gui.c +++ b/src/gui.c @@ -1621,6 +1621,16 @@ gui_set_shellsize( } #endif +#ifdef FEAT_GUI_MACVIM + if (!mustset && (vim_strchr(p_go, GO_KEEPWINSIZE) != NULL)) + { + /* We don't want to resize the window, so instruct the GUI to resize + * the view to be within the constraints of the current window's size */ + gui_mch_resize_view(); + return; + } +#endif + base_width = gui_get_base_width(); base_height = gui_get_base_height(); if (fit_to_display) diff --git a/src/proto/gui_macvim.pro b/src/proto/gui_macvim.pro index dd75a6f2b3..8fdab4ef70 100644 --- a/src/proto/gui_macvim.pro +++ b/src/proto/gui_macvim.pro @@ -174,6 +174,8 @@ gui_mch_set_shellsize( int base_height, int direction); void +gui_mch_resize_view(); + void gui_mch_set_sp_color(guicolor_T color); void gui_mch_set_text_area_pos(int x, int y, int w, int h); From 0065c3fd3be1034e6844a0f36eee6395aab0d829 Mon Sep 17 00:00:00 2001 From: Yee Cheng Chin Date: Sat, 11 Aug 2018 20:43:13 -0700 Subject: [PATCH 2/3] Fix up the previous MacVim's guioptions 'k' implementation Fix the following: * Zoom button: There was an error in refactoring leading to the handler calling the wrong function. * Toolbar addition/removal: This now respects the 'k' option. Toolbar is different from scrollbar and tabs because when you add/remove a toolbar in Cocoa it automatically resizes the window for you, so the implementation needs to manually un-resize the window and re-calculates the Vim view's 'lines' and 'columns' to fit. --- src/MacVim/MMWindowController.m | 42 +++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index a9437379ef..5f8b5058b5 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -385,7 +385,8 @@ - (void)setTextDimensionsWithRows:(int)rows columns:(int)cols isLive:(BOOL)live keepOnScreen:(BOOL)onScreen { ASLogDebug(@"setTextDimensionsWithRows:%d columns:%d isLive:%d " - "keepOnScreen:%d", rows, cols, live, onScreen); + "keepGUISize:%d " + "keepOnScreen:%d", rows, cols, live, keepGUISize, onScreen); // NOTE: The only place where the (rows,columns) of the vim view are // modified is here and when entering/leaving full-screen. Setting these @@ -443,6 +444,7 @@ - (void)zoomWithRows:(int)rows columns:(int)cols state:(int)state [self setTextDimensionsWithRows:rows columns:cols isLive:NO + keepGUISize:NO keepOnScreen:YES]; // NOTE: If state==0 then the window should be put in the non-zoomed @@ -662,6 +664,10 @@ - (void)showToolbar:(BOOL)on size:(int)size mode:(int)mode // showing its hide animation every time a new window is opened. (See // processInputQueueDidFinish for the reason why we need to delay toggling // the toolbar when the window is visible.) + // + // Also, the delayed updateToolbar will have the correct shouldKeepGUISize + // set when it's called, which is important for that function to respect + // guioptions 'k'. if (![decoratedWindow isVisible]) [self updateToolbar]; } @@ -1055,7 +1061,14 @@ - (void)windowDidResize:(id)sender // may resize automatically) we simply set the view to fill the entire // window. The vim view takes care of notifying Vim if the number of // (rows,columns) changed. - [vimView setFrameSize:[self contentSize]]; + if (shouldKeepGUISize) { + // This happens when code manually call setFrame: when we are performing + // an operation that wants to preserve GUI size (e.g. in updateToolbar:). + // Respect the wish, and pass that along. + [vimView setFrameSizeKeepGUISize:[self contentSize]]; + } else { + [vimView setFrameSize:[self contentSize]]; + } } - (void)windowDidChangeBackingProperties:(NSNotification *)notification @@ -1607,7 +1620,32 @@ - (void)updateToolbar // Positive flag shows toolbar, negative hides it. BOOL on = updateToolbarFlag > 0 ? YES : NO; + + NSRect origWindowFrame = [decoratedWindow frame]; + BOOL origHasToolbar = decoratedWindow.toolbar != nil; + [decoratedWindow setToolbar:(on ? toolbar : nil)]; + + if (shouldKeepGUISize && !fullScreenEnabled && origHasToolbar != on) { + // "shouldKeepGUISize" means guioptions has 'k' in it, indicating that user doesn't + // want the window to resize itself. In non-fullscreen when we call setToolbar: + // Cocoa automatically resizes the window so we need to un-resize it back to + // original. + + NSRect newWindowFrame = [decoratedWindow frame]; + if (newWindowFrame.size.height == origWindowFrame.size.height) { + // This is an odd case here, where the window has not changed size at all. + // The addition/removal of toolbar should have changed its size. This means that + // there isn't enough space to grow the window on the screen. Usually we rely + // on windowDidResize: to call setFrameSizeKeepGUISize for us but now we have + // to do it manually in this special case. + [vimView setFrameSizeKeepGUISize:[self contentSize]]; + } + else { + [decoratedWindow setFrame:origWindowFrame display:YES]; + } + } + [self updateTablineSeparator]; updateToolbarFlag = 0; From e35b0a69a7dc35cc4af85fbbce8160ed0ff8ea9c Mon Sep 17 00:00:00 2001 From: Yee Cheng Chin Date: Sat, 18 Aug 2018 20:36:07 -0700 Subject: [PATCH 3/3] Fix opening window in another screen resulting in broken rendering Fix the issue that MacVim's window will have broken rendering (wrong Vim size) if the window was opened in another monitor. This was introduced as part of the implementation for guioptions 'k', The issue was that the function `moveWindowAcrossScreens` was buggy. It sets a flag "resizingDueToMove" but doesn't unset it after the `setFrameTopLeftPoint`, which may or may not call the resize function that is responsible in unsetting "resizeDueToMove". Fix the function to always unset it so that the flag doesn't leak till the next resize. Previously it "worked" due to MacVim's excessive resize messages masking the issue. --- src/MacVim/MMWindowController.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index 5f8b5058b5..1003d3b451 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -363,11 +363,9 @@ - (void)moveWindowAcrossScreens:(NSPoint)topLeft // HACK! This method moves a window to a new origin and to a different // screen. This is primarily useful to avoid a scenario where such a move // will trigger a resize, even though the frame didn't actually change size. - // This method should not be called unless the new origin is definitely on - // a different screen, otherwise the next legitimate resize message will - // be skipped. resizingDueToMove = YES; [[self window] setFrameTopLeftPoint:topLeft]; + resizingDueToMove = NO; } - (void)updateTabsWithData:(NSData *)data