X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fmacosx%2Fembeddedwindow.m;h=e2ff658dc2204266b01a7167eb3056d8b06ea484;hb=46c93c9cc984b99142b6e7321c8f5c4c8c4e65bb;hp=232ce2aec30c2ec99645fb51634488b5ed9770bd;hpb=bf9fed9bb16f7252c3d2264ed3566a48363ac8a7;p=vlc diff --git a/modules/gui/macosx/embeddedwindow.m b/modules/gui/macosx/embeddedwindow.m index 232ce2aec3..e2ff658dc2 100644 --- a/modules/gui/macosx/embeddedwindow.m +++ b/modules/gui/macosx/embeddedwindow.m @@ -1,10 +1,11 @@ /***************************************************************************** * embeddedwindow.m: MacOS X interface module ***************************************************************************** - * Copyright (C) 2005-2006 the VideoLAN team + * Copyright (C) 2005-2009 the VideoLAN team * $Id$ * * Authors: Benjamin Pracht + * Felix Paul Kühne * * 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 @@ -25,9 +26,6 @@ * Preamble *****************************************************************************/ -/* DisableScreenUpdates, SetSystemUIMode, ... */ -#import - #import "intf.h" #import "controls.h" #import "vout.h" @@ -40,6 +38,22 @@ @implementation VLCEmbeddedWindow +- (id)initWithContentRect:(NSRect)contentRect styleMask: (NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation +{ + BOOL b_useTextured = YES; + if( [[NSWindow class] instancesRespondToSelector:@selector(setContentBorderThickness:forEdge:)] ) + { + b_useTextured = NO; + windowStyle ^= NSTexturedBackgroundWindowMask; + } + self = [super initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; + if(! b_useTextured ) + { + [self setContentBorderThickness:28.0 forEdge:NSMinYEdge]; + } + return self; +} + - (void)awakeFromNib { [self setDelegate: self]; @@ -51,11 +65,12 @@ [o_slider setToolTip: _NS("Position")]; o_img_play = [NSImage imageNamed: @"play_embedded"]; - o_img_play_pressed = [NSImage imageNamed: @"play_embedded_blue"]; o_img_pause = [NSImage imageNamed: @"pause_embedded"]; - o_img_pause_pressed = [NSImage imageNamed: @"pause_embedded_blue"]; - - o_saved_frame = NSMakeRect( 0.0f, 0.0f, 0.0f, 0.0f ); + [self controlTintChanged]; + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector( controlTintChanged ) + name: NSControlTintDidChangeNotification + object: nil]; /* Useful to save o_view frame in fullscreen mode */ o_temp_view = [[NSView alloc] init]; @@ -67,7 +82,55 @@ /* Not fullscreen when we wake up */ [o_btn_fullscreen setState: NO]; b_fullscreen = NO; - o_animation_lock = [[NSLock alloc] init]; + + [self setMovableByWindowBackground:YES]; + + [self setDelegate:self]; + + /* Make sure setVisible: returns NO */ + [self orderOut:self]; + b_window_is_invisible = YES; + videoRatio = NSMakeSize( 0., 0. ); +} + +- (void)controlTintChanged +{ + BOOL b_playing = NO; + if( [o_btn_play alternateImage] == o_img_play_pressed ) + b_playing = YES; + + if( [NSColor currentControlTint] == NSGraphiteControlTint ) + { + o_img_play_pressed = [NSImage imageNamed: @"play_embedded_graphite"]; + o_img_pause_pressed = [NSImage imageNamed: @"pause_embedded_graphite"]; + [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_embedded_graphite"]]; + [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_embedded_graphite"]]; + [o_btn_fullscreen setAlternateImage: [NSImage imageNamed: @"fullscreen_graphite"]]; + } + else + { + o_img_play_pressed = [NSImage imageNamed: @"play_embedded_blue"]; + o_img_pause_pressed = [NSImage imageNamed: @"pause_embedded_blue"]; + [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_embedded_blue"]]; + [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_embedded_blue"]]; + [o_btn_fullscreen setAlternateImage: [NSImage imageNamed: @"fullscreen_blue"]]; + } + + if( b_playing ) + [o_btn_play setAlternateImage: o_img_play_pressed]; + else + [o_btn_play setAlternateImage: o_img_pause_pressed]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver: self]; + [o_img_play release]; + [o_img_play_pressed release]; + [o_img_pause release]; + [o_img_pause_pressed release]; + + [super dealloc]; } - (void)setTime:(NSString *)o_arg_time position:(float)f_position @@ -99,32 +162,18 @@ [o_slider setEnabled: b_seekable]; } -- (void)zoom:(id)sender +- (BOOL)windowShouldZoom:(NSWindow *)sender toFrame:(NSRect)newFrame { - if( ![self isZoomed] ) - { - NSRect zoomRect = [[self screen] frame]; - o_saved_frame = [self frame]; - /* we don't have to take care of the eventual menu bar and dock - as zoomRect will be cropped automatically by setFrame:display: - to the right rectangle */ - [self setFrame: zoomRect display: YES animate: YES]; - } - else - { - /* unzoom to the saved_frame if the o_saved_frame coords look sound - (just in case) */ - if( o_saved_frame.size.width > 0 && o_saved_frame.size.height > 0 ) - [self setFrame: o_saved_frame display: YES animate: YES]; - } + [self setFrame: newFrame display: YES animate: YES]; + return NO; } - (BOOL)windowShouldClose:(id)sender { - playlist_t * p_playlist = pl_Yield( VLCIntf ); + playlist_t * p_playlist = pl_Hold( VLCIntf ); playlist_Stop( p_playlist ); - vlc_object_release( p_playlist ); + pl_Release( VLCIntf ); return YES; } @@ -136,6 +185,25 @@ return o_view; } +- (void)setVideoRatio:(NSSize)ratio +{ + videoRatio = ratio; +} + +- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize +{ + if( videoRatio.height == 0. || videoRatio.width == 0. ) + return proposedFrameSize; + + NSRect viewRect = [o_view convertRect:[o_view bounds] toView: nil]; + NSRect contentRect = [self contentRectForFrameRect:[self frame]]; + float marginy = viewRect.origin.y + [self frame].size.height - contentRect.size.height; + float marginx = contentRect.size.width - viewRect.size.width; + proposedFrameSize.height = (proposedFrameSize.width - marginx) * videoRatio.height / videoRatio.width + marginy; + + return proposedFrameSize; +} + /***************************************************************************** * Fullscreen support */ @@ -162,25 +230,37 @@ NSRect screen_rect; NSRect rect; vout_thread_t *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT, FIND_ANYWHERE ); - BOOL blackout_other_displays = var_GetBool( p_vout, "macosx-black" ); + BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" ); - screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_GetInteger( p_vout, "video-device" )]; - - vlc_object_release( p_vout ); - + screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_GetInteger( p_vout, "video-device" )]; + [self lockFullscreenAnimation]; if (!screen) + { + msg_Dbg( p_vout, "chosen screen isn't present, using current screen for fullscreen mode" ); screen = [self screen]; + } + if (!screen) + { + msg_Dbg( p_vout, "Using deepest screen" ); + screen = [NSScreen deepestScreen]; + } + + vlc_object_release( p_vout ); screen_rect = [screen frame]; [o_btn_fullscreen setState: YES]; [NSCursor setHiddenUntilMouseMoves: YES]; - - if (blackout_other_displays) - [screen blackoutOtherScreens]; /* We should do something like [screen blackoutOtherScreens]; */ + + if( blackout_other_displays ) + [screen blackoutOtherScreens]; + + /* Make sure we don't see the window flashes in float-on-top mode */ + 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) @@ -194,28 +274,28 @@ [o_fullscreen_window setBackgroundColor: [NSColor blackColor]]; [o_fullscreen_window setCanBecomeKeyWindow: YES]; - if (![self isVisible] || [self alphaValue] == 0.0 || MACOS_VERSION < 10.4f) + if (![self isVisible] || [self alphaValue] == 0.0) { - /* We don't animate if we are not visible or if we are running on - * Mac OS X <10.4 which doesn't support NSAnimation, instead we + /* We don't animate if we are not visible, instead we * simply fade the display */ CGDisplayFadeReservationToken token; - - [o_fullscreen_window setFrame:screen_rect display:NO]; - + CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token); - CGDisplayFade( token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES ); - + CGDisplayFade( token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES ); + if ([screen isMainScreen]) - SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar); - + [NSMenu setMenuBarVisible:NO]; + [[self contentView] replaceSubview:o_view with:o_temp_view]; [o_temp_view setFrame:[o_view frame]]; [o_fullscreen_window setContentView:o_view]; + [o_fullscreen_window makeKeyAndOrderFront:self]; - [self orderOut: self]; + [o_fullscreen_window orderFront:self animate:YES]; + + [o_fullscreen_window setFrame:screen_rect display:YES]; - CGDisplayFade( token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO ); + CGDisplayFade( token, 0.3, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO ); CGReleaseDisplayFadeReservation( token); /* Will release the lock */ @@ -223,27 +303,21 @@ return; } - + /* Make sure we don't see the o_view disappearing of the screen during this operation */ - DisableScreenUpdates(); - [[self contentView] replaceSubview:o_view with:o_temp_view]; + NSEnableScreenUpdates(); + [[self contentView] replaceSubview:o_view with:o_temp_view]; [o_temp_view setFrame:[o_view frame]]; [o_fullscreen_window setContentView:o_view]; [o_fullscreen_window makeKeyAndOrderFront:self]; - EnableScreenUpdates(); - } - - if (MACOS_VERSION < 10.4f) - { - /* We were already fullscreen nothing to do when NSAnimation - * is not supported */ - [self unlockFullscreenAnimation]; - return; + NSDisableScreenUpdates(); } /* We are in fullscreen (and no animation is running) */ if (b_fullscreen) { + /* Make sure we are hidden */ + [super orderOut: self]; [self unlockFullscreenAnimation]; return; } @@ -260,7 +334,7 @@ } if ([screen isMainScreen]) - SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar); + [NSMenu setMenuBarVisible:NO]; dict1 = [[NSMutableDictionary alloc] initWithCapacity:2]; dict2 = [[NSMutableDictionary alloc] initWithCapacity:3]; @@ -298,20 +372,29 @@ - (void)hasBecomeFullscreen { - [o_fullscreen_window makeFirstResponder: [[[VLCMain sharedInstance] getControls] getVoutView]]; + [o_fullscreen_window makeFirstResponder: [[[VLCMain sharedInstance] controls] voutView]]; [o_fullscreen_window makeKeyWindow]; [o_fullscreen_window setAcceptsMouseMovedEvents: TRUE]; /* tell the fspanel to move itself to front next time it's triggered */ - [[[[VLCMain sharedInstance] getControls] getFSPanel] setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]]; - - [[[[VLCMain sharedInstance] getControls] getFSPanel] setActive: nil]; + [[[[VLCMain sharedInstance] controls] fspanel] setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]]; + + if([self isVisible]) + [super orderOut: self]; + + [[[[VLCMain sharedInstance] controls] fspanel] setActive: nil]; + b_fullscreen = YES; [self unlockFullscreenAnimation]; } - (void)leaveFullscreen +{ + [self leaveFullscreenAndFadeOut: NO]; +} + +- (void)leaveFullscreenAndFadeOut: (BOOL)fadeout { NSMutableDictionary *dict1, *dict2; NSRect frame; @@ -327,33 +410,39 @@ /* Don't do anything if o_fullscreen_window is already closed */ if (!o_fullscreen_window) { - [self lockFullscreenAnimation]; + [self unlockFullscreenAnimation]; return; } - if (![self isVisible] || MACOS_VERSION < 10.4f) + if (fadeout) { - /* We don't animate if we are not visible or if we are running on - * Mac OS X <10.4 which doesn't support NSAnimation, instead we + /* We don't animate if we are not visible, instead we * simply fade the display */ CGDisplayFadeReservationToken token; CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token); CGDisplayFade( token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES ); - [[[[VLCMain sharedInstance] getControls] getFSPanel] setNonActive: nil]; - SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar); + [[[[VLCMain sharedInstance] controls] fspanel] setNonActive: nil]; + [NSMenu setMenuBarVisible:YES]; /* 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; + CGDisplayFade( token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO ); CGReleaseDisplayFadeReservation( token); return; } - [[[[VLCMain sharedInstance] getControls] getFSPanel] setNonActive: nil]; - SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar); + [self setAlphaValue: 0.0]; + [self orderFront: self]; + + [[[[VLCMain sharedInstance] controls] fspanel] setNonActive: nil]; + [NSMenu setMenuBarVisible:YES]; if (o_fullscreen_anim1) { @@ -367,7 +456,7 @@ } 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.x += [self frame].origin.x; frame.origin.y += [self frame].origin.y; dict2 = [[NSMutableDictionary alloc] initWithCapacity:2]; @@ -396,6 +485,10 @@ [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 */ } @@ -404,19 +497,22 @@ { /* 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_view disappearing of the screen during this operation */ - DisableScreenUpdates(); + NSDisableScreenUpdates(); [o_view retain]; [o_view removeFromSuperviewWithoutNeedingDisplay]; [[self contentView] replaceSubview:o_temp_view with:o_view]; [o_view release]; [o_view setFrame:[o_temp_view frame]]; + [self makeFirstResponder: o_view]; if ([self isVisible]) - [self makeKeyAndOrderFront:self]; + [super makeKeyAndOrderFront:self]; /* our version contains a workaround */ [o_fullscreen_window orderOut: self]; - EnableScreenUpdates(); + NSEnableScreenUpdates(); [o_fullscreen_window release]; o_fullscreen_window = nil; + [self setLevel:originalLevel]; + [self unlockFullscreenAnimation]; } @@ -445,10 +541,46 @@ - (void)orderOut: (id)sender { [super orderOut: sender]; + /* Make sure we leave fullscreen */ - [self leaveFullscreen]; + [self leaveFullscreenAndFadeOut: YES]; } +- (void)makeKeyAndOrderFront: (id)sender +{ + /* Hack + * when we exit fullscreen and fade out, we may endup in + * having a window that is faded. We can't have it fade in unless we + * animate again. */ + + if(!b_window_is_invisible) + { + /* Make sure we don't do it too much */ + [super makeKeyAndOrderFront: sender]; + return; + } + + [super setAlphaValue:0.0f]; + [super makeKeyAndOrderFront: sender]; + + NSMutableDictionary * dict = [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease]; + [dict setObject:self forKey:NSViewAnimationTargetKey]; + [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey]; + + NSViewAnimation * anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict]]; + + [anim setAnimationBlockingMode: NSAnimationNonblocking]; + [anim setDuration: 0.1]; + [anim setFrameRate: 30]; + + [anim startAnimation]; + b_window_is_invisible = NO; + + /* fullscreenAnimation will be unlocked when animation ends */ +} + + + /* Make sure setFrame gets executed on main thread especially if we are animating. * (Thus we won't block the video output thread) */ - (void)setFrame:(NSRect)frame display:(BOOL)display animate:(BOOL)animate @@ -470,6 +602,24 @@ { struct args { NSRect frame; BOOL display; BOOL animate; } * args = (struct args*)[packedargs bytes]; - [super setFrame: args->frame display: args->display animate:args->animate]; + if( args->animate ) + { + /* Make sure we don't block too long and set up a non blocking animation */ + NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys: + self, NSViewAnimationTargetKey, + [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey, + [NSValue valueWithRect:args->frame], NSViewAnimationEndFrameKey, nil]; + + NSViewAnimation * anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]]; + + [anim setAnimationBlockingMode: NSAnimationNonblocking]; + [anim setDuration: 0.4]; + [anim setFrameRate: 30]; + [anim startAnimation]; + } + else { + [super setFrame:args->frame display:args->display animate:args->animate]; + } + } @end