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:].
This commit is contained in:
Sidney San Martín
2017-03-31 13:20:41 -04:00
parent 98496b9aa2
commit 3fb41ccae8
5 changed files with 18 additions and 46 deletions
+2
View File
@@ -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;
+12 -5
View File
@@ -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;
}
}
+3 -9
View File
@@ -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) {
+1 -1
View File
@@ -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'.
-31
View File
@@ -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];