macosx: adapt and fix fullscreen handling after latest changes

Now, every video window is responsible for the fullscreen handling for its own.
Furthermore, fullscreen now acts entirely in response to vout events, and not over the
playlist fullscreen variable callback anymore.
Native fullscreen mode should also work correctly, but of course only
for embedded video in mainwindow.
This commit is contained in:
David Fuhrmann 2012-10-08 19:41:31 +02:00
parent 6c1febea5d
commit dd86d6d469
10 changed files with 453 additions and 428 deletions

View File

@ -561,6 +561,8 @@ static VLCCoreInteraction *_o_sharedInstance = nil;
if (p_vout) {
var_SetBool(p_vout, "fullscreen", b_fs);
vlc_object_release(p_vout);
} else { // e.g. lion fullscreen toggle
[[VLCMain sharedInstance] setFullscreen:b_fs forWindow:nil];
}
}

View File

@ -89,27 +89,20 @@
BOOL b_nonembedded;
BOOL b_podcastView_displayed;
VLCWindow * o_fullscreen_window;
NSViewAnimation * o_fullscreen_anim1;
NSViewAnimation * o_fullscreen_anim2;
NSViewAnimation * o_makekey_anim;
NSView * o_temp_view;
/* set to yes if we are fullscreen and all animations are over */
BOOL b_fullscreen;
BOOL b_window_is_invisible;
NSRecursiveLock * o_animation_lock;
NSTimer *t_hide_mouse_timer;
VLCColorView * o_color_backdrop;
NSInteger i_originalLevel;
id o_current_video_window;
NSRect frameBeforePlayback;
}
+ (VLCMainWindow *)sharedInstance;
@property (readonly) BOOL fullscreen;
@property (readwrite) BOOL fullscreen;
@property (readonly) BOOL nativeFullscreenMode;
@property (readonly) VLCFSPanel* fsPanel;
- (VLCMainWindowControlsBar *)controlsBar;
@ -135,22 +128,14 @@
- (void)setPlay;
- (void)updateVolumeSlider;
- (void)showFullscreenController;
- (VLCVoutView *)setupVout:(vout_window_t *)p_wnd;
- (void)setVideoplayEnabled;
- (void)hideMouseCursor:(NSTimer *)timer;
- (void)recreateHideMouseTimer;
/* fullscreen handling */
- (void)showFullscreenController;
- (void)lockFullscreenAnimation;
- (void)unlockFullscreenAnimation;
- (void)enterFullscreen;
- (void)leaveFullscreen;
- (void)leaveFullscreenAndFadeOut: (BOOL)fadeout;
- (void)hasEndedFullscreen;
- (void)hasBecomeFullscreen;
/* lion's native fullscreen handling */
- (void)windowWillEnterFullScreen:(NSNotification *)notification;
- (void)windowDidEnterFullScreen:(NSNotification *)notification;

View File

