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
225 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
226 backing:(NSBackingStoreType)backingType defer:(BOOL)flag
228 b_dark_interface = config_GetInt(VLCIntf, "macosx-interfacestyle");
230 if (b_dark_interface) {
231 styleMask = NSBorderlessWindowMask;
232 #ifdef MAC_OS_X_VERSION_10_7
233 if (!OSX_SNOW_LEOPARD)
234 styleMask |= NSResizableWindowMask;
238 self = [super initWithContentRect:contentRect styleMask:styleMask
239 backing:backingType defer:flag];
241 /* we want to be moveable regardless of our style */
242 [self setMovableByWindowBackground: YES];
247 - (void)setTitle:(NSString *)title
249 if (b_dark_interface && o_titlebar_view)
250 [o_titlebar_view setWindowTitle: title];
252 [super setTitle: title];
256 #pragma mark zoom / minimize / close
258 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
260 SEL s_menuAction = [menuItem action];
262 if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
265 return [super validateMenuItem:menuItem];
268 - (BOOL)windowShouldClose:(id)sender
273 - (void)performClose:(id)sender
275 if (!([self styleMask] & NSTitledWindowMask)) {
276 [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowWillCloseNotification object:self];
278 [self orderOut: sender];
280 [super performClose: sender];
283 - (void)performMiniaturize:(id)sender
285 if (!([self styleMask] & NSTitledWindowMask))
286 [self miniaturize: sender];
288 [super performMiniaturize: sender];
291 - (void)performZoom:(id)sender
293 if (!([self styleMask] & NSTitledWindowMask))
294 [self customZoom: sender];
296 [super performZoom: sender];
299 - (void)zoom:(id)sender
301 if (!([self styleMask] & NSTitledWindowMask))
302 [self customZoom: sender];
304 [super zoom: sender];
308 * Given a proposed frame rectangle, return a modified version
309 * which will fit inside the screen.
311 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
312 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
313 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
314 * Copyright (C) 1996 Free Software Foundation, Inc.
316 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
318 NSRect screenRect = [screen visibleFrame];
321 /* Move top edge of the window inside the screen */
322 difference = NSMaxY (frameRect) - NSMaxY (screenRect);
323 if (difference > 0) {
324 frameRect.origin.y -= difference;
327 /* If the window is resizable, resize it (if needed) so that the
328 bottom edge is on the screen or can be on the screen when the user moves
330 difference = NSMaxY (screenRect) - NSMaxY (frameRect);
331 if (_styleMask & NSResizableWindowMask) {
334 difference2 = screenRect.origin.y - frameRect.origin.y;
335 difference2 -= difference;
336 // Take in account the space between the top of window and the top of the
337 // screen which can be used to move the bottom of the window on the screen
338 if (difference2 > 0) {
339 frameRect.size.height -= difference2;
340 frameRect.origin.y += difference2;
343 /* Ensure that resizing doesn't makewindow smaller than minimum */
344 difference2 = [self minSize].height - frameRect.size.height;
345 if (difference2 > 0) {
346 frameRect.size.height += difference2;
347 frameRect.origin.y -= difference2;
357 Zooms the receiver. This method calls the delegate method
358 windowShouldZoom:toFrame: to determine if the window should
359 be allowed to zoom to full screen.
361 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
362 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
363 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
364 * Copyright (C) 1996 Free Software Foundation, Inc.
366 - (void) customZoom: (id)sender
368 NSRect maxRect = [[self screen] visibleFrame];
369 NSRect currentFrame = [self frame];
371 if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) {
372 maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
375 maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
377 // Compare the new frame with the current one
378 if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
379 && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
380 && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
381 && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST)) {
382 // Already in zoomed mode, reset user frame, if stored
383 if ([self frameAutosaveName] != nil) {
384 [self setFrame: previousSavedFrame display: YES animate: YES];
385 [self saveFrameUsingName: [self frameAutosaveName]];
390 if ([self frameAutosaveName] != nil) {
391 [self saveFrameUsingName: [self frameAutosaveName]];
392 previousSavedFrame = [self frame];
395 [self setFrame: maxRect display: YES animate: YES];
399 #pragma mark Accessibility stuff
401 - (NSArray *)accessibilityAttributeNames
403 if (!b_dark_interface || !o_titlebar_view)
404 return [super accessibilityAttributeNames];
406 static NSMutableArray *attributes = nil;
407 if (attributes == nil) {
408 attributes = [[super accessibilityAttributeNames] mutableCopy];
409 NSArray *appendAttributes = [NSArray arrayWithObjects: NSAccessibilitySubroleAttribute,
410 NSAccessibilityCloseButtonAttribute,
411 NSAccessibilityMinimizeButtonAttribute,
412 NSAccessibilityZoomButtonAttribute,
415 for(NSString *attribute in appendAttributes) {
416 if (![attributes containsObject:attribute])
417 [attributes addObject:attribute];
423 - (id)accessibilityAttributeValue: (NSString*)o_attribute_name
425 if (b_dark_interface && o_titlebar_view) {
426 VLCMainWindowTitleView *o_tbv = o_titlebar_view;
428 if ([o_attribute_name isEqualTo: NSAccessibilitySubroleAttribute])
429 return NSAccessibilityStandardWindowSubrole;
431 if ([o_attribute_name isEqualTo: NSAccessibilityCloseButtonAttribute])
432 return [[o_tbv closeButton] cell];
434 if ([o_attribute_name isEqualTo: NSAccessibilityMinimizeButtonAttribute])
435 return [[o_tbv minimizeButton] cell];
437 if ([o_attribute_name isEqualTo: NSAccessibilityZoomButtonAttribute])
438 return [[o_tbv zoomButton] cell];
441 return [super accessibilityAttributeValue: o_attribute_name];