Backend initiates window zooming

Don't change the window size immediately upon pressing the zoom button.
Instead send the message to Vim and let it resize before the window
does.  This avoids flickering problem when zooming with the Core Text
renderer.

The zooming is also slightly smarter about which window size to restore
if the toolbar was hidden while the window was zoomed.
This commit is contained in:
Bjorn Winckler
2010-02-08 18:18:34 +01:00
parent c621846160
commit b7bbbc85bf
12 changed files with 136 additions and 113 deletions
+1 -1
View File
@@ -753,7 +753,7 @@ defaultLineHeightForFont(NSFont *font)
// - Desired rows/columns shold not be 'too small'
// Constrain the desired size to the given size. Values for the minimum
// rows and columns is taken from Vim.
// rows and columns are taken from Vim.
NSSize desiredSize = [self desiredSize];
int desiredRows = maxRows;
int desiredCols = maxColumns;
+15
View File
@@ -1937,6 +1937,21 @@ static void netbeansReadCallback(CFSocketRef s,
#endif
} else if (SetMarkedTextMsgID == msgid) {
[self handleMarkedText:data];
} else if (ZoomMsgID == msgid) {
if (!data) return;
const void *bytes = [data bytes];
int rows = *((int*)bytes); bytes += sizeof(int);
int cols = *((int*)bytes); bytes += sizeof(int);
//int zoom = *((int*)bytes); bytes += sizeof(int);
// NOTE: The frontend sends zoom messages here causing us to
// immediately resize the shell and mirror the message back to the
// frontend. This is done to ensure that the draw commands reach the
// frontend before the window actually changes size in order to avoid
// flickering. (Also see comment in SetTextDimensionsReplyMsgID
// regarding resizing.)
[self queueMessage:ZoomMsgID data:data];
gui_resize_shell(cols, rows);
} else {
ASLogWarn(@"Unknown message received (msgid=%d)", msgid);
}
+3 -2
View File
@@ -562,7 +562,8 @@ defaultAdvanceForFont(CTFontRef fontRef)
- (void)drawRect:(NSRect)rect
{
//ASLogNotice(@"drawData count=%d", [drawData count]);
//ASLogTmp(@"count=%d rect=%@", [drawData count],
// NSStringFromRect(rect));
NSGraphicsContext *context = [NSGraphicsContext currentContext];
[context setShouldAntialias:antialias];
@@ -593,7 +594,7 @@ defaultAdvanceForFont(CTFontRef fontRef)
// - Desired rows/columns shold not be 'too small'
// Constrain the desired size to the given size. Values for the minimum
// rows and columns is taken from Vim.
// rows and columns are taken from Vim.
NSSize desiredSize = [self desiredSize];
int desiredRows = maxRows;
int desiredCols = maxColumns;
+15 -1
View File
@@ -584,10 +584,15 @@ static BOOL isUnsafeMessage(int msgid);
int rows = *((int*)bytes); bytes += sizeof(int);
int cols = *((int*)bytes); bytes += sizeof(int);
// NOTE: When a resize message originated in the frontend, Vim
// 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;
[windowController setTextDimensionsWithRows:rows
columns:cols
isLive:(LiveResizeMsgID==msgid)
isReply:(SetTextDimensionsReplyMsgID==msgid)];
keepOnScreen:onScreen];
} else if (SetWindowTitleMsgID == msgid) {
const void *bytes = [data bytes];
int len = *((int*)bytes); bytes += sizeof(int);
@@ -821,6 +826,15 @@ static BOOL isUnsafeMessage(int msgid);
NSDictionary *dict = [NSDictionary dictionaryWithData:data];
if (dict)
[self handleShowDialog:dict];
} else if (ZoomMsgID == msgid) {
const void *bytes = [data bytes];
int rows = *((int*)bytes); bytes += sizeof(int);
int cols = *((int*)bytes); bytes += sizeof(int);
int state = *((int*)bytes); bytes += sizeof(int);
[windowController zoomWithRows:rows
columns:cols
state:state];
// IMPORTANT: When adding a new message, make sure to update
// isUnsafeMessage() if necessary!
} else {
-1
View File
@@ -25,7 +25,6 @@
BOOL vimTaskSelectedTab;
MMTextView *textView;
NSMutableArray *scrollbars;
NSRect lastTextViewFrame;
BOOL isDirty;
}
-46
View File
@@ -198,52 +198,6 @@ enum {
isDirty = NO;
}
NSRect textViewFrame = [textView frame];
if (!NSEqualRects(lastTextViewFrame, textViewFrame)) {
// If the text view's frame changes we copy the contents of the old
// frame to the origin of the new frame. The reason for this is that
// Vim expects the contents of its view not to change unless Vim
// changes it. (Omitting this code causes the view contents to get
// messed up e.g. when the left scrollbar is shown.)
NSPoint pt = textViewFrame.origin;
CGFloat d = textViewFrame.size.height - lastTextViewFrame.size.height;
NSRect r = lastTextViewFrame;
if (d >= 0) {
// Thew view became larger. Copy the old view to the top of the
// new view.
pt.y += d;
NSCopyBits(0, r, pt);
// Clear the part of the view that has been exposed.
r = textViewFrame;
r.size.height = d;
[[textView defaultBackgroundColor] set];
NSRectFill(r);
r = textViewFrame;
r.size.width -= lastTextViewFrame.size.width;
if (r.size.width > 0) {
// The width of the view has grown to the right (i.e. user
// clicked maximize button whilst holding Cmd).
r.origin.x += lastTextViewFrame.size.width;
NSRectFill(r);
}
} else {
// The view became smaller.
// TODO: Should copy the top of the old view into the new view, but
// this does not work since the view has already been resized and
// the top of the old view is lost. Could perhaps work to cache
// the view to an offscreen surface before it resizes and then draw
// from that?
// As a temporary hack we just clear the view instead.
NSRectFill(textViewFrame);
// r.origin.y -= d;
// r.size.height = textViewFrame.size.height;
}
lastTextViewFrame = textViewFrame;
}
// On Leopard, we want to have a textured window background for nice
// looking tabs. However, the textured window background looks really
// weird behind the window resize throbber, so emulate the look of an
-1
View File
@@ -14,7 +14,6 @@
@interface MMWindow : NSWindow {
NSBox *tablineSeparator;
NSRect userFrame;
}
- (id)initWithContentRect:(NSRect)rect
+4 -26
View File
@@ -142,33 +142,11 @@
- (IBAction)zoom:(id)sender
{
NSScreen *screen = [self screen];
if (!screen) {
ASLogNotice(@"Window not on screen, zoom to main screen");
screen = [NSScreen mainScreen];
if (!screen) {
ASLogNotice(@"No main screen, abort zoom");
return;
}
}
// NOTE: We shortcut the usual zooming behavior and provide custom zooming
// in the window controller.
NSRect frame = [self frame];
NSRect defaultFrame = [screen visibleFrame];
defaultFrame = [[self delegate] windowWillUseStandardFrame:self
defaultFrame:defaultFrame];
// TODO: Check if width & height differs by cellSize or more.
BOOL isZoomed = ((abs(frame.size.width - defaultFrame.size.width) < 8) &&
(abs(frame.size.height - defaultFrame.size.height) < 8));
if (isZoomed) {
if (userFrame.size.width > 0 && userFrame.size.height > 0)
defaultFrame = userFrame;
} else {
userFrame = frame;
}
[self setFrame:defaultFrame display:YES];
// (Use performSelector:: to avoid compilation warning.)
[[self delegate] performSelector:@selector(zoom:) withObject:sender];
}
@end // MMWindow
+7 -1
View File
@@ -27,6 +27,7 @@
MMVimView *vimView;
BOOL setupDone;
BOOL shouldResizeVimView;
BOOL shouldRestoreUserTopLeft;
int updateToolbarFlag;
BOOL keepOnScreen;
BOOL fullscreenEnabled;
@@ -34,6 +35,9 @@
MMFullscreenWindow *fullscreenWindow;
MMWindow *decoratedWindow;
NSString *lastSetTitle;
int userRows;
int userCols;
NSPoint userTopLeft;
}
- (id)initWithVimController:(MMVimController *)controller;
@@ -47,7 +51,8 @@
- (void)updateTabsWithData:(NSData *)data;
- (void)selectTabWithIndex:(int)idx;
- (void)setTextDimensionsWithRows:(int)rows columns:(int)cols isLive:(BOOL)live
isReply:(BOOL)reply;
keepOnScreen:(BOOL)onScreen;
- (void)zoomWithRows:(int)rows columns:(int)cols state:(int)state;
- (void)setTitle:(NSString *)title;
- (void)setDocumentFilename:(NSString *)filename;
- (void)setToolbar:(NSToolbar *)toolbar;
@@ -84,5 +89,6 @@
- (IBAction)fontSizeUp:(id)sender;
- (IBAction)fontSizeDown:(id)sender;
- (IBAction)findAndReplace:(id)sender;
- (IBAction)zoom:(id)sender;
@end
+89 -34
View File
@@ -286,10 +286,10 @@
}
- (void)setTextDimensionsWithRows:(int)rows columns:(int)cols isLive:(BOOL)live
isReply:(BOOL)reply
keepOnScreen:(BOOL)onScreen
{
ASLogDebug(@"setTextDimensionsWithRows:%d columns:%d isLive:%d isReply:%d",
rows, cols, live, reply);
//ASLogDebug(@"setTextDimensionsWithRows:%d columns:%d isLive:%d "
// "keepOnScreen:%d", rows, cols, live, 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
@@ -301,16 +301,12 @@
// resize when this message is received. We refrain from changing the view
// size when this flag is set, otherwise the window might jitter when the
// user drags to resize the window.
//
// The 'reply' flag indicates that this resize originated in MacVim and
// that Vim is now replying to that resize to make sure that it comes into
// effect.
[vimView setDesiredRows:rows columns:cols];
if (setupDone && !live) {
shouldResizeVimView = YES;
keepOnScreen = !reply;
keepOnScreen = onScreen;
}
if (windowAutosaveKey) {
@@ -326,6 +322,24 @@
}
}
- (void)zoomWithRows:(int)rows columns:(int)cols state:(int)state
{
[self setTextDimensionsWithRows:rows
columns:cols
isLive:NO
keepOnScreen:YES];
// NOTE: If state==0 then the window should be put in the non-zoomed
// "user state". That is, move the window back to the last stored
// position. If the window is in the zoomed state, the call to change the
// dimensions above will also reposition the window to ensure it fits on
// the screen. However, since resizing of the window is delayed we also
// delay repositioning so that both happen at the same time (this avoid
// situations where the window woud appear to "jump").
if (!state && !NSEqualPoints(NSZeroPoint, userTopLeft))
shouldRestoreUserTopLeft = YES;
}
- (void)setTitle:(NSString *)title
{
if (title)
@@ -818,36 +832,69 @@
[vimView setFrameSize:[self contentSize]];
}
- (NSRect)windowWillUseStandardFrame:(NSWindow *)win
defaultFrame:(NSRect)frame
// This is not an NSWindow delegate method, our custom MMWindow class calls it
// instead of the usual windowWillUseStandardFrame:defaultFrame:.
- (IBAction)zoom:(id)sender
{
// By default the window is maximized in the vertical direction only.
// Holding down the Cmd key maximizes the window in the horizontal
// direction. If the MMZoomBoth user default is set, then the window
// maximizes in both directions by default, unless the Cmd key is held in
// which case the window only maximizes in the vertical direction.
NSEvent *event = [NSApp currentEvent];
BOOL cmdLeftClick = [event type] == NSLeftMouseUp
&& [event modifierFlags] & NSCommandKeyMask;
BOOL zoomBoth = [[NSUserDefaults standardUserDefaults]
boolForKey:MMZoomBothKey];
// The "default frame" represents the maximal size of a zoomed window.
// Constrain this frame so that the content fits an even number of rows and
// columns.
frame = [self constrainFrame:frame];
if (!((zoomBoth && !cmdLeftClick) || (!zoomBoth && cmdLeftClick))) {
// Zoom in horizontal direction only.
NSRect currentFrame = [win frame];
frame.size.width = currentFrame.size.width;
frame.origin.x = currentFrame.origin.x;
NSScreen *screen = [decoratedWindow screen];
if (!screen) {
ASLogNotice(@"Window not on screen, zoom to main screen");
screen = [NSScreen mainScreen];
if (!screen) {
ASLogNotice(@"No main screen, abort zoom");
return;
}
}
return frame;
}
// Decide whether too zoom horizontally or not (always zoom vertically).
NSEvent *event = [NSApp currentEvent];
BOOL cmdLeftClick = [event type] == NSLeftMouseUp &&
[event modifierFlags] & NSCommandKeyMask;
BOOL zoomBoth = [[NSUserDefaults standardUserDefaults]
boolForKey:MMZoomBothKey];
zoomBoth = (zoomBoth && !cmdLeftClick) || (!zoomBoth && cmdLeftClick);
// Figure out how many rows/columns can fit while zoomed.
int rowsZoomed, colsZoomed;
NSRect maxFrame = [screen visibleFrame];
NSRect contentRect = [decoratedWindow contentRectForFrameRect:maxFrame];
[vimView constrainRows:&rowsZoomed
columns:&colsZoomed
toSize:contentRect.size];
int curRows, curCols;
[[vimView textView] getMaxRows:&curRows columns:&curCols];
int rows, cols;
BOOL isZoomed = zoomBoth ? curRows >= rowsZoomed && curCols >= colsZoomed
: curRows >= rowsZoomed;
if (isZoomed) {
rows = userRows > 0 ? userRows : curRows;
cols = userCols > 0 ? userCols : curCols;
} else {
rows = rowsZoomed;
cols = zoomBoth ? colsZoomed : curCols;
if (curRows+2 < rows || curCols+2 < cols) {
// The window is being zoomed so save the current "user state".
// Note that if the window does not enlarge by a 'significant'
// number of rows/columns then we don't save the current state.
// This is done to take into account toolbar/scrollbars
// showing/hiding.
userRows = curRows;
userCols = curCols;
NSRect frame = [decoratedWindow frame];
userTopLeft = NSMakePoint(frame.origin.x, NSMaxY(frame));
}
}
// NOTE: Instead of resizing the window immediately we send a zoom message
// to the backend so that it gets a chance to resize before the window
// does. This avoids problems with the window flickering when zooming.
int info[3] = { rows, cols, !isZoomed };
NSData *data = [NSData dataWithBytes:info length:3*sizeof(int)];
[vimController sendMessage:ZoomMsgID data:data];
}
@@ -913,6 +960,14 @@
NSRect newFrame = [decoratedWindow frameRectForContentRect:contentRect];
if (shouldRestoreUserTopLeft) {
// Restore user top left window position (which is saved when zooming).
CGFloat dy = userTopLeft.y - NSMaxY(newFrame);
newFrame.origin.x = userTopLeft.x;
newFrame.origin.y += dy;
shouldRestoreUserTopLeft = NO;
}
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
+1
View File
@@ -190,6 +190,7 @@ enum {
ShowDialogMsgID,
NetBeansMsgID,
SetMarkedTextMsgID,
ZoomMsgID,
LastMsgID // NOTE: MUST BE LAST MESSAGE IN ENUM!
};
+1
View File
@@ -93,6 +93,7 @@ char *MessageStrings[] =
"ShowDialogMsgID",
"NetBeansMsgID",
"SetMarkedTextMsgID",
"ZoomMsgID",
"END OF MESSAGE IDs" // NOTE: Must be last!
};