@ -57,6 +57,10 @@
@implementation VLCMainWindow
@synthesize fullscreen=b_fullscreen;
@synthesize nativeFullscreenMode=b_nativeFullscreenMode;
@synthesize fsPanel=o_fspanel;
static VLCMainWindow *_o_sharedInstance = nil;
+ (VLCMainWindow *)sharedInstance
@ -193,8 +197,6 @@ static VLCMainWindow *_o_sharedInstance = nil;
[self setTitle: _NS("VLC media player")];
b_dropzone_active = YES;
o_temp_view = [[NSView alloc] init];
[o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
[o_dropzone_view setFrame: [o_playlist_table frame]];
[o_left_split_view setFrame: [o_sidebar_view frame]];
@ -810,11 +812,8 @@ static VLCMainWindow *_o_sharedInstance = nil;
if (b_videoPlayback) {
frameBeforePlayback = [self frame];
// look for 'start at fullscreen'
[[VLCMain sharedInstance] fullscreenChanged];
} else {
if (!b_nonembedded)
if (!b_nonembedded && !b_fullscreen)
[[self animator] setFrame:frameBeforePlayback display:YES];
[self makeFirstResponder: nil];
@ -836,14 +835,8 @@ static VLCMainWindow *_o_sharedInstance = nil;
if (!b_videoPlayback)
[o_fspanel setNonActive: nil];
}
if (!b_videoPlayback && b_fullscreen) {
if (!b_nativeFullscreenMode)
[[VLCCoreInteraction sharedInstance] toggleFullscreen];
}
}
// Called automatically if window's acceptsMouseMovedEvents property is true
- (void)mouseMoved:(NSEvent *)theEvent
{
@ -882,362 +875,6 @@ static VLCMainWindow *_o_sharedInstance = nil;
[o_fspanel fadeIn];
}
- (BOOL)fullscreen
{
return b_fullscreen;
}
- (void)lockFullscreenAnimation
{
[o_animation_lock lock];
}
- (void)unlockFullscreenAnimation
{
[o_animation_lock unlock];
}
- (void)enterFullscreen
{
NSMutableDictionary *dict1, *dict2;
NSScreen *screen;
NSRect screen_rect;
NSRect rect;
BOOL blackout_other_displays = var_InheritBool(VLCIntf, "macosx-black");
o_current_video_window = [o_video_view window];
screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_InheritInteger(VLCIntf, "macosx-vdev")];
[self lockFullscreenAnimation];
if (!screen) {
msg_Dbg(VLCIntf, "chosen screen isn't present, using current screen for fullscreen mode");
screen = [o_current_video_window screen];
}
if (!screen) {
msg_Dbg(VLCIntf, "Using deepest screen");
screen = [NSScreen deepestScreen];
}
screen_rect = [screen frame];
[o_controls_bar setFullscreenState:YES];
//if (o_detached_video_window)
// [[o_detached_video_window controlsBar] setFullscreenState:YES];
[self recreateHideMouseTimer];
if (blackout_other_displays)
[screen blackoutOtherScreens];
/* Make sure we don't see the window flashes in float-on-top mode */
i_originalLevel = [o_current_video_window level];
[o_current_video_window setLevel:NSNormalWindowLevel];
/* 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 = [[o_video_view superview] convertRect: [o_video_view frame] toView: nil]; /* Convert to Window base coord */
rect.origin.x += [o_current_video_window frame].origin.x;
rect.origin.y += [o_current_video_window 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];
if (![o_current_video_window isVisible] || [o_current_video_window alphaValue] == 0.0) {
/* 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);
}
if ([screen mainScreen])
[NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
[[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
[o_temp_view setFrame:[o_video_view frame]];
[o_fullscreen_window setContentView:o_video_view];
[o_fullscreen_window makeKeyAndOrderFront:self];
[o_fullscreen_window orderFront:self animate:YES];
[o_fullscreen_window setFrame:screen_rect display:YES 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 o_video_view disappearing of the screen during this operation */
NSDisableScreenUpdates();
[[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
[o_temp_view setFrame:[o_video_view frame]];
[o_fullscreen_window setContentView:o_video_view];
[o_fullscreen_window makeKeyAndOrderFront:self];
NSEnableScreenUpdates();
}
/* We are in fullscreen (and no animation is running) */
if (b_fullscreen) {
/* Make sure we are hidden */
[o_current_video_window orderOut: self];
[self unlockFullscreenAnimation];
return;
}
if (o_fullscreen_anim1) {
[o_fullscreen_anim1 stopAnimation];
[o_fullscreen_anim1 release];
}
if (o_fullscreen_anim2) {
[o_fullscreen_anim2 stopAnimation];
[o_fullscreen_anim2 release];
}
if ([screen mainScreen])
[NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];
[dict1 setObject:o_current_video_window 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]];
[dict1 release];
[dict2 release];
[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 */
}
- (void)hasBecomeFullscreen
{
if ([[o_video_view subviews] count] > 0)
[o_fullscreen_window makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
[o_fullscreen_window makeKeyWindow];
[o_fullscreen_window setAcceptsMouseMovedEvents: YES];
/* tell the fspanel to move itself to front next time it's triggered */
[o_fspanel setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]];
[o_fspanel setActive: nil];
if ([o_current_video_window isVisible])
[o_current_video_window orderOut: self];
b_fullscreen = YES;
[self unlockFullscreenAnimation];
}
- (void)leaveFullscreen
{
[self leaveFullscreenAndFadeOut: NO];
}
- (void)leaveFullscreenAndFadeOut: (BOOL)fadeout
{
NSMutableDictionary *dict1, *dict2;
NSRect frame;
BOOL blackout_other_displays = var_InheritBool(VLCIntf, "macosx-black");
if (!o_current_video_window)
return;
[self lockFullscreenAnimation];
[o_controls_bar setFullscreenState:NO];
//if (o_detached_video_window)
// [[o_detached_video_window controlsBar] setFullscreenState:NO];
/* We always try to do so */
[NSScreen unblackoutScreens];
vout_thread_t *p_vout = getVout();
if (p_vout) {
if (var_GetBool(p_vout, "video-on-top"))
[[o_video_view window] setLevel: NSStatusWindowLevel];
else
[[o_video_view window] setLevel: NSNormalWindowLevel];
vlc_object_release(p_vout);
}
[[o_video_view window] makeKeyAndOrderFront: nil];
/* Don't do anything if o_fullscreen_window is already closed */
if (!o_fullscreen_window) {
[self unlockFullscreenAnimation];
return;
}
if (fadeout) {
/* 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);
}
[o_fspanel setNonActive: nil];
[NSApp setPresentationOptions: NSApplicationPresentationDefault];
/* Will release the lock */
[self hasEndedFullscreen];
/* Our window is hidden, and might be faded. We need to workaround that, so note it
* here */
b_window_is_invisible = YES;
if (blackout_other_displays) {
CGDisplayFade(token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO);
CGReleaseDisplayFadeReservation(token);
}
return;
}
[o_current_video_window setAlphaValue: 0.0];
[o_current_video_window orderFront: self];
[[o_video_view window] orderFront: self];
[o_fspanel setNonActive: nil];
[NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
if (o_fullscreen_anim1) {
[o_fullscreen_anim1 stopAnimation];
[o_fullscreen_anim1 release];
}
if (o_fullscreen_anim2) {
[o_fullscreen_anim2 stopAnimation];
[o_fullscreen_anim2 release];
}
frame = [[o_temp_view superview] convertRect: [o_temp_view frame] toView: nil]; /* Convert to Window base coord */
frame.origin.x += [o_current_video_window frame].origin.x;
frame.origin.y += [o_current_video_window frame].origin.y;
dict2 = [[NSMutableDictionary alloc] initWithCapacity:2];
[dict2 setObject:o_current_video_window forKey:NSViewAnimationTargetKey];
[dict2 setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict2, nil]];
[dict2 release];
[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 arrayWithObjects:dict1, nil]];
[dict1 release];
[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
{
b_fullscreen = 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 o_video_view disappearing of the screen during this operation */
NSDisableScreenUpdates();
[o_video_view retain];
[o_video_view removeFromSuperviewWithoutNeedingDisplay];
[[o_temp_view superview] replaceSubview:o_temp_view with:o_video_view];
[o_video_view release];
[o_video_view setFrame:[o_temp_view frame]];
if ([[o_video_view subviews] count] > 0)
[[o_video_view window] makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
if (!b_nonembedded)
[super makeKeyAndOrderFront:self]; /* our version contains a workaround */
else
[[o_video_view window] makeKeyAndOrderFront: self];
[o_fullscreen_window orderOut: self];
NSEnableScreenUpdates();
[o_fullscreen_window release];
o_fullscreen_window = nil;
[[o_video_view window] setLevel:i_originalLevel];
[[o_video_view window] setAlphaValue: config_GetFloat(VLCIntf, "macosx-opaqueness")];
// if we quit fullscreen because there is no video anymore, make sure non-embedded window is not visible
if (![[VLCMain sharedInstance] activeVideoPlayback] && b_nonembedded)
[o_current_video_window orderOut: self];
o_current_video_window = nil;
[self unlockFullscreenAnimation];
}
- (void)animationDidEnd:(NSAnimation*)animation
{
NSArray *viewAnimations;
if (o_makekey_anim == animation) {
[o_makekey_anim release];
return;
}
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 objectAtIndex: 0] objectForKey: NSViewAnimationEffectKey] isEqualToString:NSViewAnimationFadeInEffect]) {
/* Fullscreen ended */
[self hasEndedFullscreen];
} else
/* Fullscreen started */
[self hasBecomeFullscreen];
}
- (void)makeKeyAndOrderFront: (id)sender
{
/* Hack

View File

@ -175,13 +175,14 @@
[[self window] performZoom: sender];
else if (sender == o_fullscreen_btn) {
// set fs directly to true, as the vars can be already true in some configs
var_SetBool(pl_Get(VLCIntf), "fullscreen", true);
vout_thread_t *p_vout = getVout();
if (p_vout) {
var_SetBool(p_vout, "fullscreen", true);
vlc_object_release(p_vout);
} else { // e.g. lion fullscreen toggle
[[VLCMain sharedInstance] setFullscreen:true forWindow:nil];
}
} else
msg_Err(VLCIntf, "unknown button action sender");

View File

@ -40,6 +40,8 @@
- (void)updateWindowsControlsBarWithSelector:(SEL)aSel;
- (void)updateWindowsUsingBlock:(void (^)(VLCVideoWindowCommon *o_window))windowUpdater;
- (void)updateWindow:(vout_window_t *)p_wnd withSelector:(SEL)aSel;
- (void)setNativeVideoSize:(NSSize)size forWindow:(vout_window_t *)p_wnd;
@end

View File

@ -54,10 +54,13 @@
return;
}
if ([[VLCMainWindow sharedInstance] fullscreen] && ![[VLCMainWindow sharedInstance] nativeFullscreenMode])
[o_window leaveFullscreen];
if (![NSStringFromClass([o_window class]) isEqualToString:@"VLCMainWindow"]) {
[o_window orderOut:self];
}
[o_vout_dict removeObjectForKey:o_key];
}
@ -70,6 +73,17 @@
}];
}
- (void)updateWindow:(vout_window_t *)p_wnd withSelector:(SEL)aSel;
{
VLCVideoWindowCommon *o_window = [o_vout_dict objectForKey:[NSValue valueWithPointer:p_wnd]];
if(!o_window) {
msg_Err(VLCIntf, "Cannot call selector for nonexisting window");
return;
}
[o_window performSelector:aSel];
}
- (void)updateWindowsUsingBlock:(void (^)(VLCVideoWindowCommon *o_window))windowUpdater
{
[o_vout_dict enumerateKeysAndObjectsUsingBlock:^(id key, VLCVideoWindowCommon *o_window, BOOL *stop) {

View File

@ -69,7 +69,7 @@ static const float f_min_video_height = 70.0;
* Common code for main window, detached window and extra video window
*****************************************************************************/
@interface VLCVideoWindowCommon : VLCWindow <NSWindowDelegate>
@interface VLCVideoWindowCommon : VLCWindow <NSWindowDelegate, NSAnimationDelegate>
{
NSRect previousSavedFrame;
BOOL b_dark_interface;
@ -80,6 +80,20 @@ static const float f_min_video_height = 70.0;
IBOutlet VLCControlsBarCommon *o_controls_bar;
NSSize nativeVideoSize;
// variables for fullscreen handling
VLCVideoWindowCommon *o_current_video_window;
VLCWindow * o_fullscreen_window;
NSViewAnimation * o_fullscreen_anim1;
NSViewAnimation * o_fullscreen_anim2;
NSViewAnimation * o_makekey_anim;
NSView * o_temp_view;
BOOL b_window_is_invisible;
NSRecursiveLock * o_animation_lock;
NSInteger i_originalLevel;
}
@property (nonatomic, assign) VLCVoutView* videoView;
@ -90,4 +104,8 @@ static const float f_min_video_height = 70.0;
- (void)setTitle:(NSString *)title;
/* fullscreen handling */
- (void)enterFullscreen;
- (void)leaveFullscreen;
@end

View File

@ -25,6 +25,8 @@
#import "Windows.h"
#import "intf.h"
#import "CoreInteraction.h"
#import "ControlsBar.h"
#import "VideoView.h"
/*****************************************************************************
* VLCWindow
@ -245,9 +247,18 @@
[self setMovableByWindowBackground: YES];
[self setCanBecomeKeyWindow:YES];
o_temp_view = [[NSView alloc] init];
[o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
return self;
}
- (void)dealloc
{
[o_temp_view release];
[super dealloc];
}
- (void)setTitle:(NSString *)title
{
if (b_dark_interface && o_titlebar_view)
@ -479,6 +490,352 @@
return proposedFrameSize;
}
#pragma mark -
#pragma mark Fullscreen Logic
- (void)lockFullscreenAnimation
{
[o_animation_lock lock];
}
- (void)unlockFullscreenAnimation
{
[o_animation_lock unlock];
}
- (void)enterFullscreen
{
NSMutableDictionary *dict1, *dict2;
NSScreen *screen;
NSRect screen_rect;
NSRect rect;
BOOL blackout_other_displays = var_InheritBool(VLCIntf, "macosx-black");
screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_InheritInteger(VLCIntf, "macosx-vdev")];
[self lockFullscreenAnimation];
if (!screen) {
msg_Dbg(VLCIntf, "chosen screen isn't present, using current screen for fullscreen mode");
screen = [self screen];
}
if (!screen) {
msg_Dbg(VLCIntf, "Using deepest screen");
screen = [NSScreen deepestScreen];
}
screen_rect = [screen frame];
if (o_controls_bar)
[o_controls_bar setFullscreenState:YES];
[[VLCMainWindow sharedInstance] recreateHideMouseTimer];
if (blackout_other_displays)
[screen blackoutOtherScreens];
/* Make sure we don't see the window flashes in float-on-top mode */
i_originalLevel = [self level];
[self setLevel:NSNormalWindowLevel];
/* 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 = [[o_video_view superview] convertRect: [o_video_view 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];
if (![self isVisible] || [self alphaValue] == 0.0) {
/* 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);
}
if ([screen mainScreen])
[NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
[[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
[o_temp_view setFrame:[o_video_view frame]];
[o_fullscreen_window setContentView:o_video_view];
[o_fullscreen_window makeKeyAndOrderFront:self];
[o_fullscreen_window orderFront:self animate:YES];
[o_fullscreen_window setFrame:screen_rect display:YES 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 o_video_view disappearing of the screen during this operation */
NSDisableScreenUpdates();
[[o_video_view superview] replaceSubview:o_video_view with:o_temp_view];
[o_temp_view setFrame:[o_video_view frame]];
[o_fullscreen_window setContentView:o_video_view];
[o_fullscreen_window makeKeyAndOrderFront:self];
NSEnableScreenUpdates();
}
/* We are in fullscreen (and no animation is running) */
if ([[VLCMainWindow sharedInstance] fullscreen]) {
/* Make sure we are hidden */
[self orderOut: self];
[self unlockFullscreenAnimation];
return;
}
if (o_fullscreen_anim1) {
[o_fullscreen_anim1 stopAnimation];
[o_fullscreen_anim1 release];
}
if (o_fullscreen_anim2) {
[o_fullscreen_anim2 stopAnimation];
[o_fullscreen_anim2 release];
}
if ([screen mainScreen])
[NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
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]];
[dict1 release];
[dict2 release];
[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 */
}
- (void)hasBecomeFullscreen
{
if ([[o_video_view subviews] count] > 0)
[o_fullscreen_window makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
[o_fullscreen_window makeKeyWindow];
[o_fullscreen_window setAcceptsMouseMovedEvents: YES];
/* tell the fspanel to move itself to front next time it's triggered */
[[[VLCMainWindow sharedInstance] fsPanel] setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]];
[[[VLCMainWindow sharedInstance] fsPanel] setActive: nil];
if ([self isVisible])
[self orderOut: self];
[[VLCMainWindow sharedInstance] setFullscreen:YES];
[self unlockFullscreenAnimation];
}
- (void)leaveFullscreen
{
[self leaveFullscreenAndFadeOut: NO];
}
- (void)leaveFullscreenAndFadeOut: (BOOL)fadeout
{
NSMutableDictionary *dict1, *dict2;
NSRect frame;
BOOL blackout_other_displays = var_InheritBool(VLCIntf, "macosx-black");
[self lockFullscreenAnimation];
if (o_controls_bar)
[o_controls_bar setFullscreenState:NO];
/* We always try to do so */
[NSScreen unblackoutScreens];
vout_thread_t *p_vout = getVout();
if (p_vout) {
if (var_GetBool(p_vout, "video-on-top"))
[[o_video_view window] setLevel: NSStatusWindowLevel];
else
[[o_video_view window] setLevel: NSNormalWindowLevel];
vlc_object_release(p_vout);
}
[[o_video_view window] makeKeyAndOrderFront: nil];
/* Don't do anything if o_fullscreen_window is already closed */
if (!o_fullscreen_window) {
[self unlockFullscreenAnimation];
return;
}
if (fadeout) {
/* 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);
}
[[[VLCMainWindow sharedInstance] fsPanel] setNonActive: nil];
[NSApp setPresentationOptions: NSApplicationPresentationDefault];
/* Will release the lock */
[self hasEndedFullscreen];
/* Our window is hidden, and might be faded. We need to workaround that, so note it
* here */
b_window_is_invisible = YES;
if (blackout_other_displays) {
CGDisplayFade(token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO);
CGReleaseDisplayFadeReservation(token);
}
return;
}
[self setAlphaValue: 0.0];
[self orderFront: self];
[[o_video_view window] orderFront: self];
[[[VLCMainWindow sharedInstance] fsPanel] setNonActive: nil];
[NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
if (o_fullscreen_anim1) {
[o_fullscreen_anim1 stopAnimation];
[o_fullscreen_anim1 release];
}
if (o_fullscreen_anim2) {
[o_fullscreen_anim2 stopAnimation];
[o_fullscreen_anim2 release];
}
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 arrayWithObjects:dict2, nil]];
[dict2 release];
[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 arrayWithObjects:dict1, nil]];
[dict1 release];
[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
{
[[VLCMainWindow sharedInstance] setFullscreen: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 o_video_view disappearing of the screen during this operation */
NSDisableScreenUpdates();
[o_video_view retain];
[o_video_view removeFromSuperviewWithoutNeedingDisplay];
[[o_temp_view superview] replaceSubview:o_temp_view with:o_video_view];
[o_video_view release];
[o_video_view setFrame:[o_temp_view frame]];
if ([[o_video_view subviews] count] > 0)
[self makeFirstResponder: [[o_video_view subviews] objectAtIndex:0]];
[super makeKeyAndOrderFront:self]; /* our version (in main window) contains a workaround */
[o_fullscreen_window orderOut: self];
NSEnableScreenUpdates();
[o_fullscreen_window release];
o_fullscreen_window = nil;
[self setLevel:i_originalLevel];
[self setAlphaValue: config_GetFloat(VLCIntf, "macosx-opaqueness")];
// if we quit fullscreen because there is no video anymore, make sure non-embedded window is not visible
if (![[VLCMain sharedInstance] activeVideoPlayback] && [self class] != [VLCMainWindow class])
[self orderOut: self];
[self unlockFullscreenAnimation];
}
- (void)animationDidEnd:(NSAnimation*)animation
{
NSArray *viewAnimations;
if (o_makekey_anim == animation) {
[o_makekey_anim release];
return;
}
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 objectAtIndex: 0] objectForKey: NSViewAnimationEffectKey] isEqualToString:NSViewAnimationFadeInEffect]) {
/* Fullscreen ended */
[self hasEndedFullscreen];
} else
/* Fullscreen started */
[self hasBecomeFullscreen];
}
#pragma mark -
#pragma mark Accessibility stuff

