You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1217 lines
40 KiB
1217 lines
40 KiB
/*****************************************************************************
|
|
* Windows.m: MacOS X interface module
|
|
*****************************************************************************
|
|
* Copyright (C) 2012-2014 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 "VLCMain.h"
|
|
#import "VLCCoreInteraction.h"
|
|
#import "ControlsBar.h"
|
|
#import "VLCVoutView.h"
|
|
#import "CompatibilityFixes.h"
|
|
|
|
/*****************************************************************************
|
|
* VLCWindow
|
|
*
|
|
* Missing extension to NSWindow
|
|
*****************************************************************************/
|
|
|
|
@interface VLCWindow()
|
|
{
|
|
BOOL b_canBecomeKeyWindow;
|
|
BOOL b_isset_canBecomeKeyWindow;
|
|
BOOL b_canBecomeMainWindow;
|
|
BOOL b_isset_canBecomeMainWindow;
|
|
NSViewAnimation *o_current_animation;
|
|
|
|
/*
|
|
* YES when all animations are over
|
|
* for fullscreen window: always YES
|
|
*/
|
|
}
|
|
@end
|
|
|
|
@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 */
|
|
[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;
|
|
}
|
|
|
|
// TODO this callback stuff does not work and is not needed
|
|
invoc = [[NSInvocation alloc] init];
|
|
[invoc setSelector:@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 alloc] init];
|
|
[invoc setSelector:@selector(orderOut:)];
|
|
[invoc setTarget: self];
|
|
[invoc setArgument:(__bridge void * __nonnull)sender atIndex:2];
|
|
[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 arrayWithObject:dict]];
|
|
|
|
[anim setAnimationBlockingMode:NSAnimationNonblocking];
|
|
[anim setDuration:0.9];
|
|
[anim setFrameRate:30];
|
|
[anim setUserInfo:(__bridge void *)callback];
|
|
[anim setDelegate:self];
|
|
|
|
@synchronized(self) {
|
|
current_anim = self->o_current_animation;
|
|
|
|
if (!([[[current_anim viewAnimations] firstObject] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating])) {
|
|
if (current_anim) {
|
|
[current_anim stopAnimation];
|
|
[anim setCurrentProgress:1.0 - [current_anim currentProgress]];
|
|
} 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 arrayWithObject:dict]];
|
|
|
|
[anim setAnimationBlockingMode:NSAnimationNonblocking];
|
|
[anim setDuration:0.5];
|
|
[anim setFrameRate:30];
|
|
[anim setDelegate:self];
|
|
|
|
@synchronized(self) {
|
|
current_anim = self->o_current_animation;
|
|
|
|
if (!([[[current_anim viewAnimations] firstObject] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating])) {
|
|
if (current_anim) {
|
|
[current_anim stopAnimation];
|
|
[anim setCurrentProgress:1.0 - [current_anim currentProgress]];
|
|
}
|
|
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];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (VLCVoutView *)videoView
|
|
{
|
|
NSArray *o_subViews = [[self contentView] subviews];
|
|
if ([o_subViews count] > 0) {
|
|
id o_vout_view = [o_subViews firstObject];
|
|
|
|
if ([o_vout_view class] == [VLCVoutView class])
|
|
return (VLCVoutView *)o_vout_view;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
|
|
{
|
|
if (!screen)
|
|
screen = [self screen];
|
|
NSRect screenRect = [screen frame];
|
|
NSRect constrainedRect = [super constrainFrameRect:frameRect toScreen:screen];
|
|
|
|
/*
|
|
* Ugly workaround!
|
|
* With Mavericks, there is a nasty bug resulting in grey bars on top in fullscreen mode.
|
|
* It looks like this is enforced by the os because the window is in the way for the menu bar.
|
|
*
|
|
* According to the documentation, this constraining can be changed by overwriting this
|
|
* method. But in this situation, even the received frameRect is already contrained with the
|
|
* menu bars height substracted. This case is detected here, and the full height is
|
|
* enforced again.
|
|
*
|
|
* See #9469 and radar://15583566
|
|
*/
|
|
|
|
BOOL b_inFullscreen = [self fullscreen] || ([self respondsToSelector:@selector(inFullscreenTransition)] && [(VLCVideoWindowCommon *)self inFullscreenTransition]);
|
|
|
|
if((OSX_MAVERICKS) && b_inFullscreen && constrainedRect.size.width == screenRect.size.width
|
|
&& constrainedRect.size.height != screenRect.size.height
|
|
&& fabs(screenRect.size.height - constrainedRect.size.height) <= 25.) {
|
|
|
|
msg_Dbg(getIntf(), "Contrain window height %.1f to screen height %.1f",
|
|
constrainedRect.size.height, screenRect.size.height);
|
|
constrainedRect.size.height = screenRect.size.height;
|
|
}
|
|
|
|
return constrainedRect;
|
|
}
|
|
|
|
@end
|
|
|
|
/*****************************************************************************
|
|
* VLCVideoWindowCommon
|
|
*
|
|
* Common code for main window, detached window and extra video window
|
|
*****************************************************************************/
|
|
|
|
@interface VLCVideoWindowCommon()
|
|
{
|
|
// variables for fullscreen handling
|
|
VLCVideoWindowCommon *o_current_video_window;
|
|
VLCWindow * o_fullscreen_window;
|
|
NSViewAnimation * o_fullscreen_anim1;
|
|
NSViewAnimation * o_fullscreen_anim2;
|
|
NSView * o_temp_view;
|
|
|
|
NSInteger i_originalLevel;
|
|
|
|
BOOL b_video_view_was_hidden;
|
|
|
|
NSTimer *t_hide_mouse_timer;
|
|
|
|
NSRect frameBeforeLionFullscreen;
|
|
}
|
|
|
|
- (void)customZoom:(id)sender;
|
|
- (void)hasBecomeFullscreen;
|
|
- (void)hasEndedFullscreen;
|
|
@end
|
|
|
|
@implementation VLCVideoWindowCommon
|
|
|
|
#pragma mark -
|
|
#pragma mark Init
|
|
|
|
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
|
|
backing:(NSBackingStoreType)backingType defer:(BOOL)flag
|
|
{
|
|
_darkInterface = config_GetInt(getIntf(), "macosx-interfacestyle");
|
|
|
|
if (_darkInterface) {
|
|
styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
|
|
}
|
|
|
|
self = [super initWithContentRect:contentRect styleMask:styleMask
|
|
backing:backingType defer:flag];
|
|
|
|
/* we want to be moveable regardless of our style */
|
|
[self setMovableByWindowBackground: YES];
|
|
[self setCanBecomeKeyWindow:YES];
|
|
|
|
o_temp_view = [[NSView alloc] init];
|
|
[o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)awakeFromNib
|
|
{
|
|
BOOL b_nativeFullscreenMode = var_InheritBool(getIntf(), "macosx-nativefullscreenmode");
|
|
|
|
if (b_nativeFullscreenMode) {
|
|
[self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
|
|
} else if (OSX_EL_CAPITAN || OSX_SIERRA) {
|
|
// Native fullscreen seems to be default on El Capitan, this disables it explicitely
|
|
[self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
|
|
}
|
|
|
|
[super awakeFromNib];
|
|
}
|
|
|
|
- (void)setTitle:(NSString *)title
|
|
{
|
|
if (!title || [title length] < 1)
|
|
return;
|
|
|
|
if (_darkInterface && self.titlebarView)
|
|
[self.titlebarView 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 close];
|
|
} 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];
|
|
CGFloat 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) {
|
|
CGFloat 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 ((fabs(NSMaxX(maxRect) - NSMaxX(currentFrame)) < DIST)
|
|
&& (fabs(NSMaxY(maxRect) - NSMaxY(currentFrame)) < DIST)
|
|
&& (fabs(NSMinX(maxRect) - NSMinX(currentFrame)) < DIST)
|
|
&& (fabs(NSMinY(maxRect) - NSMinY(currentFrame)) < DIST)) {
|
|
// Already in zoomed mode, reset user frame, if stored
|
|
if ([self frameAutosaveName] != nil) {
|
|
[self setFrame: self.previousSavedFrame display: YES animate: YES];
|
|
[self saveFrameUsingName: [self frameAutosaveName]];
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ([self frameAutosaveName] != nil) {
|
|
[self saveFrameUsingName: [self frameAutosaveName]];
|
|
self.previousSavedFrame = [self frame];
|
|
}
|
|
|
|
[self setFrame: maxRect display: YES animate: YES];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Video window resizing logic
|
|
|
|
- (void)setWindowLevel:(NSInteger)i_state
|
|
{
|
|
if (var_InheritBool(getIntf(), "video-wallpaper") || [self level] < NSNormalWindowLevel)
|
|
return;
|
|
|
|
if (!self.fullscreen && !_inFullscreenTransition)
|
|
[self setLevel: i_state];
|
|
|
|
// save it for restore if window is currently minimized or in fullscreen
|
|
i_originalLevel = i_state;
|
|
}
|
|
|
|
- (NSRect)getWindowRectForProposedVideoViewSize:(NSSize)size
|
|
{
|
|
NSSize windowMinSize = [self minSize];
|
|
NSRect screenFrame = [[self screen] visibleFrame];
|
|
|
|
NSRect topleftbase = NSMakeRect(0, [self frame].size.height, 0, 0);
|
|
NSPoint topleftscreen = [self convertRectToScreen: topleftbase].origin;
|
|
|
|
CGFloat f_width = size.width;
|
|
CGFloat f_height = size.height;
|
|
if (f_width < windowMinSize.width)
|
|
f_width = windowMinSize.width;
|
|
if (f_height < f_min_video_height)
|
|
f_height = f_min_video_height;
|
|
|
|
/* Calculate the window's new size */
|
|
NSRect new_frame;
|
|
new_frame.size.width = [self frame].size.width - [_videoView frame].size.width + f_width;
|
|
new_frame.size.height = [self frame].size.height - [_videoView frame].size.height + f_height;
|
|
new_frame.origin.x = topleftscreen.x;
|
|
new_frame.origin.y = topleftscreen.y - new_frame.size.height;
|
|
|
|
/* make sure the window doesn't exceed the screen size the window is on */
|
|
if (new_frame.size.width > screenFrame.size.width) {
|
|
new_frame.size.width = screenFrame.size.width;
|
|
new_frame.origin.x = screenFrame.origin.x;
|
|
}
|
|
if (new_frame.size.height > screenFrame.size.height) {
|
|
new_frame.size.height = screenFrame.size.height;
|
|
new_frame.origin.y = screenFrame.origin.y;
|
|
}
|
|
if (new_frame.origin.y < screenFrame.origin.y)
|
|
new_frame.origin.y = screenFrame.origin.y;
|
|
|
|
CGFloat right_screen_point = screenFrame.origin.x + screenFrame.size.width;
|
|
CGFloat right_window_point = new_frame.origin.x + new_frame.size.width;
|
|
if (right_window_point > right_screen_point)
|
|
new_frame.origin.x -= (right_window_point - right_screen_point);
|
|
|
|
return new_frame;
|
|
}
|
|
|
|
- (void)resizeWindow
|
|
{
|
|
// VOUT_WINDOW_SET_SIZE is triggered when exiting fullscreen. This event is ignored here
|
|
// to avoid interference with the animation.
|
|
if ([self fullscreen] || _inFullscreenTransition)
|
|
return;
|
|
|
|
NSRect window_rect = [self getWindowRectForProposedVideoViewSize:self.nativeVideoSize];
|
|
[[self animator] setFrame:window_rect display:YES];
|
|
}
|
|
|
|
- (void)setNativeVideoSize:(NSSize)size
|
|
{
|
|
_nativeVideoSize = size;
|
|
|
|
if (var_InheritBool(getIntf(), "macosx-video-autoresize") && !var_InheritBool(getIntf(), "video-wallpaper"))
|
|
[self resizeWindow];
|
|
}
|
|
|
|
- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
|
|
{
|
|
if (![[VLCMain sharedInstance] activeVideoPlayback] || self.nativeVideoSize.width == 0. || self.nativeVideoSize.height == 0. || window != self)
|
|
return proposedFrameSize;
|
|
|
|
// needed when entering lion fullscreen mode
|
|
if (_inFullscreenTransition || [self fullscreen])
|
|
return proposedFrameSize;
|
|
|
|
if ([_videoView isHidden])
|
|
return proposedFrameSize;
|
|
|
|
if ([[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]) {
|
|
NSRect videoWindowFrame = [self frame];
|
|
NSRect viewRect = [_videoView convertRect:[_videoView bounds] toView: nil];
|
|
NSRect contentRect = [self contentRectForFrameRect:videoWindowFrame];
|
|
CGFloat marginy = viewRect.origin.y + videoWindowFrame.size.height - contentRect.size.height;
|
|
CGFloat marginx = contentRect.size.width - viewRect.size.width;
|
|
if (self.titlebarView && _darkInterface)
|
|
marginy += [self.titlebarView frame].size.height;
|
|
|
|
proposedFrameSize.height = (proposedFrameSize.width - marginx) * self.nativeVideoSize.height / self.nativeVideoSize.width + marginy;
|
|
}
|
|
|
|
return proposedFrameSize;
|
|
}
|
|
|
|
- (void)windowWillMiniaturize:(NSNotification *)notification
|
|
{
|
|
// Set level to normal as a workaround for Mavericks bug causing window
|
|
// to vanish from screen, see radar://15473716
|
|
i_originalLevel = [self level];
|
|
[self setLevel: NSNormalWindowLevel];
|
|
}
|
|
|
|
- (void)windowDidDeminiaturize:(NSNotification *)notification
|
|
{
|
|
[self setLevel: i_originalLevel];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Mouse cursor handling
|
|
|
|
// NSTimer selectors require this function signature as per Apple's docs
|
|
- (void)hideMouseCursor:(NSTimer *)timer
|
|
{
|
|
[NSCursor setHiddenUntilMouseMoves: YES];
|
|
}
|
|
|
|
- (void)recreateHideMouseTimer
|
|
{
|
|
if (t_hide_mouse_timer != nil) {
|
|
[t_hide_mouse_timer invalidate];
|
|
}
|
|
|
|
t_hide_mouse_timer = [NSTimer scheduledTimerWithTimeInterval:2
|
|
target:self
|
|
selector:@selector(hideMouseCursor:)
|
|
userInfo:nil
|
|
repeats:NO];
|
|
}
|
|
|
|
// Called automatically if window's acceptsMouseMovedEvents property is true
|
|
- (void)mouseMoved:(NSEvent *)theEvent
|
|
{
|
|
if (self.fullscreen)
|
|
[self recreateHideMouseTimer];
|
|
if (self.hasActiveVideo && [self isKeyWindow]) {
|
|
if (NSPointInRect([theEvent locationInWindow],
|
|
[[self videoView] convertRect:[[self videoView] bounds]
|
|
toView:nil])) {
|
|
[self recreateHideMouseTimer];
|
|
} else {
|
|
[t_hide_mouse_timer invalidate];
|
|
}
|
|
}
|
|
|
|
[super mouseMoved: theEvent];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Key events
|
|
|
|
- (void)flagsChanged:(NSEvent *)theEvent
|
|
{
|
|
BOOL b_alt_pressed = ([theEvent modifierFlags] & NSAlternateKeyMask) != 0;
|
|
[self.titlebarView informModifierPressed: b_alt_pressed];
|
|
|
|
[super flagsChanged:theEvent];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Lion native fullscreen handling
|
|
|
|
- (void)becomeKeyWindow
|
|
{
|
|
[super becomeKeyWindow];
|
|
|
|
// change fspanel state for the case when multiple windows are in fullscreen
|
|
if ([self hasActiveVideo] && [self fullscreen])
|
|
[[[[VLCMain sharedInstance] mainWindow] fspanel] setActive:nil];
|
|
else
|
|
[[[[VLCMain sharedInstance] mainWindow] fspanel] setNonActive:nil];
|
|
}
|
|
|
|
- (void)resignKeyWindow
|
|
{
|
|
[super resignKeyWindow];
|
|
|
|
[[[[VLCMain sharedInstance] mainWindow] fspanel] setNonActive:nil];
|
|
}
|
|
|
|
-(NSArray*)customWindowsToEnterFullScreenForWindow:(NSWindow *)window
|
|
{
|
|
if (window == self) {
|
|
return [NSArray arrayWithObject:window];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (NSArray*)customWindowsToExitFullScreenForWindow:(NSWindow*)window
|
|
{
|
|
if (window == self) {
|
|
return [NSArray arrayWithObject:window];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (void)window:window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration
|
|
{
|
|
[window setStyleMask:([window styleMask] | NSFullScreenWindowMask)];
|
|
|
|
NSScreen *screen = [window screen];
|
|
NSRect screenFrame = [screen frame];
|
|
|
|
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
|
|
[context setDuration:0.5 * duration];
|
|
[[window animator] setFrame:screenFrame display:YES];
|
|
} completionHandler:nil];
|
|
}
|
|
|
|
- (void)window:window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration
|
|
{
|
|
[window setStyleMask:([window styleMask] & ~NSFullScreenWindowMask)];
|
|
[[window animator] setFrame:frameBeforeLionFullscreen display:YES animate:YES];
|
|
|
|
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
|
|
[context setDuration:0.5 * duration];
|
|
[[window animator] setFrame:frameBeforeLionFullscreen display:YES animate:YES];
|
|
} completionHandler:nil];
|
|
}
|
|
|
|
- (void)windowWillEnterFullScreen:(NSNotification *)notification
|
|
{
|
|
_windowShouldExitFullscreenWhenFinished = [[VLCMain sharedInstance] activeVideoPlayback];
|
|
|
|
NSInteger i_currLevel = [self level];
|
|
// self.fullscreen and _inFullscreenTransition must not be true yet
|
|
[[[VLCMain sharedInstance] voutController] updateWindowLevelForHelperWindows: NSNormalWindowLevel];
|
|
[self setLevel:NSNormalWindowLevel];
|
|
i_originalLevel = i_currLevel;
|
|
|
|
_inFullscreenTransition = YES;
|
|
|
|
var_SetBool(pl_Get(getIntf()), "fullscreen", true);
|
|
|
|
frameBeforeLionFullscreen = [self frame];
|
|
|
|
if ([self hasActiveVideo]) {
|
|
vout_thread_t *p_vout = getVoutForActiveWindow();
|
|
if (p_vout) {
|
|
var_SetBool(p_vout, "fullscreen", true);
|
|
vlc_object_release(p_vout);
|
|
}
|
|
}
|
|
|
|
if ([self hasActiveVideo])
|
|
[[[VLCMain sharedInstance] mainWindow] recreateHideMouseTimer];
|
|
|
|
if (_darkInterface) {
|
|
[self.titlebarView removeFromSuperviewWithoutNeedingDisplay];
|
|
|
|
NSRect winrect;
|
|
CGFloat f_titleBarHeight = [self.titlebarView frame].size.height;
|
|
winrect = [self frame];
|
|
|
|
winrect.size.height = winrect.size.height - f_titleBarHeight;
|
|
[self setFrame: winrect display:NO animate:NO];
|
|
}
|
|
|
|
[_videoView setFrame: [[self contentView] frame]];
|
|
if (![_videoView isHidden]) {
|
|
[[self.controlsBar bottomBarView] setHidden: YES];
|
|
}
|
|
|
|
[self setMovableByWindowBackground: NO];
|
|
}
|
|
|
|
- (void)windowDidEnterFullScreen:(NSNotification *)notification
|
|
{
|
|
// Indeed, we somehow can have an "inactive" fullscreen (but a visible window!).
|
|
// But this creates some problems when leaving fs over remote intfs, so activate app here.
|
|
[NSApp activateIgnoringOtherApps:YES];
|
|
|
|
[self setFullscreen: YES];
|
|
_inFullscreenTransition = NO;
|
|
|
|
if ([self hasActiveVideo]) {
|
|
[[[[VLCMain sharedInstance] mainWindow] fspanel] setVoutWasUpdated: self];
|
|
if (![_videoView isHidden])
|
|
[[[[VLCMain sharedInstance] mainWindow] fspanel] setActive: nil];
|
|
}
|
|
|
|
NSArray *subviews = [[self videoView] subviews];
|
|
NSUInteger count = [subviews count];
|
|
|
|
for (NSUInteger x = 0; x < count; x++) {
|
|
if ([[subviews objectAtIndex:x] respondsToSelector:@selector(reshape)])
|
|
[[subviews objectAtIndex:x] reshape];
|
|
}
|
|
}
|
|
|
|
- (void)windowWillExitFullScreen:(NSNotification *)notification
|
|
{
|
|
_inFullscreenTransition = YES;
|
|
[self setFullscreen: NO];
|
|
|
|
if ([self hasActiveVideo]) {
|
|
var_SetBool(pl_Get(getIntf()), "fullscreen", false);
|
|
|
|
vout_thread_t *p_vout = getVoutForActiveWindow();
|
|
if (p_vout) {
|
|
var_SetBool(p_vout, "fullscreen", false);
|
|
vlc_object_release(p_vout);
|
|
}
|
|
}
|
|
|
|
[NSCursor setHiddenUntilMouseMoves: NO];
|
|
[[[[VLCMain sharedInstance] mainWindow] fspanel] setNonActive: nil];
|
|
|
|
|
|
if (_darkInterface) {
|
|
NSRect winrect;
|
|
CGFloat f_titleBarHeight = [self.titlebarView frame].size.height;
|
|
|
|
winrect = [_videoView frame];
|
|
winrect.size.height -= f_titleBarHeight;
|
|
[_videoView setFrame: winrect];
|
|
|
|
winrect = [self frame];
|
|
[self.titlebarView setFrame: NSMakeRect(0, winrect.size.height - f_titleBarHeight,
|
|
winrect.size.width, f_titleBarHeight)];
|
|
[[self contentView] addSubview: self.titlebarView];
|
|
|
|
winrect.size.height = winrect.size.height + f_titleBarHeight;
|
|
[self setFrame: winrect display:NO animate:NO];
|
|
}
|
|
|
|
NSRect videoViewFrame = [_videoView frame];
|
|
videoViewFrame.origin.y += [self.controlsBar height];
|
|
videoViewFrame.size.height -= [self.controlsBar height];
|
|
[_videoView setFrame: videoViewFrame];
|
|
|
|
if (![_videoView isHidden]) {
|
|
[[self.controlsBar bottomBarView] setHidden: NO];
|
|
}
|
|
|
|
[self setMovableByWindowBackground: YES];
|
|
}
|
|
|
|
- (void)windowDidExitFullScreen:(NSNotification *)notification
|
|
{
|
|
_inFullscreenTransition = NO;
|
|
|
|
[[[VLCMain sharedInstance] voutController] updateWindowLevelForHelperWindows: i_originalLevel];
|
|
[self setLevel:i_originalLevel];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Fullscreen Logic
|
|
|
|
- (void)enterFullscreenWithAnimation:(BOOL)b_animation
|
|
{
|
|
NSMutableDictionary *dict1, *dict2;
|
|
NSScreen *screen;
|
|
NSRect screen_rect;
|
|
NSRect rect;
|
|
BOOL blackout_other_displays = var_InheritBool(getIntf(), "macosx-black");
|
|
|
|
screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_InheritInteger(getIntf(), "macosx-vdev")];
|
|
|
|
if (!screen) {
|
|
msg_Dbg(getIntf(), "chosen screen isn't present, using current screen for fullscreen mode");
|
|
screen = [self screen];
|
|
}
|
|
if (!screen) {
|
|
msg_Dbg(getIntf(), "Using deepest screen");
|
|
screen = [NSScreen deepestScreen];
|
|
}
|
|
|
|
screen_rect = [screen frame];
|
|
|
|
if (self.controlsBar)
|
|
[self.controlsBar setFullscreenState:YES];
|
|
[[[[VLCMain sharedInstance] mainWindow] controlsBar] setFullscreenState:YES];
|
|
|
|
[[[VLCMain sharedInstance] mainWindow] recreateHideMouseTimer];
|
|
|
|
if (blackout_other_displays)
|
|
[screen blackoutOtherScreens];
|
|
|
|
/* Make sure we don't see the window flashes in float-on-top mode */
|
|
NSInteger i_currLevel = [self level];
|
|
// self.fullscreen must not be true yet
|
|
[[[VLCMain sharedInstance] voutController] updateWindowLevelForHelperWindows: NSNormalWindowLevel];
|
|
[self setLevel:NSNormalWindowLevel];
|
|
i_originalLevel = i_currLevel; // would be overwritten by previous call
|
|
|
|
/* Only create the o_fullscreen_window if we are not in the middle of the zooming animation */
|
|
if (!o_fullscreen_window) {
|
|
/* We can't change the styleMask of an already created NSWindow, so we create another window, and do eye catching stuff */
|
|
|
|
rect = [[_videoView superview] convertRect: [_videoView frame] toView: nil]; /* Convert to Window base coord */
|
|
rect.origin.x += [self frame].origin.x;
|
|
rect.origin.y += [self frame].origin.y;
|
|
o_fullscreen_window = [[VLCWindow alloc] initWithContentRect:rect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
|
|
[o_fullscreen_window setBackgroundColor: [NSColor blackColor]];
|
|
[o_fullscreen_window setCanBecomeKeyWindow: YES];
|
|
[o_fullscreen_window setCanBecomeMainWindow: YES];
|
|
[o_fullscreen_window setHasActiveVideo: YES];
|
|
[o_fullscreen_window setFullscreen: YES];
|
|
|
|
/* Make sure video view gets visible in case the playlist was visible before */
|
|
b_video_view_was_hidden = [_videoView isHidden];
|
|
[_videoView setHidden: NO];
|
|
|
|
if (!b_animation) {
|
|
/* We don't animate if we are not visible, instead we
|
|
* simply fade the display */
|
|
CGDisplayFadeReservationToken token;
|
|
|
|
if (blackout_other_displays) {
|
|
CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
|
|
CGDisplayFade(token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES);
|
|
}
|
|
|
|
NSDisableScreenUpdates();
|
|
[[_videoView superview] replaceSubview:_videoView with:o_temp_view];
|
|
[o_temp_view setFrame:[_videoView frame]];
|
|
[[o_fullscreen_window contentView] addSubview:_videoView];
|
|
[_videoView setFrame: [[o_fullscreen_window contentView] frame]];
|
|
NSEnableScreenUpdates();
|
|
|
|
[screen setFullscreenPresentationOptions];
|
|
|
|
[o_fullscreen_window setFrame:screen_rect display:YES animate:NO];
|
|
|
|
[o_fullscreen_window orderFront:self animate:YES];
|
|
|
|
[o_fullscreen_window setLevel:NSNormalWindowLevel];
|
|
|
|
if (blackout_other_displays) {
|
|
CGDisplayFade(token, 0.3, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO);
|
|
CGReleaseDisplayFadeReservation(token);
|
|
}
|
|
|
|
/* Will release the lock */
|
|
[self hasBecomeFullscreen];
|
|
|
|
return;
|
|
}
|
|
|
|
/* Make sure we don't see the _videoView disappearing of the screen during this operation */
|
|
NSDisableScreenUpdates();
|
|
[[_videoView superview] replaceSubview:_videoView with:o_temp_view];
|
|
[o_temp_view setFrame:[_videoView frame]];
|
|
[[o_fullscreen_window contentView] addSubview:_videoView];
|
|
[_videoView setFrame: [[o_fullscreen_window contentView] frame]];
|
|
[o_fullscreen_window makeKeyAndOrderFront:self];
|
|
NSEnableScreenUpdates();
|
|
}
|
|
|
|
/* We are in fullscreen (and no animation is running) */
|
|
if ([self fullscreen]) {
|
|
/* Make sure we are hidden */
|
|
[self orderOut: self];
|
|
|
|
return;
|
|
}
|
|
|
|
if (o_fullscreen_anim1) {
|
|
[o_fullscreen_anim1 stopAnimation];
|
|
}
|
|
if (o_fullscreen_anim2) {
|
|
[o_fullscreen_anim2 stopAnimation];
|
|
}
|
|
|
|
[screen setFullscreenPresentationOptions];
|
|
|
|
dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
|
|
dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];
|
|
|
|
[dict1 setObject:self forKey:NSViewAnimationTargetKey];
|
|
[dict1 setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
|
|
|
|
[dict2 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
|
|
[dict2 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
|
|
[dict2 setObject:[NSValue valueWithRect:screen_rect] forKey:NSViewAnimationEndFrameKey];
|
|
|
|
/* Strategy with NSAnimation allocation:
|
|
- Keep at most 2 animation at a time
|
|
- leaveFullscreen/enterFullscreen are the only responsible for releasing and alloc-ing
|
|
*/
|
|
o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict1]];
|
|
o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict2]];
|
|
|
|
[o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
|
|
[o_fullscreen_anim1 setDuration: 0.3];
|
|
[o_fullscreen_anim1 setFrameRate: 30];
|
|
[o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
|
|
[o_fullscreen_anim2 setDuration: 0.2];
|
|
[o_fullscreen_anim2 setFrameRate: 30];
|
|
|
|
[o_fullscreen_anim2 setDelegate: self];
|
|
[o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
|
|
|
|
[o_fullscreen_anim1 startAnimation];
|
|
/* fullscreenAnimation will be unlocked when animation ends */
|
|
|
|
_inFullscreenTransition = YES;
|
|
}
|
|
|
|
- (void)hasBecomeFullscreen
|
|
{
|
|
if ([[_videoView subviews] count] > 0)
|
|
[o_fullscreen_window makeFirstResponder: [[_videoView subviews] firstObject]];
|
|
|
|
[o_fullscreen_window makeKeyWindow];
|
|
[o_fullscreen_window setAcceptsMouseMovedEvents: YES];
|
|
|
|
/* tell the fspanel to move itself to front next time it's triggered */
|
|
[[[[VLCMain sharedInstance] mainWindow] fspanel] setVoutWasUpdated: o_fullscreen_window];
|
|
[[[[VLCMain sharedInstance] mainWindow] fspanel] setActive: nil];
|
|
|
|
if ([self isVisible])
|
|
[self orderOut: self];
|
|
|
|
_inFullscreenTransition = NO;
|
|
[self setFullscreen:YES];
|
|
}
|
|
|
|
- (void)leaveFullscreenWithAnimation:(BOOL)b_animation
|
|
{
|
|
NSMutableDictionary *dict1, *dict2;
|
|
NSRect frame;
|
|
BOOL blackout_other_displays = var_InheritBool(getIntf(), "macosx-black");
|
|
|
|
if (self.controlsBar)
|
|
[self.controlsBar setFullscreenState:NO];
|
|
[[[[VLCMain sharedInstance] mainWindow] controlsBar] setFullscreenState:NO];
|
|
|
|
/* We always try to do so */
|
|
[NSScreen unblackoutScreens];
|
|
|
|
[[_videoView window] makeKeyAndOrderFront: nil];
|
|
|
|
/* Don't do anything if o_fullscreen_window is already closed */
|
|
if (!o_fullscreen_window) {
|
|
return;
|
|
}
|
|
|
|
[[[[VLCMain sharedInstance] mainWindow] fspanel] setNonActive: nil];
|
|
[[o_fullscreen_window screen] setNonFullscreenPresentationOptions];
|
|
|
|
if (o_fullscreen_anim1) {
|
|
[o_fullscreen_anim1 stopAnimation];
|
|
o_fullscreen_anim1 = nil;
|
|
}
|
|
if (o_fullscreen_anim2) {
|
|
[o_fullscreen_anim2 stopAnimation];
|
|
o_fullscreen_anim2 = nil;
|
|
}
|
|
|
|
_inFullscreenTransition = YES;
|
|
[self setFullscreen:NO];
|
|
|
|
if (!b_animation) {
|
|
/* We don't animate if we are not visible, instead we
|
|
* simply fade the display */
|
|
CGDisplayFadeReservationToken token;
|
|
|
|
if (blackout_other_displays) {
|
|
CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
|
|
CGDisplayFade(token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES);
|
|
}
|
|
|
|
[self setAlphaValue:1.0];
|
|
[self orderFront: self];
|
|
|
|
/* Will release the lock */
|
|
[self hasEndedFullscreen];
|
|
|
|
if (blackout_other_displays) {
|
|
CGDisplayFade(token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO);
|
|
CGReleaseDisplayFadeReservation(token);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
[self setAlphaValue: 0.0];
|
|
[self orderFront: self];
|
|
[[_videoView window] orderFront: self];
|
|
|
|
frame = [[o_temp_view superview] convertRect: [o_temp_view frame] toView: nil]; /* Convert to Window base coord */
|
|
frame.origin.x += [self frame].origin.x;
|
|
frame.origin.y += [self frame].origin.y;
|
|
|
|
dict2 = [[NSMutableDictionary alloc] initWithCapacity:2];
|
|
[dict2 setObject:self forKey:NSViewAnimationTargetKey];
|
|
[dict2 setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
|
|
|
|
o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict2]];
|
|
|
|
[o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
|
|
[o_fullscreen_anim2 setDuration: 0.3];
|
|
[o_fullscreen_anim2 setFrameRate: 30];
|
|
|
|
[o_fullscreen_anim2 setDelegate: self];
|
|
|
|
dict1 = [[NSMutableDictionary alloc] initWithCapacity:3];
|
|
|
|
[dict1 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
|
|
[dict1 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
|
|
[dict1 setObject:[NSValue valueWithRect:frame] forKey:NSViewAnimationEndFrameKey];
|
|
|
|
o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict1]];
|
|
|
|
[o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
|
|
[o_fullscreen_anim1 setDuration: 0.2];
|
|
[o_fullscreen_anim1 setFrameRate: 30];
|
|
[o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
|
|
|
|
/* Make sure o_fullscreen_window is the frontmost window */
|
|
[o_fullscreen_window orderFront: self];
|
|
|
|
[o_fullscreen_anim1 startAnimation];
|
|
/* fullscreenAnimation will be unlocked when animation ends */
|
|
}
|
|
|
|
- (void)hasEndedFullscreen
|
|
{
|
|
_inFullscreenTransition = NO;
|
|
|
|
/* This function is private and should be only triggered at the end of the fullscreen change animation */
|
|
/* Make sure we don't see the _videoView disappearing of the screen during this operation */
|
|
NSDisableScreenUpdates();
|
|
[_videoView removeFromSuperviewWithoutNeedingDisplay];
|
|
[[o_temp_view superview] replaceSubview:o_temp_view with:_videoView];
|
|
[_videoView setFrame:[o_temp_view frame]];
|
|
if ([[_videoView subviews] count] > 0)
|
|
[self makeFirstResponder: [[_videoView subviews] firstObject]];
|
|
|
|
[_videoView setHidden: b_video_view_was_hidden];
|
|
|
|
[self makeKeyAndOrderFront:self];
|
|
|
|
[o_fullscreen_window orderOut: self];
|
|
NSEnableScreenUpdates();
|
|
|
|
o_fullscreen_window = nil;
|
|
|
|
[[[VLCMain sharedInstance] voutController] updateWindowLevelForHelperWindows: i_originalLevel];
|
|
[self setLevel:i_originalLevel];
|
|
|
|
[self setAlphaValue: config_GetFloat(getIntf(), "macosx-opaqueness")];
|
|
}
|
|
|
|
- (void)animationDidEnd:(NSAnimation*)animation
|
|
{
|
|
NSArray *viewAnimations;
|
|
if ([animation currentValue] < 1.0)
|
|
return;
|
|
|
|
/* Fullscreen ended or started (we are a delegate only for leaveFullscreen's/enterFullscren's anim2) */
|
|
viewAnimations = [o_fullscreen_anim2 viewAnimations];
|
|
if ([viewAnimations count] >=1 &&
|
|
[[[viewAnimations firstObject] objectForKey: NSViewAnimationEffectKey] isEqualToString:NSViewAnimationFadeInEffect]) {
|
|
/* Fullscreen ended */
|
|
[self hasEndedFullscreen];
|
|
} else
|
|
/* Fullscreen started */
|
|
[self hasBecomeFullscreen];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Accessibility stuff
|
|
|
|
- (NSArray *)accessibilityAttributeNames
|
|
{
|
|
if (!_darkInterface || !self.titlebarView)
|
|
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 (_darkInterface && self.titlebarView) {
|
|
VLCMainWindowTitleView *o_tbv = self.titlebarView;
|
|
|
|
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
|
|
|