From 3fb41ccae8bd217353178196b52c24759aa47db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sidney=20San=20Mart=C3=ADn?= Date: Fri, 31 Mar 2017 13:20:41 -0400 Subject: [PATCH] Fix flashing during window resizing. The root cause of flashing/flickering was that on each resize event, AppKit called drawRect: on the MMCoreTextView, expecting it to fill an empty, newly-sized buffer with content. It has nothing to draw, so the view would show up as black until the BatchDrawMsgID reply arrived from the backend and triggered another draw. (The MMCoreTextView was display:ed twice for each resize). This change does three things: 1. Implements -[MMCoreTextView setFrameSize:] to begin an NSAnimationContext grouping before calling super, which postpones display:/drawRect: until the grouping ends, and ends the grouping in performBatchDrawWithData:. 2. Makes *all* resize messages sent to the backend synchronous, with a 1s timeout. This seems bad, but actually helps avoid spamming the backend with resize events, since the app only generates resize events as fast as we handle them (i.e. if we take time to process one resize, then the next resize event will have the current size of the window, potentially skipping a bunch in the middle that the backend never would have had time to handle). 3. Gets rid of some hacks resolved by 1 and 2, like MKVimController delaying the call to -[MMWindowController presentWindow:]. --- src/MacVim/MMCoreTextView.h | 2 ++ src/MacVim/MMCoreTextView.m | 17 ++++++++++++----- src/MacVim/MMVimController.m | 12 +++--------- src/MacVim/MMVimView.m | 2 +- src/MacVim/MMWindowController.m | 31 ------------------------------- 5 files changed, 18 insertions(+), 46 deletions(-) diff --git a/src/MacVim/MMCoreTextView.h b/src/MacVim/MMCoreTextView.h index ae4c85f313..a085013057 100644 --- a/src/MacVim/MMCoreTextView.h +++ b/src/MacVim/MMCoreTextView.h @@ -31,6 +31,7 @@ BOOL antialias; BOOL ligatures; BOOL thinStrokes; + BOOL drawPending; NSMutableArray *drawData; MMTextViewHelper *helper; @@ -96,6 +97,7 @@ // // NSTextView methods // +- (void)setFrameSize:(NSSize)newSize; - (void)keyDown:(NSEvent *)event; - (void)insertText:(id)string; - (void)doCommandBySelector:(SEL)selector; diff --git a/src/MacVim/MMCoreTextView.m b/src/MacVim/MMCoreTextView.m index c990c34abe..8b95ef1cc6 100644 --- a/src/MacVim/MMCoreTextView.m +++ b/src/MacVim/MMCoreTextView.m @@ -446,6 +446,14 @@ defaultAdvanceForFont(NSFont *font) return YES; } +- (void)setFrameSize:(NSSize)newSize { + if (!drawPending && !NSEqualSizes(newSize, self.frame.size) && drawData.count == 0) { + [NSAnimationContext beginGrouping]; + drawPending = YES; + } + [super setFrameSize:newSize]; +} + - (void)keyDown:(NSEvent *)event { [helper keyDown:event]; @@ -650,11 +658,10 @@ defaultAdvanceForFont(NSFont *font) } else { [drawData addObject:data]; [self setNeedsDisplay:YES]; - - // NOTE: During resizing, Cocoa only sends draw messages before Vim's rows - // and columns are changed (due to ipc delays). Force a redraw here. - if ([self inLiveResize]) - [self display]; + } + if (drawPending) { + [NSAnimationContext endGrouping]; + drawPending = NO; } } diff --git a/src/MacVim/MMVimController.m b/src/MacVim/MMVimController.m index a96cdbbf96..66d4b4b556 100644 --- a/src/MacVim/MMVimController.m +++ b/src/MacVim/MMVimController.m @@ -554,15 +554,9 @@ static BOOL isUnsafeMessage(int msgid); { if (OpenWindowMsgID == msgid) { [windowController openWindow]; - - // HACK: Delay actually presenting the window onscreen until after - // processing the queue since it contains drawing commands that need to - // be issued before presentation; otherwise the window may flash white - // just as it opens. - if (!isPreloading) - [windowController performSelector:@selector(presentWindow:) - withObject:nil - afterDelay:0]; + if (!isPreloading) { + [windowController presentWindow:nil]; + } } else if (BatchDrawMsgID == msgid) { [[[windowController vimView] textView] performBatchDrawWithData:data]; } else if (SelectTabMsgID == msgid) { diff --git a/src/MacVim/MMVimView.m b/src/MacVim/MMVimView.m index a4125ced60..fd04c47e5b 100644 --- a/src/MacVim/MMVimView.m +++ b/src/MacVim/MMVimView.m @@ -909,7 +909,7 @@ enum { "%dx%d (%s)", cols, rows, constrained[1], constrained[0], MessageStrings[msgid]); - [vimController sendMessage:msgid data:data]; + [vimController sendMessageNow:msgid data:data timeout:1]; // We only want to set the window title if this resize came from // a live-resize, not (for example) setting 'columns' or 'lines'. diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index 3338b75095..8a966793b2 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -697,37 +697,6 @@ NSConnection *connection = [(NSDistantObject*)proxy connectionForProxy]; [connection removeRequestMode:NSEventTrackingRunLoopMode]; - // NOTE: During live resize messages from MacVim to Vim are often dropped - // (because too many messages are sent at once). This may lead to - // inconsistent states between Vim and MacVim; to avoid this we send a - // synchronous resize message to Vim now (this is not fool-proof, but it - // does seem to work quite well). - // Do NOT send a SetTextDimensionsMsgID message (as opposed to - // LiveResizeMsgID) since then the view is constrained to not be larger - // than the screen the window mostly occupies; this makes it impossible to - // resize the window across multiple screens. - - int constrained[2]; - NSSize textViewSize = [[vimView textView] frame].size; - [[vimView textView] constrainRows:&constrained[0] columns:&constrained[1] - toSize:textViewSize]; - - ASLogDebug(@"End of live resize, notify Vim that text dimensions are %dx%d", - constrained[1], constrained[0]); - - NSData *data = [NSData dataWithBytes:constrained length:2*sizeof(int)]; - BOOL sendOk = [vimController sendMessageNow:LiveResizeMsgID - data:data - timeout:.5]; - - if (!sendOk) { - // Sending of synchronous message failed. Force the window size to - // match the last dimensions received from Vim, otherwise we end up - // with inconsistent states. - [self resizeWindowToFitContentSize:[vimView desiredSize] - keepOnScreen:NO]; - } - // If we saved the original title while resizing, restore it. if (lastSetTitle != nil) { [decoratedWindow setTitle:lastSetTitle];