|
|
|
|
/*****************************************************************************
|
|
|
|
|
* Windows.m: MacOS X interface module
|
|
|
|
|
*****************************************************************************
|
|
|
|
|
* Copyright (C) 2012 VLC authors and VideoLAN
|
|
|
|
|
* $Id$
|
|
|
|
|
*
|
|
|
|
|
* Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
|
|
|
|
|
* David Fuhrmann <david dot fuhrmann at googlemail dot com>
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#import "Windows.h"
|
|
|
|
|
#import "intf.h"
|
|
|
|
|
#import "CoreInteraction.h"
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* VLCWindow
|
|
|
|
|
*
|
|
|
|
|
* Missing extension to NSWindow
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
@implementation VLCWindow
|
|
|
|
|
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
|
|
|
|
|
backing:(NSBackingStoreType)backingType defer:(BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
|
|
|
|
|
if (self) {
|
|
|
|
|
/* we don't want this window to be restored on relaunch */
|
|
|
|
|
if (!OSX_SNOW_LEOPARD)
|
|
|
|
|
[self setRestorable:NO];
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
|
|
|
|
|
{
|
|
|
|
|
b_isset_canBecomeKeyWindow = YES;
|
|
|
|
|
b_canBecomeKeyWindow = canBecomeKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)canBecomeKeyWindow
|
|
|
|
|
{
|
|
|
|
|
if (b_isset_canBecomeKeyWindow)
|
|
|
|
|
return b_canBecomeKeyWindow;
|
|
|
|
|
|
|
|
|
|
return [super canBecomeKeyWindow];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setCanBecomeMainWindow: (BOOL)canBecomeMain
|
|
|
|
|
{
|
|
|
|
|
b_isset_canBecomeMainWindow = YES;
|
|
|
|
|
b_canBecomeMainWindow = canBecomeMain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)canBecomeMainWindow
|
|
|
|
|
{
|
|
|
|
|
if (b_isset_canBecomeMainWindow)
|
|
|
|
|
return b_canBecomeMainWindow;
|
|
|
|
|
|
|
|
|
|
return [super canBecomeMainWindow];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)closeAndAnimate: (BOOL)animate
|
|
|
|
|
{
|
|
|
|
|
NSInvocation *invoc;
|
|
|
|
|
|
|
|
|
|
if (!animate) {
|
|
|
|
|
[super close];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(close)]];
|
|
|
|
|
[invoc setTarget: self];
|
|
|
|
|
|
|
|
|
|
if (![self isVisible] || [self alphaValue] == 0.0) {
|
|
|
|
|
[super close];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[self orderOut: self animate: YES callback: invoc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)orderOut: (id)sender animate: (BOOL)animate
|
|
|
|
|
{
|
|
|
|
|
NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(orderOut:)]];
|
|
|
|
|
[invoc setTarget: self];
|
|
|
|
|
[invoc setArgument: sender atIndex: 0];
|
|
|
|
|
[self orderOut: sender animate: animate callback: invoc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)orderOut: (id)sender animate: (BOOL)animate callback:(NSInvocation *)callback
|
|
|
|
|
{
|
|
|
|
|
NSViewAnimation *anim;
|
|
|
|
|
NSViewAnimation *current_anim;
|
|
|
|
|
NSMutableDictionary *dict;
|
|
|
|
|
|
|
|
|
|
if (!animate) {
|
|
|
|
|
[self orderOut: sender];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dict = [[NSMutableDictionary alloc] initWithCapacity:2];
|
|
|
|
|
|
|
|
|
|
[dict setObject:self forKey:NSViewAnimationTargetKey];
|
|
|
|
|
|
|
|
|
|
[dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
|
|
|
|
|
anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
|
|
|
|
|
[dict release];
|
|
|
|
|
|
|
|
|
|
[anim setAnimationBlockingMode:NSAnimationNonblocking];
|
|
|
|
|
[anim setDuration:0.9];
|
|
|
|
|
[anim setFrameRate:30];
|
|
|
|
|
[anim setUserInfo: callback];
|
|
|
|
|
|
|
|
|
|
@synchronized(self) {
|
|
|
|
|
current_anim = self->o_current_animation;
|
|
|
|
|
|
|
|
|
|
if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating]) {
|
|
|
|
|
[anim release];
|
|
|
|
|
} else {
|
|
|
|
|
if (current_anim) {
|
|
|
|
|
[current_anim stopAnimation];
|
|
|
|
|
[anim setCurrentProgress:1.0 - [current_anim currentProgress]];
|
|
|
|
|
[current_anim release];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
[anim setCurrentProgress:1.0 - [self alphaValue]];
|
|
|
|
|
self->o_current_animation = anim;
|
|
|
|
|
[anim startAnimation];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)orderFront: (id)sender animate: (BOOL)animate
|
|
|
|
|
{
|
|
|
|
|
NSViewAnimation *anim;
|
|
|
|
|
NSViewAnimation *current_anim;
|
|
|
|
|
NSMutableDictionary *dict;
|
|
|
|
|
|
|
|
|
|
if (!animate) {
|
|
|
|
|
[super orderFront: sender];
|
|
|
|
|
[self setAlphaValue: 1.0];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (![self isVisible]) {
|
|
|
|
|
[self setAlphaValue: 0.0];
|
|
|
|
|
[super orderFront: sender];
|
|
|
|
|
}
|
|
|
|
|
else if ([self alphaValue] == 1.0) {
|
|
|
|
|
[super orderFront: self];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dict = [[NSMutableDictionary alloc] initWithCapacity:2];
|
|
|
|
|
|
|
|
|
|
[dict setObject:self forKey:NSViewAnimationTargetKey];
|
|
|
|
|
|
|
|
|
|
[dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
|
|
|
|
|
anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
|
|
|
|
|
[dict release];
|
|
|
|
|
|
|
|
|
|
[anim setAnimationBlockingMode:NSAnimationNonblocking];
|
|
|
|
|
[anim setDuration:0.5];
|
|
|
|
|
[anim setFrameRate:30];
|
|
|
|
|
|
|
|
|
|
@synchronized(self) {
|
|
|
|
|
current_anim = self->o_current_animation;
|
|
|
|
|
|
|
|
|
|
if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating]) {
|
|
|
|
|
[anim release];
|
|
|
|
|
} else {
|
|
|
|
|
if (current_anim) {
|
|
|
|
|
[current_anim stopAnimation];
|
|
|
|
|
[anim setCurrentProgress:1.0 - [current_anim currentProgress]];
|
|
|
|
|
[current_anim release];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
[anim setCurrentProgress:[self alphaValue]];
|
|
|
|
|
self->o_current_animation = anim;
|
|
|
|
|
[self orderFront: sender];
|
|
|
|
|
[anim startAnimation];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)animationDidEnd:(NSAnimation*)anim
|
|
|
|
|
{
|
|
|
|
|
if ([self alphaValue] <= 0.0) {
|
|
|
|
|
NSInvocation * invoc;
|
|
|
|
|
[super orderOut: nil];
|
|
|
|
|
[self setAlphaValue: 1.0];
|
|
|
|
|
if ((invoc = [anim userInfo]))
|
|
|
|
|
[invoc invoke];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* VLCVideoWindowCommon
|
|
|
|
|
*
|
|
|
|
|
* Common code for main window, detached window and extra video window
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
@implementation VLCVideoWindowCommon
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
#pragma mark Init
|
|
|
|
|
|
|
|
|
|
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
|
|
|
|
|
backing:(NSBackingStoreType)backingType defer:(BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
b_dark_interface = config_GetInt(VLCIntf, "macosx-interfacestyle");
|
|
|
|
|
|
|
|
|
|
if (b_dark_interface) {
|
|
|
|
|
styleMask = NSBorderlessWindowMask;
|
|
|
|
|
#ifdef MAC_OS_X_VERSION_10_7
|
|
|
|
|
if (!OSX_SNOW_LEOPARD)
|
|
|
|
|
styleMask |= NSResizableWindowMask;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self = [super initWithContentRect:contentRect styleMask:styleMask
|
|
|
|
|
backing:backingType defer:flag];
|
|
|
|
|
|
|
|
|
|
/* we want to be moveable regardless of our style */
|
|
|
|
|
[self setMovableByWindowBackground: YES];
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setTitle:(NSString *)title
|
|
|
|
|
{
|
|
|
|
|
if (b_dark_interface && o_titlebar_view)
|
|
|
|
|
[o_titlebar_view setWindowTitle: title];
|
|
|
|
|
|
|
|
|
|
[super setTitle: title];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
#pragma mark zoom / minimize / close
|
|
|
|
|
|
|
|
|
|
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
|
|
|
|
|
{
|
|
|
|
|
SEL s_menuAction = [menuItem action];
|
|
|
|
|
|
|
|
|
|
if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
|
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
|
|
return [super validateMenuItem:menuItem];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)windowShouldClose:(id)sender
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)performClose:(id)sender
|
|
|
|
|
{
|
|
|
|
|
if (!([self styleMask] & NSTitledWindowMask)) {
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NSWindowWillCloseNotification object:self];
|
|
|
|
|
|
|
|
|
|
[self orderOut: sender];
|
|
|
|
|
} else
|
|
|
|
|
[super performClose: sender];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)performMiniaturize:(id)sender
|
|
|
|
|
{
|
|
|
|
|
if (!([self styleMask] & NSTitledWindowMask))
|
|
|
|
|
[self miniaturize: sender];
|
|
|
|
|
else
|
|
|
|
|
[super performMiniaturize: sender];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)performZoom:(id)sender
|
|
|
|
|
{
|
|
|
|
|
if (!([self styleMask] & NSTitledWindowMask))
|
|
|
|
|
[self customZoom: sender];
|
|
|
|
|
else
|
|
|
|
|
[super performZoom: sender];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)zoom:(id)sender
|
|
|
|
|
{
|
|
|
|
|
if (!([self styleMask] & NSTitledWindowMask))
|
|
|
|
|
[self customZoom: sender];
|
|
|
|
|
else
|
|
|
|
|
[super zoom: sender];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Given a proposed frame rectangle, return a modified version
|
|
|
|
|
* which will fit inside the screen.
|
|
|
|
|
*
|
|
|
|
|
* This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
|
|
|
|
|
* Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
|
|
|
|
|
* Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
|
* Copyright (C) 1996 Free Software Foundation, Inc.
|
|
|
|
|
*/
|
|
|
|
|
- (NSRect) customConstrainFrameRect: (NSRect)frameRect toScreen: (NSScreen*)screen
|
|
|
|
|
{
|
|
|
|
|
NSRect screenRect = [screen visibleFrame];
|
|
|
|
|
float difference;
|
|
|
|
|
|
|
|
|
|
/* Move top edge of the window inside the screen */
|
|
|
|
|
difference = NSMaxY (frameRect) - NSMaxY (screenRect);
|
|
|
|
|
if (difference > 0) {
|
|
|
|
|
frameRect.origin.y -= difference;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the window is resizable, resize it (if needed) so that the
|
|
|
|
|
bottom edge is on the screen or can be on the screen when the user moves
|
|
|
|
|
the window */
|
|
|
|
|
difference = NSMaxY (screenRect) - NSMaxY (frameRect);
|
|
|
|
|
if (_styleMask & NSResizableWindowMask) {
|
|
|
|
|
float difference2;
|
|
|
|
|
|
|
|
|
|
difference2 = screenRect.origin.y - frameRect.origin.y;
|
|
|
|
|
difference2 -= difference;
|
|
|
|
|
// Take in account the space between the top of window and the top of the
|
|
|
|
|
// screen which can be used to move the bottom of the window on the screen
|
|
|
|
|
if (difference2 > 0) {
|
|
|
|
|
frameRect.size.height -= difference2;
|
|
|
|
|
frameRect.origin.y += difference2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ensure that resizing doesn't makewindow smaller than minimum */
|
|
|
|
|
difference2 = [self minSize].height - frameRect.size.height;
|
|
|
|
|
if (difference2 > 0) {
|
|
|
|
|
frameRect.size.height += difference2;
|
|
|
|
|
frameRect.origin.y -= difference2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return frameRect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define DIST 3
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
Zooms the receiver. This method calls the delegate method
|
|
|
|
|
windowShouldZoom:toFrame: to determine if the window should
|
|
|
|
|
be allowed to zoom to full screen.
|
|
|
|
|
*
|
|
|
|
|
* This method is based upon NSWindow.m, part of the GNUstep GUI Library, licensed under LGPLv2+.
|
|
|
|
|
* Authors: Scott Christley <scottc@net-community.com>, Venkat Ajjanagadde <venkat@ocbi.com>,
|
|
|
|
|
* Felipe A. Rodriguez <far@ix.netcom.com>, Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
|
* Copyright (C) 1996 Free Software Foundation, Inc.
|
|
|
|
|
*/
|
|
|
|
|
- (void) customZoom: (id)sender
|
|
|
|
|
{
|
|
|
|
|
NSRect maxRect = [[self screen] visibleFrame];
|
|
|
|
|
NSRect currentFrame = [self frame];
|
|
|
|
|
|
|
|
|
|
if ([[self delegate] respondsToSelector: @selector(windowWillUseStandardFrame:defaultFrame:)]) {
|
|
|
|
|
maxRect = [[self delegate] windowWillUseStandardFrame: self defaultFrame: maxRect];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
maxRect = [self customConstrainFrameRect: maxRect toScreen: [self screen]];
|
|
|
|
|
|
|
|
|
|
// Compare the new frame with the current one
|
|
|
|
|
if ((abs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
|
|
|
|
|
&& (abs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
|
|
|
|
|
&& (abs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
|
|
|
|
|
&& (abs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST)) {
|
|
|
|
|
// Already in zoomed mode, reset user frame, if stored
|
|
|
|
|
if ([self frameAutosaveName] != nil) {
|
|
|
|
|
[self setFrame: previousSavedFrame display: YES animate: YES];
|
|
|
|
|
[self saveFrameUsingName: [self frameAutosaveName]];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([self frameAutosaveName] != nil) {
|
|
|
|
|
[self saveFrameUsingName: [self frameAutosaveName]];
|
|
|
|
|
previousSavedFrame = [self frame];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[self setFrame: maxRect display: YES animate: YES];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
#pragma mark Accessibility stuff
|
|
|
|
|
|
|
|
|
|
- (NSArray *)accessibilityAttributeNames
|
|
|
|
|
{
|
|
|
|
|
if (!b_dark_interface || !o_titlebar_view)
|
|
|
|
|
return [super accessibilityAttributeNames];
|
|
|
|
|
|
|
|
|
|
static NSMutableArray *attributes = nil;
|
|
|
|
|
if (attributes == nil) {
|
|
|
|
|
attributes = [[super accessibilityAttributeNames] mutableCopy];
|
|
|
|
|
NSArray *appendAttributes = [NSArray arrayWithObjects: NSAccessibilitySubroleAttribute,
|
|
|
|
|
NSAccessibilityCloseButtonAttribute,
|
|
|
|
|
NSAccessibilityMinimizeButtonAttribute,
|
|
|
|
|
NSAccessibilityZoomButtonAttribute,
|
|
|
|
|
nil];
|
|
|
|
|
|
|
|
|
|
for(NSString *attribute in appendAttributes) {
|
|
|
|
|
if (![attributes containsObject:attribute])
|
|
|
|
|
[attributes addObject:attribute];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return attributes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id)accessibilityAttributeValue: (NSString*)o_attribute_name
|
|
|
|
|
{
|
|
|
|
|
if (b_dark_interface && o_titlebar_view) {
|
|
|
|
|
VLCMainWindowTitleView *o_tbv = o_titlebar_view;
|
|
|
|
|
|
|
|
|
|
if ([o_attribute_name isEqualTo: NSAccessibilitySubroleAttribute])
|
|
|
|
|
return NSAccessibilityStandardWindowSubrole;
|
|
|
|
|
|
|
|
|
|
if ([o_attribute_name isEqualTo: NSAccessibilityCloseButtonAttribute])
|
|
|
|
|
return [[o_tbv closeButton] cell];
|
|
|
|
|
|
|
|
|
|
if ([o_attribute_name isEqualTo: NSAccessibilityMinimizeButtonAttribute])
|
|
|
|
|
return [[o_tbv minimizeButton] cell];
|
|
|
|
|
|
|
|
|
|
if ([o_attribute_name isEqualTo: NSAccessibilityZoomButtonAttribute])
|
|
|
|
|
return [[o_tbv zoomButton] cell];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [super accessibilityAttributeValue: o_attribute_name];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|