Added MMTexturedWindow user default
[MacVim.git] / src / MacVim / MMWindowController.m
blob048741f8d2cb769f2924b09fd02228f240a6d468
1 /* vi:set ts=8 sts=4 sw=4 ft=objc:
2  *
3  * VIM - Vi IMproved            by Bram Moolenaar
4  *                              MacVim GUI port by Bjorn Winckler
5  *
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.
9  */
11  * MMWindowController
12  *
13  * Handles resizing of windows, acts as an mediator between MMVimView and
14  * MMVimController.
15  *
16  * Resizing in windowed mode:
17  *
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.
23  *
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).
29  *
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
32  * (rows,columns).
33  *
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:
37  *
38  *   Tabline visible & Toolbar visible  =>  Separator visible
39  *   =====================================================================
40  *         NO        &        NO        =>  YES, if the window is textured
41  *                                           NO, otherwise
42  *         NO        &       YES        =>  YES
43  *        YES        &        NO        =>   NO
44  *        YES        &       YES        =>   NO
45  *
46  *
47  * Resizing in full-screen mode:
48  *
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
51  * is toggled.
52  *
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.
55  *  
56  */
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"
65 #import "MMVimView.h"
66 #import "MMWindow.h"
67 #import "MacVim.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 - (IBAction)vimMenuItemAction:(id)sender;
80 - (BOOL)askBackendForStarRegister:(NSPasteboard *)pb;
81 - (void)hideTablineSeparator:(BOOL)hide;
82 @end
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;
93 @end
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
105 # ifdef __LP64__
106     typedef double CGFloat;
107 # else
108     typedef float CGFloat;
109 # endif
110 #endif
111 - (void)setAutorecalculatesContentBorderThickness:(BOOL)b forEdge:(NSRectEdge)e;
112 - (void)setContentBorderThickness:(CGFloat)b forEdge:(NSRectEdge)e;
113 @end
118 @implementation MMWindowController
120 - (id)initWithVimController:(MMVimController *)controller
122 #ifndef NSAppKitVersionNumber10_4  // needed for non-10.5 sdk
123 # define NSAppKitVersionNumber10_4 824
124 #endif
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)
141                       styleMask:styleMask
142                         backing:NSBackingStoreBuffered
143                           defer:YES];
144     [win autorelease];
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]];
169     
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
186                                                    forEdge:NSMaxYEdge];
187         if ([win respondsToSelector:
188                 @selector(setContentBorderThickness:forEdge:)])
189             [win setContentBorderThickness:0 forEdge:NSMaxYEdge];
190     }
192     // Make us safe on pre-tiger OSX
193     if ([win respondsToSelector:@selector(_setContentHasShadow:)])
194         [win _setContentHasShadow:NO];
196     return self;
199 - (void)dealloc
201     //NSLog(@"%@ %s", [self className], _cmd);
203     [decoratedWindow release];  decoratedWindow = nil;
204     [windowAutosaveKey release];  windowAutosaveKey = nil;
205     [vimView release];  vimView = nil;
207     [super dealloc];
210 - (NSString *)description
212     NSString *format =
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
225     return vimView;
228 - (NSString *)windowAutosaveKey
230     return windowAutosaveKey;
233 - (void)setWindowAutosaveKey:(NSString *)key
235     [windowAutosaveKey autorelease];
236     windowAutosaveKey = [key copy];
239 - (void)cleanup
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];
248     }
250     setupDone = NO;
251     vimController = nil;
253     [vimView removeFromSuperviewWithoutNeedingDisplay];
254     [vimView cleanup];
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];
264 - (void)openWindow
266     [[NSApp delegate] windowControllerWillOpen:self];
268     [self addNewTabViewItem];
270     setupDone = YES;
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.
295     //
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
310     if (title) {
311         [decoratedWindow setTitle:title];
312         [fullscreenWindow setTitle:title];
313     }
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
322     // toolbar.
323     NSButton *pillButton = [decoratedWindow
324             standardWindowButton:NSWindowToolbarButton];
325     if (pillButton) {
326         [pillButton setAction:@selector(toggleToolbar:)];
327         [pillButton setTarget:self];
328     }
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
347                                                            state:visible];
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     [[self window] setOpaque:isOpaque];
371     [vimView setDefaultColorsBackground:back foreground:fore];
374 - (void)setFont:(NSFont *)font
376     [[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:NO];
377     [[vimView textView] setFont:font];
378     [self updateResizeConstraints];
381 - (void)setWideFont:(NSFont *)font
383     [[vimView textView] setWideFont:font];
386 - (void)processCommandQueueDidFinish
388     // NOTE: Resizing is delayed until after all commands have been processed
389     // since it often happens that more than one command will cause a resize.
390     // If we were to immediately resize then the vim view size would jitter
391     // (e.g.  hiding/showing scrollbars often happens several time in one
392     // update).
394     if (shouldResizeVimView) {
395         shouldResizeVimView = NO;
397         NSSize contentSize = [vimView desiredSize];
398         contentSize = [self constrainContentSizeToScreenSize:contentSize];
399         contentSize = [vimView constrainRows:NULL columns:NULL
400                                       toSize:contentSize];
401         [vimView setFrameSize:contentSize];
403         if (fullscreenEnabled) {
404             [[fullscreenWindow contentView] setNeedsDisplay:YES];
405             [fullscreenWindow centerView];
406         } else {
407             [self resizeWindowToFitContentSize:contentSize];
408         }
409     }
412 - (void)popupMenu:(NSMenu *)menu atRow:(int)row column:(int)col
414     if (!setupDone) return;
416     NSEvent *event;
417     if (row >= 0 && col >= 0) {
418         // TODO: Let textView convert (row,col) to NSPoint.
419         NSSize cellSize = [[vimView textView] cellSize];
420         NSPoint pt = { (col+1)*cellSize.width, (row+1)*cellSize.height };
421         pt = [[vimView textView] convertPoint:pt toView:nil];
423         event = [NSEvent mouseEventWithType:NSRightMouseDown
424                                    location:pt
425                               modifierFlags:0
426                                   timestamp:0
427                                windowNumber:[[self window] windowNumber]
428                                     context:nil
429                                 eventNumber:0
430                                  clickCount:0
431                                    pressure:1.0];
432     } else {
433         event = [[vimView textView] lastMouseDownEvent];
434     }
436     [NSMenu popUpContextMenu:menu withEvent:event forView:[vimView textView]];
439 - (void)showTabBar:(BOOL)on
441     [[vimView tabBarControl] setHidden:!on];
443     // Showing the tabline may result in the tabline separator being hidden or
444     // shown; this does not apply to full-screen mode.
445     if (!on) {
446         NSToolbar *toolbar = [decoratedWindow toolbar]; 
447         if (([decoratedWindow styleMask] & NSTexturedBackgroundWindowMask)
448                 == 0) {
449             [self hideTablineSeparator:![toolbar isVisible]];
450         } else {
451             [self hideTablineSeparator:NO];
452         }
453     } else {
454         if (([decoratedWindow styleMask] & NSTexturedBackgroundWindowMask)
455                 == 0) {
456             [self hideTablineSeparator:on];
457         } else {
458             [self hideTablineSeparator:YES];
459         }
460     }
463 - (void)showToolbar:(BOOL)on size:(int)size mode:(int)mode
465     NSToolbar *toolbar = [decoratedWindow toolbar];
466     if (!toolbar) return;
468     [toolbar setSizeMode:size];
469     [toolbar setDisplayMode:mode];
470     [toolbar setVisible:on];
472     if (([decoratedWindow styleMask] & NSTexturedBackgroundWindowMask) == 0) {
473         if (!on) {
474             [self hideTablineSeparator:YES];
475         } else {
476             [self hideTablineSeparator:![[vimView tabBarControl] isHidden]];
477         }
478     } else {
479         // Textured windows don't have a line below there title bar, so we
480         // need the separator in this case as well. In fact, the only case
481         // where we don't need the separator is when the tab bar control
482         // is visible (because it brings its own separator).
483         [self hideTablineSeparator:![[vimView tabBarControl] isHidden]];
484     }
487 - (void)setMouseShape:(int)shape
489     // This switch should match mshape_names[] in misc2.c.
490     //
491     // TODO: Add missing cursor shapes.
492     switch (shape) {
493         case 2: [[NSCursor IBeamCursor] set]; break;
494         case 3: case 4: [[NSCursor resizeUpDownCursor] set]; break;
495         case 5: case 6: [[NSCursor resizeLeftRightCursor] set]; break;
496         case 9: [[NSCursor crosshairCursor] set]; break;
497         case 10: [[NSCursor pointingHandCursor] set]; break;
498         case 11: [[NSCursor openHandCursor] set]; break;
499         default:
500             [[NSCursor arrowCursor] set]; break;
501     }
503     // Shape 1 indicates that the mouse cursor should be hidden.
504     if (1 == shape)
505         [NSCursor setHiddenUntilMouseMoves:YES];
508 - (void)adjustLinespace:(int)linespace
510     if (vimView && [vimView textView]) {
511         [[vimView textView] setLinespace:(float)linespace];
512         shouldResizeVimView = YES;
513     }
516 - (void)liveResizeWillStart
518     // Save the original title, if we haven't already.
519     if (lastSetTitle == nil) {
520         lastSetTitle = [[decoratedWindow title] retain];
521     }
524 - (void)liveResizeDidEnd
526     if (!setupDone) return;
528     // NOTE: During live resize messages from MacVim to Vim are often dropped
529     // (because too many messages are sent at once).  This may lead to
530     // inconsistent states between Vim and MacVim; to avoid this we send a
531     // synchronous resize message to Vim now (this is not fool-proof, but it
532     // does seem to work quite well).
534     int constrained[2];
535     NSSize textViewSize = [[vimView textView] frame].size;
536     [[vimView textView] constrainRows:&constrained[0] columns:&constrained[1]
537                                toSize:textViewSize];
539     //NSLog(@"End of live resize, notify Vim that text dimensions are %dx%d",
540     //       constrained[1], constrained[0]);
542     NSData *data = [NSData dataWithBytes:constrained length:2*sizeof(int)];
543     BOOL sendOk = [vimController sendMessageNow:SetTextDimensionsMsgID
544                                            data:data
545                                         timeout:.5];
547     if (!sendOk) {
548         // Sending of synchronous message failed.  Force the window size to
549         // match the last dimensions received from Vim, otherwise we end up
550         // with inconsistent states.
551         [self resizeWindowToFitContentSize:[vimView desiredSize]];
552     }
554     // If we saved the original title while resizing, restore it.
555     if (lastSetTitle != nil) {
556         [decoratedWindow setTitle:lastSetTitle];
557         [lastSetTitle release];
558         lastSetTitle = nil;
559     }
562 - (void)enterFullscreen
564     if (fullscreenEnabled) return;
566     fullscreenWindow = [[MMFullscreenWindow alloc]
567             initWithWindow:decoratedWindow view:vimView];
568     [fullscreenWindow enterFullscreen];    
569     [fullscreenWindow setDelegate:self];
570     fullscreenEnabled = YES;
572     // The resize handle disappears so the vim view needs to update the
573     // scrollbars.
574     shouldResizeVimView = YES;
577 - (void)leaveFullscreen
579     if (!fullscreenEnabled) return;
581     fullscreenEnabled = NO;
582     [fullscreenWindow leaveFullscreen];    
583     [fullscreenWindow release];
584     fullscreenWindow = nil;
586     // The vim view may be too large to fit the screen, so update it.
587     shouldResizeVimView = YES;
590 - (void)setBuffersModified:(BOOL)mod
592     // NOTE: We only set the document edited flag on the decorated window since
593     // the full-screen window has no close button anyway.  (It also saves us
594     // from keeping track of the flag in two different places.)
595     [decoratedWindow setDocumentEdited:mod];
599 - (IBAction)addNewTab:(id)sender
601     [vimView addNewTab:sender];
604 - (IBAction)toggleToolbar:(id)sender
606     [vimController sendMessage:ToggleToolbarMsgID data:nil];
611 // -- NSWindow delegate ------------------------------------------------------
613 - (void)windowDidBecomeMain:(NSNotification *)notification
615     [vimController updateMainMenu];
616     [vimController sendMessage:GotFocusMsgID data:nil];
618     if ([vimView textView]) {
619         NSFontManager *fm = [NSFontManager sharedFontManager];
620         [fm setSelectedFont:[[vimView textView] font] isMultiple:NO];
621     }
624 - (void)windowDidResignMain:(NSNotification *)notification
626     [vimController sendMessage:LostFocusMsgID data:nil];
628     if ([vimView textView])
629         [[vimView textView] hideMarkedTextField];
632 - (BOOL)windowShouldClose:(id)sender
634     // Don't close the window now; Instead let Vim decide whether to close the
635     // window or not.
636     [vimController sendMessage:VimShouldCloseMsgID data:nil];
637     return NO;
640 - (void)windowDidMove:(NSNotification *)notification
642     if (setupDone && windowAutosaveKey) {
643         NSRect frame = [decoratedWindow frame];
644         NSPoint topLeft = { frame.origin.x, NSMaxY(frame) };
645         NSString *topLeftString = NSStringFromPoint(topLeft);
647         [[NSUserDefaults standardUserDefaults]
648             setObject:topLeftString forKey:windowAutosaveKey];
649     }
652 - (void)windowDidResize:(id)sender
654     if (!setupDone || fullscreenEnabled) return;
656     // NOTE: Since we have no control over when the window may resize (Cocoa
657     // may resize automatically) we simply set the view to fill the entire
658     // window.  The vim view takes care of notifying Vim if the number of
659     // (rows,columns) changed.
660     [vimView setFrameSize:[self contentSize]];
663 - (NSRect)windowWillUseStandardFrame:(NSWindow *)win
664                         defaultFrame:(NSRect)frame
666     // Keep old width and horizontal position unless user clicked while the
667     // Command key is held down.
668     NSEvent *event = [NSApp currentEvent];
669     if (!([event type] == NSLeftMouseUp
670             && [event modifierFlags] & NSCommandKeyMask)) {
671         NSRect currentFrame = [win frame];
672         frame.size.width = currentFrame.size.width;
673         frame.origin.x = currentFrame.origin.x;
674     }
676     return frame;
682 // -- Services menu delegate -------------------------------------------------
684 - (id)validRequestorForSendType:(NSString *)sendType
685                      returnType:(NSString *)returnType
687     if ([sendType isEqual:NSStringPboardType]
688             && [self askBackendForStarRegister:nil])
689         return self;
691     return [super validRequestorForSendType:sendType returnType:returnType];
694 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard
695                              types:(NSArray *)types
697     if (![types containsObject:NSStringPboardType])
698         return NO;
700     return [self askBackendForStarRegister:pboard];
703 @end // MMWindowController
707 @implementation MMWindowController (Private)
709 - (NSSize)contentSize
711     // NOTE: Never query the content view directly for its size since it may
712     // not return the same size as contentRectForFrameRect: (e.g. when in
713     // windowed mode and the tabline separator is visible)!
714     NSWindow *win = [self window];
715     return [win contentRectForFrameRect:[win frame]].size;
718 - (void)resizeWindowToFitContentSize:(NSSize)contentSize
720     NSRect frame = [decoratedWindow frame];
721     NSRect contentRect = [decoratedWindow contentRectForFrameRect:frame];
723     // Keep top-left corner of the window fixed when resizing.
724     contentRect.origin.y -= contentSize.height - contentRect.size.height;
725     contentRect.size = contentSize;
727     frame = [decoratedWindow frameRectForContentRect:contentRect];
728     [decoratedWindow setFrame:frame display:YES];
731 - (NSSize)constrainContentSizeToScreenSize:(NSSize)contentSize
733     NSWindow *win = [self window];
734     NSRect rect = [win contentRectForFrameRect:[[win screen] visibleFrame]];
736     if (contentSize.height > rect.size.height)
737         contentSize.height = rect.size.height;
738     if (contentSize.width > rect.size.width)
739         contentSize.width = rect.size.width;
741     return contentSize;
744 - (void)updateResizeConstraints
746     if (!setupDone) return;
748     // Set the resize increments to exactly match the font size; this way the
749     // window will always hold an integer number of (rows,columns).
750     NSSize cellSize = [[vimView textView] cellSize];
751     [decoratedWindow setContentResizeIncrements:cellSize];
753     NSSize minSize = [vimView minSize];
754     [decoratedWindow setContentMinSize:minSize];
757 - (NSTabViewItem *)addNewTabViewItem
759     return [vimView addNewTabViewItem];
762 - (IBAction)vimMenuItemAction:(id)sender
764     int tag = [sender tag];
766     NSMutableData *data = [NSMutableData data];
767     [data appendBytes:&tag length:sizeof(int)];
769     [vimController sendMessage:ExecuteMenuMsgID data:data];
772 - (BOOL)askBackendForStarRegister:(NSPasteboard *)pb
774     // TODO: Can this be done with evaluateExpression: instead?
775     BOOL reply = NO;
776     id backendProxy = [vimController backendProxy];
778     if (backendProxy) {
779         @try {
780             reply = [backendProxy starRegisterToPasteboard:pb];
781         }
782         @catch (NSException *e) {
783             NSLog(@"WARNING: Caught exception in %s: \"%@\"", _cmd, e);
784         }
785     }
787     return reply;
790 - (void)hideTablineSeparator:(BOOL)hide
792     // The full-screen window has no tabline separator so we operate on
793     // decoratedWindow instead of [self window].
794     if ([decoratedWindow hideTablineSeparator:hide]) {
795         // The tabline separator was toggled so the content view must change
796         // size.
797         [self updateResizeConstraints];
798         shouldResizeVimView = YES;
799     }
802 @end // MMWindowController (Private)