From 346ebb12737ca99493016de96f0c1fad3ad9ac46 Mon Sep 17 00:00:00 2001 From: Bjorn Winckler Date: Sat, 20 Feb 2010 00:40:23 +0100 Subject: [PATCH] Add support for :winpos Note that window coordinates are specified in a coordinate system where X points to the right and Y points upwards. --- src/MacVim/MMAppController.m | 20 ++++++++++++------ src/MacVim/MMBackend.h | 4 ++++ src/MacVim/MMBackend.m | 38 ++++++++++++++++++++++++++++++++++ src/MacVim/MMVimController.m | 6 ++++++ src/MacVim/MMWindowController.h | 3 +++ src/MacVim/MMWindowController.m | 45 +++++++++++++++++++++++++++++++++++++++-- src/MacVim/MacVim.h | 1 + src/MacVim/MacVim.m | 1 + src/MacVim/gui_macvim.m | 32 +++++++++++++++-------------- 9 files changed, 127 insertions(+), 23 deletions(-) diff --git a/src/MacVim/MMAppController.m b/src/MacVim/MMAppController.m index 8b7dac98..5f2203b7 100644 --- a/src/MacVim/MMAppController.m +++ b/src/MacVim/MMAppController.m @@ -743,15 +743,23 @@ fsEventCallback(ConstFSEventStreamRef streamRef, - (void)windowControllerWillOpen:(MMWindowController *)windowController { NSPoint topLeft = NSZeroPoint; - NSWindow *topWin = [[[self topmostVimController] windowController] window]; + NSWindow *cascadeFrom = [[[self topmostVimController] windowController] + window]; NSWindow *win = [windowController window]; if (!win) return; - // If there is a window belonging to a Vim process, cascade from it, - // otherwise use the autosaved window position (if any). - if (topWin) { - NSRect frame = [topWin frame]; + // Heuristic to determine where to position the window: + // 1. Use the default top left position (set using :winpos in .[g]vimrc) + // 2. Cascade from an existing window + // 3. Use autosaved position + // If all of the above fail, then the window position is not changed. + if ([windowController getDefaultTopLeft:&topLeft]) { + // Make sure the window is not cascaded (note that topLeft was set in + // the above call). + cascadeFrom = nil; + } else if (cascadeFrom) { + NSRect frame = [cascadeFrom frame]; topLeft = NSMakePoint(frame.origin.x, NSMaxY(frame)); } else { NSString *topLeftString = [[NSUserDefaults standardUserDefaults] @@ -767,7 +775,7 @@ fsEventCallback(ConstFSEventStreamRef streamRef, if (!screen) screen = [win screen]; - if (topWin) { + if (cascadeFrom) { // Do manual cascading instead of using // -[MMWindow cascadeTopLeftFromPoint:] since it is rather // unpredictable. diff --git a/src/MacVim/MMBackend.h b/src/MacVim/MMBackend.h index f4adbfad..ac9499ca 100644 --- a/src/MacVim/MMBackend.h +++ b/src/MacVim/MMBackend.h @@ -53,6 +53,8 @@ BOOL imState; CFSocketRef netbeansSocket; CFRunLoopSourceRef netbeansRunLoopSource; + int winposX; + int winposY; } + (MMBackend *)sharedInstance; @@ -64,6 +66,8 @@ - (NSConnection *)connection; - (NSDictionary *)actionDict; - (int)initialWindowLayout; +- (void)getWindowPositionX:(int*)x Y:(int*)y; +- (void)setWindowPositionX:(int)x Y:(int)y; - (void)queueMessage:(int)msgid properties:(NSDictionary *)props; - (BOOL)checkin; diff --git a/src/MacVim/MMBackend.m b/src/MacVim/MMBackend.m index 4c6291e6..bf5b58a8 100644 --- a/src/MacVim/MMBackend.m +++ b/src/MacVim/MMBackend.m @@ -326,6 +326,24 @@ extern GuiFont gui_mch_retain_font(GuiFont font); return initialWindowLayout; } +- (void)getWindowPositionX:(int*)x Y:(int*)y +{ + // NOTE: winposX and winposY are set by the SetWindowPositionMsgID message. + if (x) *x = winposX; + if (y) *y = winposY; +} + +- (void)setWindowPositionX:(int)x Y:(int)y +{ + // NOTE: Setting the window position has no immediate effect on the cached + // variables winposX and winposY. These are set by the frontend when the + // window actually moves (see SetWindowPositionMsgID). + ASLogDebug(@"x=%d y=%d", x, y); + int pos[2] = { x, y }; + NSData *data = [NSData dataWithBytes:pos length:2*sizeof(int)]; + [self queueMessage:SetWindowPositionMsgID data:data]; +} + - (void)queueMessage:(int)msgid properties:(NSDictionary *)props { [self queueMessage:msgid data:[props dictionaryAsData]]; @@ -440,7 +458,21 @@ extern GuiFont gui_mch_retain_font(GuiFont font); - (BOOL)openGUIWindow { + if (gui_win_x != -1 && gui_win_y != -1) { + // NOTE: the gui_win_* coordinates are both set to -1 if no :winpos + // command is in .[g]vimrc. (This way of detecting if :winpos has been + // used may cause problems if a second monitor is located to the left + // and underneath the main monitor as it will have negative + // coordinates. However, this seems like a minor problem that is not + // worth fixing since all GUIs work this way.) + ASLogDebug(@"default x=%d y=%d", gui_win_x, gui_win_y); + int pos[2] = { gui_win_x, gui_win_y }; + NSData *data = [NSData dataWithBytes:pos length:2*sizeof(int)]; + [self queueMessage:SetWindowPositionMsgID data:data]; + } + [self queueMessage:OpenWindowMsgID data:nil]; + return YES; } @@ -1952,6 +1984,12 @@ static void netbeansReadCallback(CFSocketRef s, // regarding resizing.) [self queueMessage:ZoomMsgID data:data]; gui_resize_shell(cols, rows); + } else if (SetWindowPositionMsgID == msgid) { + if (!data) return; + const void *bytes = [data bytes]; + winposX = *((int*)bytes); bytes += sizeof(int); + winposY = *((int*)bytes); bytes += sizeof(int); + ASLogDebug(@"SetWindowPositionMsgID: x=%d y=%d", winposX, winposY); } else { ASLogWarn(@"Unknown message received (msgid=%d)", msgid); } diff --git a/src/MacVim/MMVimController.m b/src/MacVim/MMVimController.m index 279cf8f8..f114bae0 100644 --- a/src/MacVim/MMVimController.m +++ b/src/MacVim/MMVimController.m @@ -824,6 +824,12 @@ static BOOL isUnsafeMessage(int msgid); [windowController zoomWithRows:rows columns:cols state:state]; + } else if (SetWindowPositionMsgID == msgid) { + const void *bytes = [data bytes]; + int x = *((int*)bytes); bytes += sizeof(int); + int y = *((int*)bytes); bytes += sizeof(int); + + [windowController setTopLeft:NSMakePoint(x,y)]; // IMPORTANT: When adding a new message, make sure to update // isUnsafeMessage() if necessary! } else { diff --git a/src/MacVim/MMWindowController.h b/src/MacVim/MMWindowController.h index 9b05d817..5ac4ade8 100644 --- a/src/MacVim/MMWindowController.h +++ b/src/MacVim/MMWindowController.h @@ -38,6 +38,7 @@ int userRows; int userCols; NSPoint userTopLeft; + NSPoint defaultTopLeft; } - (id)initWithVimController:(MMVimController *)controller; @@ -78,6 +79,8 @@ - (void)setFullscreenBackgroundColor:(NSColor *)back; - (void)setBuffersModified:(BOOL)mod; +- (void)setTopLeft:(NSPoint)pt; +- (BOOL)getDefaultTopLeft:(NSPoint*)pt; - (IBAction)addNewTab:(id)sender; - (IBAction)toggleToolbar:(id)sender; diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index 366041d0..39c4512f 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -640,6 +640,30 @@ [decoratedWindow setDocumentEdited:mod]; } +- (void)setTopLeft:(NSPoint)pt +{ + if (setupDone) { + [decoratedWindow setFrameTopLeftPoint:pt]; + } else { + // Window has not been "opened" yet (see openWindow:) but remember this + // value to be used when the window opens. + defaultTopLeft = pt; + } +} + +- (BOOL)getDefaultTopLeft:(NSPoint*)pt +{ + // A default top left point may be set in .[g]vimrc with the :winpos + // command. (If this has not been done the top left point will be the zero + // point.) + if (pt && !NSEqualPoints(defaultTopLeft, NSZeroPoint)) { + *pt = defaultTopLeft; + return YES; + } + + return NO; +} + - (IBAction)addNewTab:(id)sender { @@ -792,14 +816,20 @@ return; } + NSRect frame = [decoratedWindow frame]; + NSPoint topLeft = { frame.origin.x, NSMaxY(frame) }; if (windowAutosaveKey) { - NSRect frame = [decoratedWindow frame]; - NSPoint topLeft = { frame.origin.x, NSMaxY(frame) }; NSString *topLeftString = NSStringFromPoint(topLeft); [[NSUserDefaults standardUserDefaults] setObject:topLeftString forKey:windowAutosaveKey]; } + + // NOTE: This method is called when the user drags the window, but not when + // the top left point changes programmatically. + int pos[2] = { (int)topLeft.x, (int)topLeft.y }; + NSData *data = [NSData dataWithBytes:pos length:2*sizeof(int)]; + [vimController sendMessage:SetWindowPositionMsgID data:data]; } - (void)windowDidResize:(id)sender @@ -978,6 +1008,17 @@ } [decoratedWindow setFrame:newFrame display:YES]; + + NSPoint oldTopLeft = { frame.origin.x, NSMaxY(frame) }; + NSPoint newTopLeft = { newFrame.origin.x, NSMaxY(newFrame) }; + if (!NSEqualPoints(oldTopLeft, newTopLeft)) { + // NOTE: The window top left position may change due to the window + // being moved e.g. when the tabline is shown so we must tell Vim what + // the new window position is here. + int pos[2] = { (int)newTopLeft.x, (int)newTopLeft.y }; + NSData *data = [NSData dataWithBytes:pos length:2*sizeof(int)]; + [vimController sendMessage:SetWindowPositionMsgID data:data]; + } } - (NSSize)constrainContentSizeToScreenSize:(NSSize)contentSize diff --git a/src/MacVim/MacVim.h b/src/MacVim/MacVim.h index f07bfe5a..927a887c 100644 --- a/src/MacVim/MacVim.h +++ b/src/MacVim/MacVim.h @@ -191,6 +191,7 @@ enum { NetBeansMsgID, SetMarkedTextMsgID, ZoomMsgID, + SetWindowPositionMsgID, LastMsgID // NOTE: MUST BE LAST MESSAGE IN ENUM! }; diff --git a/src/MacVim/MacVim.m b/src/MacVim/MacVim.m index 90449001..ce060d24 100644 --- a/src/MacVim/MacVim.m +++ b/src/MacVim/MacVim.m @@ -94,6 +94,7 @@ char *MessageStrings[] = "NetBeansMsgID", "SetMarkedTextMsgID", "ZoomMsgID", + "SetWindowPositionMsgID", "END OF MESSAGE IDs" // NOTE: Must be last! }; diff --git a/src/MacVim/gui_macvim.m b/src/MacVim/gui_macvim.m index 71748ce7..4d5e3b96 100644 --- a/src/MacVim/gui_macvim.m +++ b/src/MacVim/gui_macvim.m @@ -1655,17 +1655,6 @@ gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) /* - * Get the position of the top left corner of the window. - */ - int -gui_mch_get_winpos(int *x, int *y) -{ - *x = *y = 0; - return OK; -} - - -/* * Return OK if the key with the termcap name "name" is supported. */ int @@ -1714,17 +1703,30 @@ gui_mch_set_shellsize( } +/* + * Set the position of the top left corner of the window to the given + * coordinates. + */ void -gui_mch_set_text_area_pos(int x, int y, int w, int h) +gui_mch_set_winpos(int x, int y) { + [[MMBackend sharedInstance] setWindowPositionX:x Y:y]; } + /* - * Set the position of the top left corner of the window to the given - * coordinates. + * Get the position of the top left corner of the window. */ + int +gui_mch_get_winpos(int *x, int *y) +{ + [[MMBackend sharedInstance] getWindowPositionX:x Y:y]; + return OK; +} + + void -gui_mch_set_winpos(int x, int y) +gui_mch_set_text_area_pos(int x, int y, int w, int h) { } -- 2.11.4.GIT