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 controlsBar=o_controls_bar;
227 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
228 backing:(NSBackingStoreType)backingType defer:(BOOL)flag
230 b_dark_interface = config_GetInt(VLCIntf, "macosx-interfacestyle");
232 if (b_dark_interface) {
233 styleMask = NSBorderlessWindowMask;
234 #ifdef MAC_OS_X_VERSION_10_7
235 if (!OSX_SNOW_LEOPARD)
236 styleMask |= NSResizableWindowMask;
240 self = [super initWithContentRect:contentRect styleMask:styleMask
241 backing:backingType defer:flag];
243 /* we want to be moveable regardless of our style */
244 [self setMovableByWindowBackground: YES];
249 - (void)setTitle:(NSString *)title
251 if (b_dark_interface && o_titlebar_view)
252 [o_titlebar_view setWindowTitle: title];
254 [super setTitle: title];
258 #pragma mark zoom / minimize / close
260 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
262 SEL s_menuAction = [menuItem action];
264 if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
267 return [super validateMenuItem:menuItem];
270 - (BOOL)windowShouldClose:(id)sender
275 - (void)performClose:(id)sender
277 if (!([self styleMask] & NSTitledWindowMask)) {
278 [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowWillCloseNotification object:self];
280 [self orderOut: sender];
282 [super performClose: sender];
285 - (void)performMiniaturize:(id)sender
287 if (!([self styleMask] & NSTitledWindowMask))
288 [self miniaturize: sender];
290 [super performMiniaturize: sender];
293 - (void)performZoom:(id)sender
295 if (!([self styleMask] & NSTitledWindowMask))
296 [self customZoom: sender];
298 [super performZoom: sender];
301 - (void)zoom:(id)sender
303 if (!([self styleMask] & NSTitledWindowMask))
304 [self customZoom: sender];
306 [super zoom: sender];
310 * Given a proposed frame rectangle, return a modified version
311 * which will fit inside the screen.
313 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
314 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
315 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
316 * Copyright (C) 1996 Free Software Foundation, Inc.
318 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
320 NSRect screenRect = [screen visibleFrame];
323 /* Move top edge of the window inside the screen */
324 difference = NSMaxY (frameRect) - NSMaxY (screenRect);
325 if (difference > 0) {
326 frameRect.origin.y -= difference;
329 /* If the window is resizable, resize it (if needed) so that the
330 bottom edge is on the screen or can be on the screen when the user moves
332 difference = NSMaxY (screenRect) - NSMaxY (frameRect);
333 if (_styleMask & NSResizableWindowMask) {
336 difference2 = screenRect.origin.y - frameRect.origin.y;
337 difference2 -= difference;
338 // Take in account the space between the top of window and the top of the
339 // screen which can be used to move the bottom of the window on the screen
340 if (difference2 > 0) {
341 frameRect.size.height -= difference2;
342 frameRect.origin.y += difference2;
345 /* Ensure that resizing doesn't makewindow smaller than minimum */
346 difference2 = [self minSize].height - frameRect.size.height;
347 if (difference2 > 0) {
348 frameRect.size.height += difference2;
349 frameRect.origin.y -= difference2;
359 Zooms the receiver. This method calls the delegate method
360 windowShouldZoom:toFrame: to determine if the window should
361 be allowed to zoom to full screen.
363 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
364 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
365 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
366 * Copyright (C) 1996 Free Software Foundation, Inc.
368 - (void) customZoom: (id)sender
370 NSRect maxRect = [[self screen] visibleFrame];
371 NSRect currentFrame = [self frame];
373 if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) {
374 maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
377 maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
379 // Compare the new frame with the current one
380 if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
381 && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
382 && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
383 && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST)) {
384 // Already in zoomed mode, reset user frame, if stored
385 if ([self frameAutosaveName] != nil) {
386 [self setFrame: previousSavedFrame display: YES animate: YES];
387 [self saveFrameUsingName: [self frameAutosaveName]];
392 if ([self frameAutosaveName] != nil) {
393 [self saveFrameUsingName: [self frameAutosaveName]];
394 previousSavedFrame = [self frame];
397 [self setFrame: maxRect display: YES animate: YES];
401 #pragma mark Accessibility stuff
403 - (NSArray *)accessibilityAttributeNames
405 if (!b_dark_interface || !o_titlebar_view)
406 return [super accessibilityAttributeNames];
408 static NSMutableArray *attributes = nil;
409 if (attributes == nil) {
410 attributes = [[super accessibilityAttributeNames] mutableCopy];
411 NSArray *appendAttributes = [NSArray arrayWithObjects: NSAccessibilitySubroleAttribute,
412 NSAccessibilityCloseButtonAttribute,
413 NSAccessibilityMinimizeButtonAttribute,
414 NSAccessibilityZoomButtonAttribute,
417 for(NSString *attribute in appendAttributes) {
418 if (![attributes containsObject:attribute])
419 [attributes addObject:attribute];
425 - (id)accessibilityAttributeValue: (NSString*)o_attribute_name
427 if (b_dark_interface && o_titlebar_view) {
428 VLCMainWindowTitleView *o_tbv = o_titlebar_view;
430 if ([o_attribute_name isEqualTo: NSAccessibilitySubroleAttribute])
431 return NSAccessibilityStandardWindowSubrole;
433 if ([o_attribute_name isEqualTo: NSAccessibilityCloseButtonAttribute])
434 return [[o_tbv closeButton] cell];
436 if ([o_attribute_name isEqualTo: NSAccessibilityMinimizeButtonAttribute])
437 return [[o_tbv minimizeButton] cell];
439 if ([o_attribute_name isEqualTo: NSAccessibilityZoomButtonAttribute])
440 return [[o_tbv zoomButton] cell];
443 return [super accessibilityAttributeValue: o_attribute_name];