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 * Support for full-screen editing.
18 #import "MMFullscreenWindow.h"
19 #import <PSMTabBarControl.h>
21 #import "MMTextView.h"
22 #import "MMWindowController.h"
23 #import <Carbon/Carbon.h>
26 static int numFullscreenWindows = 0;
28 @interface MMFullscreenWindow (Private)
30 - (BOOL)isOnPrimaryScreen;
31 - (void)hideDockIfAppropriate;
32 - (void)revealDockIfAppropriate;
35 @implementation MMFullscreenWindow
37 - (MMFullscreenWindow *)initWithWindow:(NSWindow *)t view:(MMVimView *)v
39 NSScreen* screen = [t screen];
41 // XXX: what if screen == nil?
43 // you can't change the style of an existing window in cocoa. create a new
44 // window and move the MMTextView into it.
45 // (another way would be to make the existing window large enough that the
46 // title bar is off screen. but that doesn't work with multiple screens).
47 self = [super initWithContentRect:[screen frame]
48 styleMask:NSBorderlessWindowMask
49 backing:NSBackingStoreBuffered
51 // since we're passing [screen frame] above,
52 // we want the content rect to be relative to
53 // the main screen (ie, pass nil for screen).
59 [self setHasShadow:NO];
60 [self setShowsResizeIndicator:NO];
61 [self setBackgroundColor:[NSColor blackColor]];
62 [self setReleasedWhenClosed:NO];
64 target = t; [target retain];
65 view = v; [view retain];
78 - (void)enterFullscreen
80 [self hideDockIfAppropriate];
83 Boolean didBlend = NO;
84 CGDisplayFadeReservationToken token;
85 if (CGAcquireDisplayFadeReservation(.5, &token) == kCGErrorSuccess) {
86 CGDisplayFade(token, .25, kCGDisplayBlendNormal,
87 kCGDisplayBlendSolidColor, .0, .0, .0, true);
92 id delegate = [target delegate];
93 [target setDelegate:nil];
95 // make target's window controller believe that it's now controlling us
96 [target retain]; // NSWindowController will release target once in the
98 [[target windowController] setWindow:self];
101 oldTabBarStyle = [[view tabBarControl] styleName];
102 [[view tabBarControl] setStyleNamed:@"Unified"];
105 oldPosition = [view frame].origin;
107 [[self contentView] addSubview:view];
108 [self setInitialFirstResponder:[view textView]];
110 [self setTitle:[target title]];
111 [self setOpaque:[target isOpaque]];
113 // don't set this sooner, so we don't get an additional
114 // focus gained message
115 [self setDelegate:delegate];
117 // update bottom right corner scrollbar (no resize handle in fu mode)
120 // move vim view to the window's center
123 // make us visible and target invisible
124 [target orderOut:self];
125 [self makeKeyAndOrderFront:self];
129 CGDisplayFade(token, .25, kCGDisplayBlendSolidColor,
130 kCGDisplayBlendNormal, .0, .0, .0, false);
131 CGReleaseDisplayFadeReservation(token);
135 - (void)leaveFullscreen
138 Boolean didBlend = NO;
139 CGDisplayFadeReservationToken token;
140 if (CGAcquireDisplayFadeReservation(.5, &token) == kCGErrorSuccess) {
141 CGDisplayFade(token, .25, kCGDisplayBlendNormal,
142 kCGDisplayBlendSolidColor, .0, .0, .0, true);
146 // fix up target controller
147 [self retain]; // NSWindowController releases us once
148 [[self windowController] setWindow:target];
150 [[view tabBarControl] setStyleNamed:oldTabBarStyle];
153 id delegate = [self delegate];
154 [self setDelegate:nil];
156 // move text view back to original window, hide fullscreen window,
157 // show original window
158 // do this _after_ resetting delegate and window controller, so the
159 // window controller doesn't get a focus lost message from the fullscreen
161 [[target contentView] addSubview:view];
162 [view setFrameOrigin:oldPosition];
164 [target makeKeyAndOrderFront:self];
166 // ...but we don't want a focus gained message either, so don't set this
168 [target setDelegate:delegate];
170 // update bottom right corner scrollbar (resize handle reappears)
175 CGDisplayFade(token, .25, kCGDisplayBlendSolidColor,
176 kCGDisplayBlendNormal, .0, .0, .0, false);
177 CGReleaseDisplayFadeReservation(token);
180 [self revealDockIfAppropriate];
183 // Title-less windows normally don't receive key presses, override this
184 - (BOOL)canBecomeKeyWindow
189 // Title-less windows normally can't become main which means that another
190 // non-fullscreen window will have the "active" titlebar in expose. Bad, fix it.
191 - (BOOL)canBecomeMainWindow
197 #pragma mark Proxy/Decorator/whatever stuff
199 - (void)scrollWheel:(NSEvent *)theEvent
201 [[view textView] scrollWheel:theEvent];
204 // the window controller will send us messages that are meant for the original,
205 // non-fullscreen window. forward those, and interpret the messages that are
206 // interesting for us
208 - (void)setTitle:(NSString *)title
210 [target setTitle:title];
211 [super setTitle:title];
214 // HACK: if the T flag in guioptions is changed in fu mode, the toolbar needs
215 // to be changed when nofu is set. MMWindowController gets the toolbar object,
216 // so we need to return a toolbar from this method, even if none is visible for
217 // the fullscreen window. Seems to work, though.
218 - (NSToolbar *)toolbar
220 return [target toolbar];
223 - (void)setFrame:(NSRect)frame display:(BOOL)display
225 // HACK: if the target window would resize, we have to call our own
226 // windowDidResize method so that placeViews in MMWindowController is called
227 if (!NSEqualRects(frame, [target frame]))
229 [target setFrame:frame display:NO];
231 // XXX: send this directly to MMVimView
232 if ([[self delegate] respondsToSelector:@selector(windowDidResize:)])
233 [[self delegate] windowDidResize:nil];
242 return [target frame]; // really? needed by MMWindowController placeViews.
243 // but mucks up display
246 - (NSRect)contentRectForFrameRect:(NSRect)rect
248 //return [target contentRectForFrameRect:rect];
250 // EVIL HACK: if this is always called with [[self window] frame] as
251 // argument from MMWindowController, we can't let frame return the frame
252 // of target so "fix" this here.
253 if (NSEqualRects([self frame], rect)) {
254 return [target contentRectForFrameRect:[target frame]];
256 return [target contentRectForFrameRect:rect];
260 - (NSRect)frameRectForContentRect:(NSRect)contentRect
262 return [target frameRectForContentRect:contentRect];
265 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)screen
267 return [target constrainFrameRect:frameRect toScreen:screen];
270 - (void)setContentResizeIncrements:(NSSize)size
272 [target setContentResizeIncrements:size];
275 - (void)setOpaque:(BOOL)isOpaque
277 // XXX: Do we want transparency even in fullscreen mode?
278 [super setOpaque:isOpaque];
279 [target setOpaque:isOpaque];
282 @end // MMFullscreenWindow
287 @implementation MMFullscreenWindow (Private)
291 NSRect outer = [self frame], inner = [view frame];
292 //NSLog(@"%s %@%@", _cmd, NSStringFromRect(outer), NSStringFromRect(inner));
294 NSPoint origin = NSMakePoint((outer.size.width - inner.size.width)/2,
295 (outer.size.height - inner.size.height)/2);
296 [view setFrameOrigin:origin];
299 - (BOOL)isOnPrimaryScreen
301 // The primary screen is the screen the menu bar is on. This is different
302 // from [NSScreen mainScreen] (which returns the screen containing the
304 NSArray *screens = [NSScreen screens];
305 if (screens == nil || [screens count] < 1)
308 return [self screen] == [screens objectAtIndex:0];
311 - (void)hideDockIfAppropriate
313 // Hide menu and dock, both appear on demand.
315 // Don't hide the dock if going fullscreen on a non-primary screen. Also,
316 // if there are several fullscreen windows on the primary screen, only
317 // hide dock and friends for the first fullscreen window (and display
318 // them again after the last fullscreen window has been closed).
320 // Another way to deal with several fullscreen windows would be to hide/
321 // reveal the dock each time a fullscreen window gets/loses focus, but
322 // this way it's less distracting.
324 // XXX: If you have a fullscreen window on a secondary monitor and unplug
325 // the monitor, this will probably not work right.
327 if ([self isOnPrimaryScreen]) {
328 if (numFullscreenWindows == 0) {
329 SetSystemUIMode(kUIModeAllSuppressed, 0); //requires 10.3
331 ++numFullscreenWindows;
335 - (void)revealDockIfAppropriate
337 // order menu and dock back in
338 if ([self isOnPrimaryScreen]) {
339 --numFullscreenWindows;
340 if (numFullscreenWindows == 0) {
341 SetSystemUIMode(kUIModeNormal, 0);
346 @end // MMFullscreenWindow (Private)