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];
245 [self setCanBecomeKeyWindow:YES];
250 - (void)setTitle:(NSString *)title
252 if (b_dark_interface && o_titlebar_view)
253 [o_titlebar_view setWindowTitle: title];
255 [super setTitle: title];
259 #pragma mark zoom / minimize / close
261 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
263 SEL s_menuAction = [menuItem action];
265 if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
268 return [super validateMenuItem:menuItem];
271 - (BOOL)windowShouldClose:(id)sender
276 - (void)performClose:(id)sender
278 if (!([self styleMask] & NSTitledWindowMask)) {
279 [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowWillCloseNotification object:self];
281 [self orderOut: sender];
283 [super performClose: sender];
286 - (void)performMiniaturize:(id)sender
288 if (!([self styleMask] & NSTitledWindowMask))
289 [self miniaturize: sender];
291 [super performMiniaturize: sender];
294 - (void)performZoom:(id)sender
296 if (!([self styleMask] & NSTitledWindowMask))
297 [self customZoom: sender];
299 [super performZoom: sender];
302 - (void)zoom:(id)sender
304 if (!([self styleMask] & NSTitledWindowMask))
305 [self customZoom: sender];
307 [super zoom: sender];
311 * Given a proposed frame rectangle, return a modified version
312 * which will fit inside the screen.
314 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
315 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
316 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
317 * Copyright (C) 1996 Free Software Foundation, Inc.
319 - (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
321 NSRect screenRect = [screen visibleFrame];
324 /* Move top edge of the window inside the screen */
325 difference = NSMaxY (frameRect) - NSMaxY (screenRect);
326 if (difference > 0) {
327 frameRect.origin.y -= difference;
330 /* If the window is resizable, resize it (if needed) so that the
331 bottom edge is on the screen or can be on the screen when the user moves
333 difference = NSMaxY (screenRect) - NSMaxY (frameRect);
334 if (_styleMask & NSResizableWindowMask) {
337 difference2 = screenRect.origin.y - frameRect.origin.y;
338 difference2 -= difference;
339 // Take in account the space between the top of window and the top of the
340 // screen which can be used to move the bottom of the window on the screen
341 if (difference2 > 0) {
342 frameRect.size.height -= difference2;
343 frameRect.origin.y += difference2;
346 /* Ensure that resizing doesn't makewindow smaller than minimum */
347 difference2 = [self minSize].height - frameRect.size.height;
348 if (difference2 > 0) {
349 frameRect.size.height += difference2;
350 frameRect.origin.y -= difference2;
360 Zooms the receiver. This method calls the delegate method
361 windowShouldZoom:toFrame: to determine if the window should
362 be allowed to zoom to full screen.
364 * This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
365 * Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
366 * Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
367 * Copyright (C) 1996 Free Software Foundation, Inc.
369 - (void) customZoom: (id)sender
371 NSRect maxRect = [[self screen] visibleFrame];
372 NSRect currentFrame = [self frame];
374 if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) {
375 maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
378 maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
380 // Compare the new frame with the current one
381 if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
382 && (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
383 && (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
384 && (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST)) {
385 // Already in zoomed mode, reset user frame, if stored
386 if ([self frameAutosaveName] != nil) {
387 [self setFrame: previousSavedFrame display: YES animate: YES];
388 [self saveFrameUsingName: [self frameAutosaveName]];
393 if ([self frameAutosaveName] != nil) {
394 [self saveFrameUsingName: [self frameAutosaveName]];
395 previousSavedFrame = [self frame];
398 [self setFrame: maxRect display: YES animate: YES];
402 #pragma mark Accessibility stuff
404 - (NSArray *)accessibilityAttributeNames
406 if (!b_dark_interface || !o_titlebar_view)
407 return [super accessibilityAttributeNames];
409 static NSMutableArray *attributes = nil;
410 if (attributes == nil) {
411 attributes = [[super accessibilityAttributeNames] mutableCopy];
412 NSArray *appendAttributes = [NSArray arrayWithObjects: NSAccessibilitySubroleAttribute,
413 NSAccessibilityCloseButtonAttribute,
414 NSAccessibilityMinimizeButtonAttribute,
415 NSAccessibilityZoomButtonAttribute,
418 for(NSString *attribute in appendAttributes) {
419 if (![attributes containsObject:attribute])
420 [attributes addObject:attribute];
426 - (id)accessibilityAttributeValue: (NSString*)o_attribute_name
428 if (b_dark_interface && o_titlebar_view) {
429 VLCMainWindowTitleView *o_tbv = o_titlebar_view;
431 if ([o_attribute_name isEqualTo: NSAccessibilitySubroleAttribute])
432 return NSAccessibilityStandardWindowSubrole;
434 if ([o_attribute_name isEqualTo: NSAccessibilityCloseButtonAttribute])
435 return [[o_tbv closeButton] cell];
437 if ([o_attribute_name isEqualTo: NSAccessibilityMinimizeButtonAttribute])
438 return [[o_tbv minimizeButton] cell];
440 if ([o_attribute_name isEqualTo: NSAccessibilityZoomButtonAttribute])
441 return [[o_tbv zoomButton] cell];
444 return [super accessibilityAttributeValue: o_attribute_name];