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 @synthesize videoView=o_video_view;
223 @synthesize controlsBar=o_controls_bar;
228 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
229 backing:(NSBackingStoreType)backingType defer:(BOOL)flag
231 b_dark_interface = config_GetInt(VLCIntf, "macosx-interfacestyle");
233 if (b_dark_interface) {
234 styleMask = NSBorderlessWindowMask;
235 #ifdef MAC_OS_X_VERSION_10_7
236 if (!OSX_SNOW_LEOPARD)
237 styleMask |= NSResizableWindowMask;
241 self = [super initWithContentRect:contentRect styleMask:styleMask
242 backing:backingType defer:flag];
244 /* we want to be moveable regardless of our style */
245 [self setMovableByWindowBackground: YES];
246 [self setCanBecomeKeyWindow:YES];
251 - (void)setTitle:(NSString *)title
253 if (b_dark_interface && o_titlebar_view)
254 [o_titlebar_view setWindowTitle: title];
256 [super setTitle: title];
260 #pragma mark zoom / minimize / close
262 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
264 SEL s_menuAction = [menuItem action];
266 if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
269 return [super validateMenuItem:menuItem];
272 - (BOOL)windowShouldClose:(id)sender
277 - (void)performClose:(id)sender
279 if (!([self styleMask] & NSTitledWindowMask)) {
280 [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowWillCloseNotification object:self];
282 [self orderOut: sender];
284 [super performClose: sender];
287 - (void)performMiniaturize:(id)sender
289 if (!([self styleMask] & NSTitledWindowMask))
290 [self miniaturize: sender];
292 [super performMiniaturize: sender];
295 - (void)performZoom:(id)sender
297 if (!([self styleMask] & NSTitledWindowMask))
298 [self customZoom: sender];
300 [super performZoom: sender];
303 - (void)zoom:(id)sender
305 if (!([self styleMask] & NSTitledWindowMask))
306 [self customZoom: sender];
308 [super zoom: sender];
312 * Given a proposed frame rectangle, return a modified version
313 * which will fit inside the screen.
315 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
316 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
317 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
318 * Copyright (C) 1996 Free Software Foundation, Inc.
320 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
322 NSRect screenRect = [screen visibleFrame];
325 /* Move top edge of the window inside the screen */
326 difference = NSMaxY (frameRect) - NSMaxY (screenRect);
327 if (difference > 0) {
328 frameRect.origin.y -= difference;
331 /* If the window is resizable, resize it (if needed) so that the
332 bottom edge is on the screen or can be on the screen when the user moves
334 difference = NSMaxY (screenRect) - NSMaxY (frameRect);
335 if (_styleMask & NSResizableWindowMask) {
338 difference2 = screenRect.origin.y - frameRect.origin.y;
339 difference2 -= difference;
340 // Take in account the space between the top of window and the top of the
341 // screen which can be used to move the bottom of the window on the screen
342 if (difference2 > 0) {
343 frameRect.size.height -= difference2;
344 frameRect.origin.y += difference2;
347 /* Ensure that resizing doesn't makewindow smaller than minimum */
348 difference2 = [self minSize].height - frameRect.size.height;
349 if (difference2 > 0) {
350 frameRect.size.height += difference2;
351 frameRect.origin.y -= difference2;
361 Zooms the receiver. This method calls the delegate method
362 windowShouldZoom:toFrame: to determine if the window should
363 be allowed to zoom to full screen.
365 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
366 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
367 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
368 * Copyright (C) 1996 Free Software Foundation, Inc.
370 - (void) customZoom: (id)sender
372 NSRect maxRect = [[self screen] visibleFrame];
373 NSRect currentFrame = [self frame];
375 if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) {
376 maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
379 maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
381 // Compare the new frame with the current one
382 if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
383 && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
384 && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
385 && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST)) {
386 // Already in zoomed mode, reset user frame, if stored
387 if ([self frameAutosaveName] != nil) {
388 [self setFrame: previousSavedFrame display: YES animate: YES];
389 [self saveFrameUsingName: [self frameAutosaveName]];
394 if ([self frameAutosaveName] != nil) {
395 [self saveFrameUsingName: [self frameAutosaveName]];
396 previousSavedFrame = [self frame];
399 [self setFrame: maxRect display: YES animate: YES];
403 #pragma mark Accessibility stuff
405 - (NSArray *)accessibilityAttributeNames
407 if (!b_dark_interface || !o_titlebar_view)
408 return [super accessibilityAttributeNames];
410 static NSMutableArray *attributes = nil;
411 if (attributes == nil) {
412 attributes = [[super accessibilityAttributeNames] mutableCopy];
413 NSArray *appendAttributes = [NSArray arrayWithObjects: NSAccessibilitySubroleAttribute,
414 NSAccessibilityCloseButtonAttribute,
415 NSAccessibilityMinimizeButtonAttribute,
416 NSAccessibilityZoomButtonAttribute,
419 for(NSString *attribute in appendAttributes) {
420 if (![attributes containsObject:attribute])
421 [attributes addObject:attribute];
427 - (id)accessibilityAttributeValue: (NSString*)o_attribute_name
429 if (b_dark_interface && o_titlebar_view) {
430 VLCMainWindowTitleView *o_tbv = o_titlebar_view;
432 if ([o_attribute_name isEqualTo: NSAccessibilitySubroleAttribute])
433 return NSAccessibilityStandardWindowSubrole;
435 if ([o_attribute_name isEqualTo: NSAccessibilityCloseButtonAttribute])
436 return [[o_tbv closeButton] cell];
438 if ([o_attribute_name isEqualTo: NSAccessibilityMinimizeButtonAttribute])
439 return [[o_tbv minimizeButton] cell];
441 if ([o_attribute_name isEqualTo: NSAccessibilityZoomButtonAttribute])
442 return [[o_tbv zoomButton] cell];
445 return [super accessibilityAttributeValue: o_attribute_name];