View File

@ -172,9 +172,10 @@ struct intf_sys_t
- (BOOL)activeVideoPlayback;
- (void)applicationWillTerminate:(NSNotification *)notification;
- (void)updateCurrentlyUsedHotkeys;
- (void)fullscreenChanged;
- (BOOL)hasDefinedShortcutKey:(NSEvent *)o_event force:(BOOL)b_force;
- (void)checkFullscreenChange:(NSNumber *)o_full;
- (void)setFullscreen:(int)i_full forWindow:(vout_window_t *)p_wnd;
- (void)PlaylistItemChanged;
- (void)playbackStatusUpdated;
- (void)sendDistributedNotificationWithUpdatedPlaybackStatus;

View File

@ -162,6 +162,20 @@ int WindowOpen(vout_window_t *p_wnd, const vout_window_cfg_t *cfg)
[inv performSelectorOnMainThread:@selector(invoke) withObject:nil
waitUntilDone:NO];
// TODO: find a cleaner way for "start in fullscreen"
if (var_GetBool(pl_Get(VLCIntf), "fullscreen")) {
int i_full = 1;
SEL sel = @selector(setFullscreen:forWindow:);
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[VLCMain sharedInstance] methodSignatureForSelector:sel]];
[inv setTarget:[VLCMain sharedInstance]];
[inv setSelector:sel];
[inv setArgument:&i_full atIndex:2];
[inv setArgument:&p_wnd atIndex:3];
[inv performSelectorOnMainThread:@selector(invoke) withObject:nil
waitUntilDone:NO];
}
[[VLCMain sharedInstance] setActiveVideoPlayback: YES];
p_wnd->control = WindowControl;
p_wnd->sys = (vout_window_sys_t *)VLCIntf;
@ -202,7 +216,18 @@ static int WindowControl(vout_window_t *p_wnd, int i_query, va_list args)
{
NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
int i_full = va_arg(args, int);
[[VLCMain sharedInstance] performSelectorOnMainThread:@selector(checkFullscreenChange:) withObject:[NSNumber numberWithInt: i_full] waitUntilDone:NO];
SEL sel = @selector(setFullscreen:forWindow:);
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[[VLCMain sharedInstance] methodSignatureForSelector:sel]];
[inv setTarget:[VLCMain sharedInstance]];
[inv setSelector:sel];
[inv setArgument:&i_full atIndex:2]; // starting at 2!
[inv setArgument:&p_wnd atIndex:3];
[inv performSelectorOnMainThread:@selector(invoke) withObject:nil
waitUntilDone:NO];
//[[VLCMain sharedInstance] performSelectorOnMainThread:@selector(fullscreenChanged:) withObject:[NSValue valueWithPointer:p_wnd] waitUntilDone:NO];
[o_pool release];
return VLC_SUCCESS;
}
@ -411,22 +436,6 @@ static int ShowController(vlc_object_t *p_this, const char *psz_variable,
return VLC_SUCCESS;
}
/*****************************************************************************
* FullscreenChanged: Callback triggered by the fullscreen-change playlist
* variable, to let the intf update the controller.
*****************************************************************************/
static int FullscreenChanged(vlc_object_t *p_this, const char *psz_variable,
vlc_value_t old_val, vlc_value_t new_val, void *param)
{
intf_thread_t * p_intf = VLCIntf;
if (p_intf) {
NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
[[VLCMain sharedInstance] performSelectorOnMainThread:@selector(fullscreenChanged) withObject:nil waitUntilDone:NO];
[o_pool release];
}
return VLC_SUCCESS;
}
/*****************************************************************************
* DialogCallback: Callback triggered by the "dialog-*" variables
* to let the intf display error and interaction dialogs
@ -609,7 +618,6 @@ static VLCMain *_o_sharedMainInstance = nil;
val.b_bool = false;
var_AddCallback(p_playlist, "fullscreen", FullscreenChanged, self);
var_AddCallback(p_intf->p_libvlc, "intf-toggle-fscontrol", ShowController, self);
var_AddCallback(p_intf->p_libvlc, "intf-show", ShowController, self);
// var_AddCallback(p_playlist, "item-change", PLItemChanged, self);
@ -796,7 +804,6 @@ static VLCMain *_o_sharedMainInstance = nil;
var_DelCallback(p_playlist, "loop", PlaybackModeUpdated, self);
var_DelCallback(p_playlist, "volume", VolumeUpdated, self);
var_DelCallback(p_playlist, "mute", VolumeUpdated, self);
var_DelCallback(p_playlist, "fullscreen", FullscreenChanged, self);
var_DelCallback(p_intf->p_libvlc, "intf-toggle-fscontrol", ShowController, self);
var_DelCallback(p_intf->p_libvlc, "intf-show", ShowController, self);
@ -1204,10 +1211,16 @@ static VLCMain *_o_sharedMainInstance = nil;
#pragma mark -
#pragma mark Interface updaters
- (void)fullscreenChanged
- (void)setFullscreen:(int)i_full forWindow:(vout_window_t *)p_wnd
{
playlist_t * p_playlist = pl_Get(VLCIntf);
BOOL b_fullscreen = var_GetBool(p_playlist, "fullscreen");
if (!p_intf || (!b_nativeFullscreenMode && !p_wnd))
return;
playlist_t * p_playlist = pl_Get(p_intf);
BOOL b_fullscreen = i_full;
if (!var_GetBool(p_playlist, "fullscreen") != !b_fullscreen) {
var_SetBool(p_playlist, "fullscreen", b_fullscreen);
}
if (b_nativeFullscreenMode) {
// this is called twice in certain situations, so only toogle if we really need to
@ -1220,30 +1233,25 @@ static VLCMain *_o_sharedMainInstance = nil;
else
[NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
} else {
assert(p_wnd);
if (b_fullscreen) {
input_thread_t * p_input = pl_CurrentInput(VLCIntf);
input_thread_t * p_input = pl_CurrentInput(p_intf);
if (p_input != NULL && [self activeVideoPlayback]) {
// activate app, as method can also be triggered from outside the app (prevents nasty window layout)
[NSApp activateIgnoringOtherApps:YES];
[o_mainwindow performSelectorOnMainThread:@selector(enterFullscreen) withObject:nil waitUntilDone:NO];
[o_vout_controller updateWindow:p_wnd withSelector:@selector(enterFullscreen)];
}
if (p_input)
vlc_object_release(p_input);
} else {
// leaving fullscreen is always allowed
[o_mainwindow performSelectorOnMainThread:@selector(leaveFullscreen) withObject:nil waitUntilDone:NO];
[o_vout_controller updateWindow:p_wnd withSelector:@selector(leaveFullscreen)];
}
}
}
- (void)checkFullscreenChange:(NSNumber *)o_full
{
BOOL b_full = [o_full boolValue];
if (p_intf && !var_GetBool(pl_Get(p_intf), "fullscreen") != !b_full) {
var_SetBool(pl_Get(p_intf), "fullscreen", b_full);
}
}
- (void)PlaylistItemChanged
{
if (p_current_input && (p_current_input->b_dead || !vlc_object_alive(p_current_input))) {