1 /* vi:set ts=8 sts=4 sw=4 ft=objc:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * MacVim GUI port by Bjorn Winckler
6 * Do ":help uganda" in Vim to read copying and usage conditions.
7 * Do ":help credits" in Vim to see a list of people who contributed.
8 * See README.txt for an overview of the Vim source code.
13 * Handles resizing of windows, acts as an mediator between MMVimView and
16 * Resizing in windowed mode:
18 * In windowed mode resizing can occur either due to the window frame changing
19 * size (e.g. when the user drags to resize), or due to Vim changing the number
20 * of (rows,columns). The former case is dealt with by letting the vim view
21 * fill the entire content view when the window has resized. In the latter
22 * case we ensure that vim view fits on the screen.
24 * The vim view notifies Vim if the number of (rows,columns) does not match the
25 * current number whenver the view size is about to change. Upon receiving a
26 * dimension change message, Vim notifies the window controller and the window
27 * resizes. However, the window is never resized programmatically during a
28 * live resize (in order to avoid jittering).
30 * The window size is constrained to not become too small during live resize,
31 * and it is also constrained to always fit an integer number of
34 * In windowed mode we have to manually draw a tabline separator (due to bugs
35 * in the way Cocoa deals with the toolbar separator) when certain conditions
36 * are met. The rules for this are as follows:
38 * Tabline visible & Toolbar visible => Separator visible
39 * =====================================================================
40 * NO & NO => YES, if the window is textured
47 * Resizing in full-screen mode:
49 * The window never resizes since it fills the screen, however the vim view may
50 * change size, e.g. when the user types ":set lines=60", or when a scrollbar
53 * It is ensured that the vim view never becomes larger than the screen size
54 * and that it always stays in the center of the screen.
58 #import "MMWindowController.h"
59 #import "MMAppController.h"
60 #import "MMAtsuiTextView.h"
61 #import "MMFullscreenWindow.h"
62 #import "MMTextView.h"
63 #import "MMTypesetter.h"
64 #import "MMVimController.h"
69 #import <PSMTabBarControl.h>
73 @interface MMWindowController (Private)
74 - (NSSize)contentSize;
75 - (void)resizeWindowToFitContentSize:(NSSize)contentSize;
76 - (NSSize)constrainContentSizeToScreenSize:(NSSize)contentSize;
77 - (void)updateResizeConstraints;
78 - (NSTabViewItem *)addNewTabViewItem;
79 - (BOOL)askBackendForStarRegister:(NSPasteboard *)pb;
80 - (void)hideTablineSeparator:(BOOL)hide;
81 - (void)doFindNext:(BOOL)next;
85 @interface NSWindow (NSWindowPrivate)
86 // Note: This hack allows us to set content shadowing separately from
87 // the window shadow. This is apparently what webkit and terminal do.
88 - (void)_setContentHasShadow:(BOOL)shadow; // new Tiger private method
90 // This is a private api that makes textured windows not have rounded corners.
91 // We want this on Leopard.
92 - (void)setBottomCornerRounded:(BOOL)rounded;
96 @interface NSWindow (NSLeopardOnly)
97 // Note: These functions are Leopard-only, use -[NSObject respondsToSelector:]
98 // before calling them to make sure everything works on Tiger too.
100 #ifndef CGFLOAT_DEFINED
101 // On Leopard, CGFloat is float on 32bit and double on 64bit. On Tiger,
102 // we can't use this anyways, so it's just here to keep the compiler happy.
103 // However, when we're compiling for Tiger and running on Leopard, we
104 // might need the correct typedef, so this piece is copied from ATSTypes.h
106 typedef double CGFloat;
108 typedef float CGFloat;
111 - (void)setAutorecalculatesContentBorderThickness:(BOOL)b forEdge:(NSRectEdge)e;
112 - (void)setContentBorderThickness:(CGFloat)b forEdge:(NSRectEdge)e;
118 @implementation MMWindowController
120 - (id)initWithVimController:(MMVimController *)controller
122 #ifndef NSAppKitVersionNumber10_4 // needed for non-10.5 sdk
123 # define NSAppKitVersionNumber10_4 824
125 unsigned styleMask = NSTitledWindowMask | NSClosableWindowMask
126 | NSMiniaturizableWindowMask | NSResizableWindowMask
127 | NSUnifiedTitleAndToolbarWindowMask;
129 // Use textured background on Leopard or later (skip the 'if' on Tiger for
130 // polished metal window).
131 if ([[NSUserDefaults standardUserDefaults] boolForKey:MMTexturedWindowKey]
132 || (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4))
133 styleMask |= NSTexturedBackgroundWindowMask;
135 // NOTE: The content rect is only used the very first time MacVim is
136 // started (or rather, when ~/Library/Preferences/org.vim.MacVim.plist does
137 // not exist). The chosen values will put the window somewhere near the
138 // top and in the middle of a 1024x768 screen.
139 MMWindow *win = [[MMWindow alloc]
140 initWithContentRect:NSMakeRect(242,364,480,360)
142 backing:NSBackingStoreBuffered
146 self = [super initWithWindow:win];
147 if (!self) return nil;
149 vimController = controller;
150 decoratedWindow = [win retain];
152 // Window cascading is handled by MMAppController.
153 [self setShouldCascadeWindows:NO];
155 // NOTE: Autoresizing is enabled for the content view, but only used
156 // for the tabline separator. The vim view must be resized manually
157 // because of full-screen considerations, and because its size depends
158 // on whether the tabline separator is visible or not.
159 NSView *contentView = [win contentView];
160 [contentView setAutoresizesSubviews:YES];
162 vimView = [[MMVimView alloc] initWithFrame:[contentView frame]
163 vimController:vimController];
164 [vimView setAutoresizingMask:NSViewNotSizable];
165 [contentView addSubview:vimView];
167 [win setDelegate:self];
168 [win setInitialFirstResponder:[vimView textView]];
170 if ([win styleMask] & NSTexturedBackgroundWindowMask) {
171 // On Leopard, we want to have a textured window to have nice
172 // looking tabs. But the textured window look implies rounded
173 // corners, which looks really weird -- disable them. This is a
174 // private api, though.
175 if ([win respondsToSelector:@selector(setBottomCornerRounded:)])
176 [win setBottomCornerRounded:NO];
178 // When the tab bar is toggled, it changes color for the fraction
179 // of a second, probably because vim sends us events in a strange
180 // order, confusing appkit's content border heuristic for a short
181 // while. This can be worked around with these two methods. There
182 // might be a better way, but it's good enough.
183 if ([win respondsToSelector:@selector(
184 setAutorecalculatesContentBorderThickness:forEdge:)])
185 [win setAutorecalculatesContentBorderThickness:NO
187 if ([win respondsToSelector:
188 @selector(setContentBorderThickness:forEdge:)])
189 [win setContentBorderThickness:0 forEdge:NSMaxYEdge];
192 // Make us safe on pre-tiger OSX
193 if ([win respondsToSelector:@selector(_setContentHasShadow:)])
194 [win _setContentHasShadow:NO];
201 //NSLog(@"%@ %s", [self className], _cmd);
203 [decoratedWindow release]; decoratedWindow = nil;
204 [windowAutosaveKey release]; windowAutosaveKey = nil;
205 [vimView release]; vimView = nil;
210 - (NSString *)description
213 @"%@ : setupDone=%d windowAutosaveKey=%@ vimController=%@";
214 return [NSString stringWithFormat:format,
215 [self className], setupDone, windowAutosaveKey, vimController];
218 - (MMVimController *)vimController
220 return vimController;
223 - (MMVimView *)vimView
228 - (NSString *)windowAutosaveKey
230 return windowAutosaveKey;
233 - (void)setWindowAutosaveKey:(NSString *)key
235 [windowAutosaveKey autorelease];
236 windowAutosaveKey = [key copy];
241 //NSLog(@"%@ %s", [self className], _cmd);
243 if (fullscreenEnabled) {
244 // If we are closed while still in fullscreen, end fullscreen mode,
245 // release ourselves (because this won't happen in MMWindowController)
246 // and perform close operation on the original window.
247 [self leaveFullscreen];
253 [vimView removeFromSuperviewWithoutNeedingDisplay];
256 // It is feasible (though unlikely) that the user quits before the window
257 // controller is released, make sure the edit flag is cleared so no warning
258 // dialog is displayed.
259 [decoratedWindow setDocumentEdited:NO];
261 [[self window] orderOut:self];
266 [[MMAppController sharedInstance] windowControllerWillOpen:self];
268 [self addNewTabViewItem];
272 [self updateResizeConstraints];
273 [self resizeWindowToFitContentSize:[vimView desiredSize]];
274 [[self window] makeKeyAndOrderFront:self];
277 - (void)updateTabsWithData:(NSData *)data
279 [vimView updateTabsWithData:data];
282 - (void)selectTabWithIndex:(int)idx
284 [vimView selectTabWithIndex:idx];
287 - (void)setTextDimensionsWithRows:(int)rows columns:(int)cols live:(BOOL)live
289 //NSLog(@"setTextDimensionsWithRows:%d columns:%d live:%s", rows, cols,
290 // live ? "YES" : "NO");
292 // NOTE: This is the only place where the (rows,columns) of the vim view
293 // are modified. Setting these values have no immediate effect, the actual
294 // resizing of the view is done in processCommandQueueDidFinish.
296 // The 'live' flag indicates that this resize originated from a live
297 // resize; it may very well happen that the view is no longer in live
298 // resize when this message is received. We refrain from changing the view
299 // size when this flag is set, otherwise the window might jitter when the
300 // user drags to resize the window.
302 [vimView setDesiredRows:rows columns:cols];
304 if (setupDone && !live)
305 shouldResizeVimView = YES;
308 - (void)setTitle:(NSString *)title
311 [decoratedWindow setTitle:title];
312 [fullscreenWindow setTitle:title];
316 - (void)setToolbar:(NSToolbar *)toolbar
318 // The full-screen window has no toolbar.
319 [decoratedWindow setToolbar:toolbar];
321 // HACK! Redirect the pill button so that we can ask Vim to hide the
323 NSButton *pillButton = [decoratedWindow
324 standardWindowButton:NSWindowToolbarButton];
326 [pillButton setAction:@selector(toggleToolbar:)];
327 [pillButton setTarget:self];
331 - (void)createScrollbarWithIdentifier:(long)ident type:(int)type
333 [vimView createScrollbarWithIdentifier:ident type:type];
336 - (BOOL)destroyScrollbarWithIdentifier:(long)ident
338 BOOL scrollbarHidden = [vimView destroyScrollbarWithIdentifier:ident];
339 shouldResizeVimView = shouldResizeVimView || scrollbarHidden;
341 return scrollbarHidden;
344 - (BOOL)showScrollbarWithIdentifier:(long)ident state:(BOOL)visible
346 BOOL scrollbarToggled = [vimView showScrollbarWithIdentifier:ident
348 shouldResizeVimView = shouldResizeVimView || scrollbarToggled;
350 return scrollbarToggled;
353 - (void)setScrollbarPosition:(int)pos length:(int)len identifier:(long)ident
355 [vimView setScrollbarPosition:pos length:len identifier:ident];
358 - (void)setScrollbarThumbValue:(float)val proportion:(float)prop
359 identifier:(long)ident
361 [vimView setScrollbarThumbValue:val proportion:prop identifier:ident];
364 - (void)setDefaultColorsBackground:(NSColor *)back foreground:(NSColor *)fore
366 // NOTE: This is called when the transparency changes so set the opacity
367 // flag on the window here (should be faster if the window is opaque).
368 BOOL isOpaque = [back alphaComponent] == 1.0f;
369 [decoratedWindow setOpaque:isOpaque];
370 if (fullscreenEnabled)
371 [fullscreenWindow setOpaque:isOpaque];
373 [vimView setDefaultColorsBackground:back foreground:fore];
376 - (void)setFont:(NSFont *)font
378 [[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:NO];
379 [[vimView textView] setFont:font];
380 [self updateResizeConstraints];
383 - (void)setWideFont:(NSFont *)font
385 [[vimView textView] setWideFont:font];
388 - (void)processCommandQueueDidFinish
390 // IMPORTANT! No synchronous DO calls are allowed in this method. They
391 // may cause the command queue to get processed out of order.
393 // NOTE: Resizing is delayed until after all commands have been processed
394 // since it often happens that more than one command will cause a resize.
395 // If we were to immediately resize then the vim view size would jitter
396 // (e.g. hiding/showing scrollbars often happens several time in one
399 if (shouldResizeVimView) {
400 shouldResizeVimView = NO;
402 NSSize contentSize = [vimView desiredSize];
403 contentSize = [self constrainContentSizeToScreenSize:contentSize];
404 contentSize = [vimView constrainRows:NULL columns:NULL
406 [vimView setFrameSize:contentSize];
408 if (fullscreenEnabled) {
409 [[fullscreenWindow contentView] setNeedsDisplay:YES];
410 [fullscreenWindow centerView];
412 [self resizeWindowToFitContentSize:contentSize];
417 - (void)showTabBar:(BOOL)on
419 [[vimView tabBarControl] setHidden:!on];
421 // Showing the tabline may result in the tabline separator being hidden or
422 // shown; this does not apply to full-screen mode.
424 NSToolbar *toolbar = [decoratedWindow toolbar];
425 if (([decoratedWindow styleMask] & NSTexturedBackgroundWindowMask)
427 [self hideTablineSeparator:![toolbar isVisible]];
429 [self hideTablineSeparator:NO];
432 if (([decoratedWindow styleMask] & NSTexturedBackgroundWindowMask)
434 [self hideTablineSeparator:on];
436 [self hideTablineSeparator:YES];
441 - (void)showToolbar:(BOOL)on size:(int)size mode:(int)mode
443 NSToolbar *toolbar = [decoratedWindow toolbar];
444 if (!toolbar) return;
446 [toolbar setSizeMode:size];
447 [toolbar setDisplayMode:mode];
448 [toolbar setVisible:on];
450 if (([decoratedWindow styleMask] & NSTexturedBackgroundWindowMask) == 0) {
452 [self hideTablineSeparator:YES];
454 [self hideTablineSeparator:![[vimView tabBarControl] isHidden]];
457 // Textured windows don't have a line below there title bar, so we
458 // need the separator in this case as well. In fact, the only case
459 // where we don't need the separator is when the tab bar control
460 // is visible (because it brings its own separator).
461 [self hideTablineSeparator:![[vimView tabBarControl] isHidden]];
465 - (void)setMouseShape:(int)shape
467 [[vimView textView] setMouseShape:shape];
470 - (void)adjustLinespace:(int)linespace
472 if (vimView && [vimView textView]) {
473 [[vimView textView] setLinespace:(float)linespace];
474 shouldResizeVimView = YES;
478 - (void)liveResizeWillStart
480 // Save the original title, if we haven't already.
481 if (lastSetTitle == nil) {
482 lastSetTitle = [[decoratedWindow title] retain];
486 - (void)liveResizeDidEnd
488 if (!setupDone) return;
490 // NOTE: During live resize messages from MacVim to Vim are often dropped
491 // (because too many messages are sent at once). This may lead to
492 // inconsistent states between Vim and MacVim; to avoid this we send a
493 // synchronous resize message to Vim now (this is not fool-proof, but it
494 // does seem to work quite well).
497 NSSize textViewSize = [[vimView textView] frame].size;
498 [[vimView textView] constrainRows:&constrained[0] columns:&constrained[1]
499 toSize:textViewSize];
501 //NSLog(@"End of live resize, notify Vim that text dimensions are %dx%d",
502 // constrained[1], constrained[0]);
504 NSData *data = [NSData dataWithBytes:constrained length:2*sizeof(int)];
505 BOOL sendOk = [vimController sendMessageNow:SetTextDimensionsMsgID
510 // Sending of synchronous message failed. Force the window size to
511 // match the last dimensions received from Vim, otherwise we end up
512 // with inconsistent states.
513 [self resizeWindowToFitContentSize:[vimView desiredSize]];
516 // If we saved the original title while resizing, restore it.
517 if (lastSetTitle != nil) {
518 [decoratedWindow setTitle:lastSetTitle];
519 [lastSetTitle release];
524 - (void)enterFullscreen:(int)fuoptions backgroundColor:(NSColor *)back
526 if (fullscreenEnabled) return;
528 fullscreenWindow = [[MMFullscreenWindow alloc]
529 initWithWindow:decoratedWindow view:vimView backgroundColor:back];
530 [fullscreenWindow enterFullscreen:fuoptions];
531 [fullscreenWindow setDelegate:self];
532 fullscreenEnabled = YES;
534 // The resize handle disappears so the vim view needs to update the
536 shouldResizeVimView = YES;
539 - (void)leaveFullscreen
541 if (!fullscreenEnabled) return;
543 fullscreenEnabled = NO;
544 [fullscreenWindow leaveFullscreen];
545 [fullscreenWindow release];
546 fullscreenWindow = nil;
548 // The vim view may be too large to fit the screen, so update it.
549 shouldResizeVimView = YES;
552 - (void)setBuffersModified:(BOOL)mod
554 // NOTE: We only set the document edited flag on the decorated window since
555 // the full-screen window has no close button anyway. (It also saves us
556 // from keeping track of the flag in two different places.)
557 [decoratedWindow setDocumentEdited:mod];
561 - (IBAction)addNewTab:(id)sender
563 [vimView addNewTab:sender];
566 - (IBAction)toggleToolbar:(id)sender
568 [vimController sendMessage:ToggleToolbarMsgID data:nil];
571 - (IBAction)performClose:(id)sender
573 // NOTE: With the introduction of :macmenu it is possible to bind
574 // File.Close to ":conf q" but at the same time have it send off the
575 // performClose: action. For this reason we no longer need the CloseMsgID
576 // message. However, we still need File.Close to send performClose:
577 // otherwise Cmd-w will not work on dialogs.
578 [self vimMenuItemAction:sender];
581 - (IBAction)findNext:(id)sender
583 [self doFindNext:YES];
586 - (IBAction)findPrevious:(id)sender
588 [self doFindNext:NO];
591 - (IBAction)vimMenuItemAction:(id)sender
593 if (![sender isKindOfClass:[NSMenuItem class]]) return;
595 // TODO: Make into category on NSMenuItem which returns descriptor.
596 NSMenuItem *item = (NSMenuItem*)sender;
597 NSMutableArray *desc = [NSMutableArray arrayWithObject:[item title]];
599 NSMenu *menu = [item menu];
601 [desc insertObject:[menu title] atIndex:0];
602 menu = [menu supermenu];
605 // The "MainMenu" item is part of the Cocoa menu and should not be part of
607 if ([[desc objectAtIndex:0] isEqual:@"MainMenu"])
608 [desc removeObjectAtIndex:0];
610 NSDictionary *attrs = [NSDictionary dictionaryWithObject:desc
611 forKey:@"descriptor"];
612 [vimController sendMessage:ExecuteMenuMsgID data:[attrs dictionaryAsData]];
615 - (IBAction)vimToolbarItemAction:(id)sender
617 NSArray *desc = [NSArray arrayWithObjects:@"ToolBar", [sender label], nil];
618 NSDictionary *attrs = [NSDictionary dictionaryWithObject:desc
619 forKey:@"descriptor"];
620 [vimController sendMessage:ExecuteMenuMsgID data:[attrs dictionaryAsData]];
623 - (IBAction)fontSizeUp:(id)sender
625 [[NSFontManager sharedFontManager] modifyFont:
626 [NSNumber numberWithInt:NSSizeUpFontAction]];
629 - (IBAction)fontSizeDown:(id)sender
631 [[NSFontManager sharedFontManager] modifyFont:
632 [NSNumber numberWithInt:NSSizeDownFontAction]];
635 - (BOOL)validateMenuItem:(NSMenuItem *)item
637 if ([item action] == @selector(vimMenuItemAction:)
638 || [item action] == @selector(performClose:))
644 // -- NSWindow delegate ------------------------------------------------------
646 - (void)windowDidBecomeMain:(NSNotification *)notification
648 [[MMAppController sharedInstance] setMainMenu:[vimController mainMenu]];
649 [vimController sendMessage:GotFocusMsgID data:nil];
651 if ([vimView textView]) {
652 NSFontManager *fm = [NSFontManager sharedFontManager];
653 [fm setSelectedFont:[[vimView textView] font] isMultiple:NO];
657 - (void)windowDidResignMain:(NSNotification *)notification
659 [vimController sendMessage:LostFocusMsgID data:nil];
661 if ([vimView textView])
662 [[vimView textView] hideMarkedTextField];
665 - (BOOL)windowShouldClose:(id)sender
667 // Don't close the window now; Instead let Vim decide whether to close the
669 [vimController sendMessage:VimShouldCloseMsgID data:nil];
673 - (void)windowDidMove:(NSNotification *)notification
675 if (setupDone && windowAutosaveKey) {
676 NSRect frame = [decoratedWindow frame];
677 NSPoint topLeft = { frame.origin.x, NSMaxY(frame) };
678 NSString *topLeftString = NSStringFromPoint(topLeft);
680 [[NSUserDefaults standardUserDefaults]
681 setObject:topLeftString forKey:windowAutosaveKey];
685 - (void)windowDidResize:(id)sender
687 if (!setupDone || fullscreenEnabled) return;
689 // NOTE: Since we have no control over when the window may resize (Cocoa
690 // may resize automatically) we simply set the view to fill the entire
691 // window. The vim view takes care of notifying Vim if the number of
692 // (rows,columns) changed.
693 [vimView setFrameSize:[self contentSize]];
696 - (NSRect)windowWillUseStandardFrame:(NSWindow *)win
697 defaultFrame:(NSRect)frame
699 // By default the window is maximized in the vertical direction only.
700 // Holding down the Cmd key maximizes the window in the horizontal
701 // direction. If the MMZoomBoth user default is set, then the window
702 // maximizes in both directions by default, unless the Cmd key is held in
703 // which case the window only maximizes in the vertical direction.
705 NSEvent *event = [NSApp currentEvent];
706 BOOL cmdLeftClick = [event type] == NSLeftMouseUp
707 && [event modifierFlags] & NSCommandKeyMask;
708 BOOL zoomBoth = [[NSUserDefaults standardUserDefaults]
709 boolForKey:MMZoomBothKey];
711 if (!((zoomBoth && !cmdLeftClick) || (!zoomBoth && cmdLeftClick))) {
712 // Zoom in horizontal direction only.
713 NSRect currentFrame = [win frame];
714 frame.size.width = currentFrame.size.width;
715 frame.origin.x = currentFrame.origin.x;
718 // HACK! The window frame is often higher than the 'defaultFrame' (the fact
719 // that 'defaultFrame' doesn't cover the entire area up to the menu bar
720 // seems like a Cocoa bug). To ensure that the window doesn't move
721 // downwards when the zoom button is clicked we check for this situation
722 // and return a frame whose max Y coordinate is no lower than the current
724 float delta = NSMaxY([win frame]) - NSMaxY(frame);
726 frame.origin.y += delta;
734 // -- Services menu delegate -------------------------------------------------
736 - (id)validRequestorForSendType:(NSString *)sendType
737 returnType:(NSString *)returnType
739 if ([sendType isEqual:NSStringPboardType]
740 && [self askBackendForStarRegister:nil])
743 return [super validRequestorForSendType:sendType returnType:returnType];
746 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard
747 types:(NSArray *)types
749 if (![types containsObject:NSStringPboardType])
752 return [self askBackendForStarRegister:pboard];
755 @end // MMWindowController
759 @implementation MMWindowController (Private)
761 - (NSSize)contentSize
763 // NOTE: Never query the content view directly for its size since it may
764 // not return the same size as contentRectForFrameRect: (e.g. when in
765 // windowed mode and the tabline separator is visible)!
766 NSWindow *win = [self window];
767 return [win contentRectForFrameRect:[win frame]].size;
770 - (void)resizeWindowToFitContentSize:(NSSize)contentSize
772 NSRect frame = [decoratedWindow frame];
773 NSRect contentRect = [decoratedWindow contentRectForFrameRect:frame];
775 // Keep top-left corner of the window fixed when resizing.
776 contentRect.origin.y -= contentSize.height - contentRect.size.height;
777 contentRect.size = contentSize;
779 frame = [decoratedWindow frameRectForContentRect:contentRect];
780 [decoratedWindow setFrame:frame display:YES];
783 - (NSSize)constrainContentSizeToScreenSize:(NSSize)contentSize
785 NSWindow *win = [self window];
786 NSRect rect = [win contentRectForFrameRect:[[win screen] visibleFrame]];
788 if (contentSize.height > rect.size.height)
789 contentSize.height = rect.size.height;
790 if (contentSize.width > rect.size.width)
791 contentSize.width = rect.size.width;
796 - (void)updateResizeConstraints
798 if (!setupDone) return;
800 // Set the resize increments to exactly match the font size; this way the
801 // window will always hold an integer number of (rows,columns).
802 NSSize cellSize = [[vimView textView] cellSize];
803 [decoratedWindow setContentResizeIncrements:cellSize];
805 NSSize minSize = [vimView minSize];
806 [decoratedWindow setContentMinSize:minSize];
809 - (NSTabViewItem *)addNewTabViewItem
811 return [vimView addNewTabViewItem];
814 - (BOOL)askBackendForStarRegister:(NSPasteboard *)pb
816 // TODO: Can this be done with evaluateExpression: instead?
818 id backendProxy = [vimController backendProxy];
822 reply = [backendProxy starRegisterToPasteboard:pb];
824 @catch (NSException *e) {
825 NSLog(@"WARNING: Caught exception in %s: \"%@\"", _cmd, e);
832 - (void)hideTablineSeparator:(BOOL)hide
834 // The full-screen window has no tabline separator so we operate on
835 // decoratedWindow instead of [self window].
836 if ([decoratedWindow hideTablineSeparator:hide]) {
837 // The tabline separator was toggled so the content view must change
839 [self updateResizeConstraints];
840 shouldResizeVimView = YES;
844 - (void)doFindNext:(BOOL)next
846 NSString *query = nil;
849 // Use current query if the search field is selected.
850 id searchField = [[self searchFieldItem] view];
851 if (searchField && [[searchField stringValue] length] > 0 &&
852 [decoratedWindow firstResponder] == [searchField currentEditor])
853 query = [searchField stringValue];
857 // Use find pasteboard for next query.
858 NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSFindPboard];
859 NSArray *types = [NSArray arrayWithObject:NSStringPboardType];
860 if ([pb availableTypeFromArray:types])
861 query = [pb stringForType:NSStringPboardType];
864 NSString *input = nil;
866 // NOTE: The '/' register holds the last search string. By setting it
867 // (using the '@/' syntax) we fool Vim into thinking that it has
868 // already searched for that string and then we can simply use 'n' or
869 // 'N' to find the next/previous match.
870 input = [NSString stringWithFormat:@"<C-\\><C-N>:let @/='%@'<CR>%c",
871 query, next ? 'n' : 'N'];
873 input = next ? @"<C-\\><C-N>n" : @"<C-\\><C-N>N";
876 [vimController addVimInput:input];
879 @end // MMWindowController (Private)