1 /*****************************************************************************
2 * Windows.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2012 VLC authors and VideoLAN
7 * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
8 * David Fuhrmann <david dot fuhrmann at googlemail dot com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
27 #import "CoreInteraction.h"
29 /*****************************************************************************
32 * Missing extension to NSWindow
33 *****************************************************************************/
35 @implementation VLCWindow
36 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
37 backing:(NSBackingStoreType)backingType defer:(BOOL)flag
39 self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
41 /* we don't want this window to be restored on relaunch */
42 if (!OSX_SNOW_LEOPARD)
43 [self setRestorable:NO];
48 - (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
50 b_isset_canBecomeKeyWindow = YES;
51 b_canBecomeKeyWindow = canBecomeKey;
54 - (BOOL)canBecomeKeyWindow
56 if (b_isset_canBecomeKeyWindow)
57 return b_canBecomeKeyWindow;
59 return [super canBecomeKeyWindow];
62 - (void)setCanBecomeMainWindow: (BOOL)canBecomeMain
64 b_isset_canBecomeMainWindow = YES;
65 b_canBecomeMainWindow = canBecomeMain;
68 - (BOOL)canBecomeMainWindow
70 if (b_isset_canBecomeMainWindow)
71 return b_canBecomeMainWindow;
73 return [super canBecomeMainWindow];
76 - (void)closeAndAnimate: (BOOL)animate
85 invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(close)]];
86 [invoc setTarget: self];
88 if (![self isVisible] || [self alphaValue] == 0.0) {
93 [self orderOut: self animate: YES callback: invoc];
96 - (void)orderOut: (id)sender animate: (BOOL)animate
98 NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(orderOut:)]];
99 [invoc setTarget: self];
100 [invoc setArgument: sender atIndex: 0];
101 [self orderOut: sender animate: animate callback: invoc];
104 - (void)orderOut: (id)sender animate: (BOOL)animate callback:(NSInvocation *)callback
106 NSViewAnimation *anim;
107 NSViewAnimation *current_anim;
108 NSMutableDictionary *dict;
111 [self orderOut: sender];
115 dict = [[NSMutableDictionary alloc] initWithCapacity:2];
117 [dict setObject:self forKey:NSViewAnimationTargetKey];
119 [dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
120 anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
123 [anim setAnimationBlockingMode:NSAnimationNonblocking];
124 [anim setDuration:0.9];
125 [anim setFrameRate:30];
126 [anim setUserInfo: callback];
128 @synchronized(self) {
129 current_anim = self->o_current_animation;
131 if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating]) {
135 [current_anim stopAnimation];
136 [anim setCurrentProgress:1.0 - [current_anim currentProgress]];
137 [current_anim release];
140 [anim setCurrentProgress:1.0 - [self alphaValue]];
141 self->o_current_animation = anim;
142 [anim startAnimation];
147 - (void)orderFront: (id)sender animate: (BOOL)animate
149 NSViewAnimation *anim;
150 NSViewAnimation *current_anim;
151 NSMutableDictionary *dict;
154 [super orderFront: sender];
155 [self setAlphaValue: 1.0];
159 if (![self isVisible]) {
160 [self setAlphaValue: 0.0];
161 [super orderFront: sender];
163 else if ([self alphaValue] == 1.0) {
164 [super orderFront: self];
168 dict = [[NSMutableDictionary alloc] initWithCapacity:2];
170 [dict setObject:self forKey:NSViewAnimationTargetKey];
172 [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
173 anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
176 [anim setAnimationBlockingMode:NSAnimationNonblocking];
177 [anim setDuration:0.5];
178 [anim setFrameRate:30];
180 @synchronized(self) {
181 current_anim = self->o_current_animation;
183 if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating]) {
187 [current_anim stopAnimation];
188 [anim setCurrentProgress:1.0 - [current_anim currentProgress]];
189 [current_anim release];
192 [anim setCurrentProgress:[self alphaValue]];
193 self->o_current_animation = anim;
194 [self orderFront: sender];
195 [anim startAnimation];
200 - (void)animationDidEnd:(NSAnimation*)anim
202 if ([self alphaValue] <= 0.0) {
203 NSInvocation * invoc;
204 [super orderOut: nil];
205 [self setAlphaValue: 1.0];
206 if ((invoc = [anim userInfo]))
214 /*****************************************************************************
215 * VLCVideoWindowCommon
217 * Common code for main window, detached window and extra video window
218 *****************************************************************************/
220 @implementation VLCVideoWindowCommon
222 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
223 backing:(NSBackingStoreType)backingType defer:(BOOL)flag
225 b_dark_interface = config_GetInt(VLCIntf, "macosx-interfacestyle");
227 if (b_dark_interface) {
228 styleMask = NSBorderlessWindowMask;
229 #ifdef MAC_OS_X_VERSION_10_7
230 if (!OSX_SNOW_LEOPARD)
231 styleMask |= NSResizableWindowMask;
235 self = [super initWithContentRect:contentRect styleMask:styleMask
236 backing:backingType defer:flag];
238 /* we want to be moveable regardless of our style */
239 [self setMovableByWindowBackground: YES];
244 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
246 SEL s_menuAction = [menuItem action];
248 if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
251 return [super validateMenuItem:menuItem];
254 - (BOOL)windowShouldClose:(id)sender
259 - (void)performClose:(id)sender
261 if (!([self styleMask] & NSTitledWindowMask)) {
262 [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowWillCloseNotification object:self];
264 [self orderOut: sender];
266 [super performClose: sender];
269 - (void)performMiniaturize:(id)sender
271 if (!([self styleMask] & NSTitledWindowMask))
272 [self miniaturize: sender];
274 [super performMiniaturize: sender];
277 - (void)performZoom:(id)sender
279 if (!([self styleMask] & NSTitledWindowMask))
280 [self customZoom: sender];
282 [super performZoom: sender];
285 - (void)zoom:(id)sender
287 if (!([self styleMask] & NSTitledWindowMask))
288 [self customZoom: sender];
290 [super zoom: sender];
294 * Given a proposed frame rectangle, return a modified version
295 * which will fit inside the screen.
297 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
298 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
299 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
300 * Copyright (C) 1996 Free Software Foundation, Inc.
302 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
304 NSRect screenRect = [screen visibleFrame];
307 /* Move top edge of the window inside the screen */
308 difference = NSMaxY (frameRect) - NSMaxY (screenRect);
309 if (difference > 0) {
310 frameRect.origin.y -= difference;
313 /* If the window is resizable, resize it (if needed) so that the
314 bottom edge is on the screen or can be on the screen when the user moves
316 difference = NSMaxY (screenRect) - NSMaxY (frameRect);
317 if (_styleMask & NSResizableWindowMask) {
320 difference2 = screenRect.origin.y - frameRect.origin.y;
321 difference2 -= difference;
322 // Take in account the space between the top of window and the top of the
323 // screen which can be used to move the bottom of the window on the screen
324 if (difference2 > 0) {
325 frameRect.size.height -= difference2;
326 frameRect.origin.y += difference2;
329 /* Ensure that resizing doesn't makewindow smaller than minimum */
330 difference2 = [self minSize].height - frameRect.size.height;
331 if (difference2 > 0) {
332 frameRect.size.height += difference2;
333 frameRect.origin.y -= difference2;
343 Zooms the receiver. This method calls the delegate method
344 windowShouldZoom:toFrame: to determine if the window should
345 be allowed to zoom to full screen.
347 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
348 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
349 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
350 * Copyright (C) 1996 Free Software Foundation, Inc.
352 - (void) customZoom: (id)sender
354 NSRect maxRect = [[self screen] visibleFrame];
355 NSRect currentFrame = [self frame];
357 if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) {
358 maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
361 maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
363 // Compare the new frame with the current one
364 if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
365 && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
366 && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
367 && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST)) {
368 // Already in zoomed mode, reset user frame, if stored
369 if ([self frameAutosaveName] != nil) {
370 [self setFrame: previousSavedFrame display: YES animate: YES];
371 [self saveFrameUsingName: [self frameAutosaveName]];
376 if ([self frameAutosaveName] != nil) {
377 [self saveFrameUsingName: [self frameAutosaveName]];
378 previousSavedFrame = [self frame];
381 [self setFrame: maxRect display: YES animate: YES];