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 * A window without any decorations which covers an entire screen.
15 * When entering full-screen mode the window controller is set to control an
16 * instance of this class instead of an MMWindow. (This seems to work fine
17 * even though the Apple docs state that it is generally a better idea to
18 * create a separate window controller for each window.)
20 * Most of the full-screen logic is currently in this class although it might
21 * move to the window controller in the future.
26 #import "MMFullscreenWindow.h"
27 #import <PSMTabBarControl.h>
29 #import "MMTextView.h"
30 #import "MMWindowController.h"
31 #import <Carbon/Carbon.h>
34 static int numFullscreenWindows = 0;
36 @interface MMFullscreenWindow (Private)
37 - (BOOL)isOnPrimaryScreen;
38 - (void)hideDockIfAppropriate;
39 - (void)revealDockIfAppropriate;
42 @implementation MMFullscreenWindow
44 - (MMFullscreenWindow *)initWithWindow:(NSWindow *)t view:(MMVimView *)v
46 NSScreen* screen = [t screen];
48 // XXX: what if screen == nil?
50 // you can't change the style of an existing window in cocoa. create a new
51 // window and move the MMTextView into it.
52 // (another way would be to make the existing window large enough that the
53 // title bar is off screen. but that doesn't work with multiple screens).
54 self = [super initWithContentRect:[screen frame]
55 styleMask:NSBorderlessWindowMask
56 backing:NSBackingStoreBuffered
58 // since we're passing [screen frame] above,
59 // we want the content rect to be relative to
60 // the main screen (ie, pass nil for screen).
69 [self setHasShadow:NO];
70 [self setShowsResizeIndicator:NO];
71 [self setBackgroundColor:[NSColor blackColor]];
72 [self setReleasedWhenClosed:NO];
85 - (void)enterFullscreen
87 [self hideDockIfAppropriate];
90 Boolean didBlend = NO;
91 CGDisplayFadeReservationToken token;
92 if (CGAcquireDisplayFadeReservation(.5, &token) == kCGErrorSuccess) {
93 CGDisplayFade(token, .25, kCGDisplayBlendNormal,
94 kCGDisplayBlendSolidColor, .0, .0, .0, true);
99 id delegate = [target delegate];
100 [target setDelegate:nil];
102 // make target's window controller believe that it's now controlling us
103 [[target windowController] setWindow:self];
105 oldTabBarStyle = [[view tabBarControl] styleName];
106 [[view tabBarControl] setStyleNamed:@"Unified"];
109 oldPosition = [view frame].origin;
111 [view removeFromSuperviewWithoutNeedingDisplay];
112 [[self contentView] addSubview:view];
113 [self setInitialFirstResponder:[view textView]];
115 // NOTE: Calling setTitle:nil causes an exception to be raised (and it is
116 // possible that 'target' has no title when we get here).
118 [self setTitle:[target title]];
120 [self setOpaque:[target isOpaque]];
122 // don't set this sooner, so we don't get an additional
123 // focus gained message
124 [self setDelegate:delegate];
126 // move vim view to the window's center
129 // make us visible and target invisible
130 [target orderOut:self];
131 [self makeKeyAndOrderFront:self];
135 CGDisplayFade(token, .25, kCGDisplayBlendSolidColor,
136 kCGDisplayBlendNormal, .0, .0, .0, false);
137 CGReleaseDisplayFadeReservation(token);
141 - (void)leaveFullscreen
144 Boolean didBlend = NO;
145 CGDisplayFadeReservationToken token;
146 if (CGAcquireDisplayFadeReservation(.5, &token) == kCGErrorSuccess) {
147 CGDisplayFade(token, .25, kCGDisplayBlendNormal,
148 kCGDisplayBlendSolidColor, .0, .0, .0, true);
152 // fix up target controller
153 [self retain]; // NSWindowController releases us once
154 [[self windowController] setWindow:target];
156 [[view tabBarControl] setStyleNamed:oldTabBarStyle];
159 id delegate = [self delegate];
160 [self setDelegate:nil];
162 // move text view back to original window, hide fullscreen window,
163 // show original window
164 // do this _after_ resetting delegate and window controller, so the
165 // window controller doesn't get a focus lost message from the fullscreen
167 [view removeFromSuperviewWithoutNeedingDisplay];
168 [[target contentView] addSubview:view];
169 [view setFrameOrigin:oldPosition];
172 // Set the text view to initial first responder, otherwise the 'plus'
173 // button on the tabline steals the first responder status.
174 [target setInitialFirstResponder:[view textView]];
176 [target makeKeyAndOrderFront:self];
178 // ...but we don't want a focus gained message either, so don't set this
180 [target setDelegate:delegate];
184 CGDisplayFade(token, .25, kCGDisplayBlendSolidColor,
185 kCGDisplayBlendNormal, .0, .0, .0, false);
186 CGReleaseDisplayFadeReservation(token);
189 [self revealDockIfAppropriate];
191 [self autorelease]; // Balance the above retain
194 // Title-less windows normally don't receive key presses, override this
195 - (BOOL)canBecomeKeyWindow
200 // Title-less windows normally can't become main which means that another
201 // non-fullscreen window will have the "active" titlebar in expose. Bad, fix it.
202 - (BOOL)canBecomeMainWindow
209 NSRect outer = [self frame], inner = [view frame];
210 //NSLog(@"%s %@%@", _cmd, NSStringFromRect(outer), NSStringFromRect(inner));
212 NSPoint origin = NSMakePoint((outer.size.width - inner.size.width)/2,
213 (outer.size.height - inner.size.height)/2);
214 [view setFrameOrigin:origin];
217 - (void)scrollWheel:(NSEvent *)theEvent
219 [[view textView] scrollWheel:theEvent];
222 - (void)performClose:(id)sender
224 id wc = [self windowController];
225 if ([wc respondsToSelector:@selector(performClose:)])
226 [wc performClose:sender];
228 [super performClose:sender];
231 @end // MMFullscreenWindow
236 @implementation MMFullscreenWindow (Private)
238 - (BOOL)isOnPrimaryScreen
240 // The primary screen is the screen the menu bar is on. This is different
241 // from [NSScreen mainScreen] (which returns the screen containing the
243 NSArray *screens = [NSScreen screens];
244 if (screens == nil || [screens count] < 1)
247 return [self screen] == [screens objectAtIndex:0];
250 - (void)hideDockIfAppropriate
252 // Hide menu and dock, both appear on demand.
254 // Don't hide the dock if going fullscreen on a non-primary screen. Also,
255 // if there are several fullscreen windows on the primary screen, only
256 // hide dock and friends for the first fullscreen window (and display
257 // them again after the last fullscreen window has been closed).
259 // Another way to deal with several fullscreen windows would be to hide/
260 // reveal the dock each time a fullscreen window gets/loses focus, but
261 // this way it's less distracting.
263 // XXX: If you have a fullscreen window on a secondary monitor and unplug
264 // the monitor, this will probably not work right.
266 if ([self isOnPrimaryScreen]) {
267 if (numFullscreenWindows == 0) {
268 SetSystemUIMode(kUIModeAllSuppressed, 0); //requires 10.3
270 ++numFullscreenWindows;
274 - (void)revealDockIfAppropriate
276 // order menu and dock back in
277 if ([self isOnPrimaryScreen]) {
278 --numFullscreenWindows;
279 if (numFullscreenWindows == 0) {
280 SetSystemUIMode(kUIModeNormal, 0);
285 @end // MMFullscreenWindow (Private)