| /* |
| * Copyright (C) 2009 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #if ENABLE(VIDEO) |
| |
| #import "WebVideoFullscreenController.h" |
| |
| #import "WebTypesInternal.h" |
| #import "WebVideoFullscreenHUDWindowController.h" |
| #import "WebWindowAnimation.h" |
| #import <IOKit/pwr_mgt/IOPMLib.h> |
| #import <OSServices/Power.h> |
| #import <QTKit/QTKit.h> |
| #import <WebCore/HTMLMediaElement.h> |
| #import <WebCore/SoftLinking.h> |
| #import <objc/objc-runtime.h> |
| #import <wtf/UnusedParam.h> |
| |
| #if USE(GSTREAMER) |
| #import <WebCore/GStreamerGWorld.h> |
| #endif |
| |
| SOFT_LINK_FRAMEWORK(QTKit) |
| SOFT_LINK_CLASS(QTKit, QTMovieLayer) |
| |
| SOFT_LINK_POINTER(QTKit, QTMovieRateDidChangeNotification, NSString *) |
| |
| #define QTMovieRateDidChangeNotification getQTMovieRateDidChangeNotification() |
| static const NSTimeInterval tickleTimerInterval = 1.0; |
| |
| @interface WebVideoFullscreenWindow : NSWindow |
| #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) |
| <NSAnimationDelegate> |
| #endif |
| { |
| SEL _controllerActionOnAnimationEnd; |
| WebWindowScaleAnimation *_fullscreenAnimation; // (retain) |
| } |
| - (void)animateFromRect:(NSRect)startRect toRect:(NSRect)endRect withSubAnimation:(NSAnimation *)subAnimation controllerAction:(SEL)controllerAction; |
| @end |
| |
| @interface WebVideoFullscreenController(HUDWindowControllerDelegate) <WebVideoFullscreenHUDWindowControllerDelegate> |
| - (void)requestExitFullscreenWithAnimation:(BOOL)animation; |
| - (void)updateMenuAndDockForFullscreen; |
| - (void)updatePowerAssertions; |
| @end |
| |
| @interface NSWindow(IsOnActiveSpaceAdditionForTigerAndLeopard) |
| - (BOOL)isOnActiveSpace; |
| @end |
| |
| @implementation WebVideoFullscreenController |
| - (id)init |
| { |
| // Do not defer window creation, to make sure -windowNumber is created (needed by WebWindowScaleAnimation). |
| NSWindow *window = [[WebVideoFullscreenWindow alloc] initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; |
| self = [super initWithWindow:window]; |
| [window release]; |
| if (!self) |
| return nil; |
| [self windowDidLoad]; |
| return self; |
| |
| } |
| - (void)dealloc |
| { |
| ASSERT(!_backgroundFullscreenWindow); |
| ASSERT(!_fadeAnimation); |
| [_tickleTimer invalidate]; |
| [_tickleTimer release]; |
| _tickleTimer = nil; |
| [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| [super dealloc]; |
| } |
| |
| - (WebVideoFullscreenWindow *)fullscreenWindow |
| { |
| return (WebVideoFullscreenWindow *)[super window]; |
| } |
| |
| - (void)setupVideoOverlay:(QTMovieLayer*)layer |
| { |
| WebVideoFullscreenWindow *window = [self fullscreenWindow]; |
| #if USE(GSTREAMER) |
| if (_mediaElement && _mediaElement->platformMedia().type == WebCore::PlatformMedia::GStreamerGWorldType) { |
| WebCore::GStreamerGWorld* gstGworld = _mediaElement->platformMedia().media.gstreamerGWorld; |
| if (gstGworld->enterFullscreen()) |
| [window setContentView:gstGworld->platformVideoWindow()->window()]; |
| } |
| #else |
| [[window contentView] setLayer:layer]; |
| [[window contentView] setWantsLayer:YES]; |
| if (_mediaElement && _mediaElement->platformMedia().type == WebCore::PlatformMedia::QTMovieType) |
| [layer setMovie:_mediaElement->platformMedia().media.qtMovie]; |
| #endif |
| } |
| |
| - (void)windowDidLoad |
| { |
| #ifdef BUILDING_ON_TIGER |
| // WebVideoFullscreenController is not supported on Tiger: |
| ASSERT_NOT_REACHED(); |
| #else |
| WebVideoFullscreenWindow *window = [self fullscreenWindow]; |
| [window setHasShadow:YES]; // This is nicer with a shadow. |
| [window setLevel:NSPopUpMenuWindowLevel-1]; |
| |
| QTMovieLayer *layer = [[getQTMovieLayerClass() alloc] init]; |
| [self setupVideoOverlay:layer]; |
| [layer release]; |
| |
| #if !USE(GSTREAMER) |
| [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidResignActive:) name:NSApplicationDidResignActiveNotification object:NSApp]; |
| [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidChangeScreenParameters:) name:NSApplicationDidChangeScreenParametersNotification object:NSApp]; |
| #endif |
| #endif |
| } |
| |
| - (WebCore::HTMLMediaElement*)mediaElement |
| { |
| return _mediaElement.get(); |
| } |
| |
| - (void)setMediaElement:(WebCore::HTMLMediaElement*)mediaElement |
| { |
| #ifdef BUILDING_ON_TIGER |
| // WebVideoFullscreenController is not supported on Tiger: |
| ASSERT_NOT_REACHED(); |
| #else |
| _mediaElement = mediaElement; |
| if ([self isWindowLoaded]) { |
| QTMovieLayer *movieLayer = (QTMovieLayer *)[[[self fullscreenWindow] contentView] layer]; |
| |
| ASSERT(movieLayer && [movieLayer isKindOfClass:[getQTMovieLayerClass() class]]); |
| [self setupVideoOverlay:movieLayer]; |
| #if !USE(GSTREAMER) |
| ASSERT([movieLayer movie]); |
| [[NSNotificationCenter defaultCenter] addObserver:self |
| selector:@selector(rateChanged:) |
| name:QTMovieRateDidChangeNotification |
| object:[movieLayer movie]]; |
| #endif |
| } |
| #endif |
| } |
| |
| - (id <WebVideoFullscreenControllerDelegate>)delegate |
| { |
| return _delegate; |
| } |
| |
| - (void)setDelegate:(id <WebVideoFullscreenControllerDelegate>)delegate |
| { |
| _delegate = delegate; |
| } |
| |
| - (CGFloat)clearFadeAnimation |
| { |
| [_fadeAnimation stopAnimation]; |
| CGFloat previousAlpha = [_fadeAnimation currentAlpha]; |
| [_fadeAnimation setWindow:nil]; |
| [_fadeAnimation release]; |
| _fadeAnimation = nil; |
| return previousAlpha; |
| } |
| |
| - (void)windowDidExitFullscreen |
| { |
| #if USE(GSTREAMER) |
| if (_mediaElement && _mediaElement->platformMedia().type == WebCore::PlatformMedia::GStreamerGWorldType) |
| _mediaElement->platformMedia().media.gstreamerGWorld->exitFullscreen(); |
| #endif |
| [self clearFadeAnimation]; |
| [[self window] close]; |
| [self setWindow:nil]; |
| [self updateMenuAndDockForFullscreen]; |
| [self updatePowerAssertions]; |
| [_hudController setDelegate:nil]; |
| [_hudController release]; |
| _hudController = nil; |
| [_backgroundFullscreenWindow close]; |
| [_backgroundFullscreenWindow release]; |
| _backgroundFullscreenWindow = nil; |
| |
| [self autorelease]; // Associated -retain is in -exitFullscreen. |
| _isEndingFullscreen = NO; |
| } |
| |
| - (void)windowDidEnterFullscreen |
| { |
| [self clearFadeAnimation]; |
| |
| ASSERT(!_hudController); |
| _hudController = [[WebVideoFullscreenHUDWindowController alloc] init]; |
| [_hudController setDelegate:self]; |
| |
| [self updateMenuAndDockForFullscreen]; |
| [self updatePowerAssertions]; |
| [NSCursor setHiddenUntilMouseMoves:YES]; |
| |
| // Give the HUD keyboard focus initially |
| [_hudController fadeWindowIn]; |
| } |
| |
| - (NSRect)mediaElementRect |
| { |
| return _mediaElement->screenRect(); |
| } |
| |
| - (void)applicationDidResignActive:(NSNotification*)notification |
| { |
| // Check to see if the fullscreenWindow is on the active space; this function is available |
| // on 10.6 and later, so default to YES if the function is not available: |
| NSWindow* fullscreenWindow = [self fullscreenWindow]; |
| BOOL isOnActiveSpace = ([fullscreenWindow respondsToSelector:@selector(isOnActiveSpace)] ? [fullscreenWindow isOnActiveSpace] : YES); |
| |
| // Replicate the QuickTime Player (X) behavior when losing active application status: |
| // Is the fullscreen screen the main screen? (Note: this covers the case where only a |
| // single screen is available.) Is the fullscreen screen on the current space? IFF so, |
| // then exit fullscreen mode. |
| if ([fullscreenWindow screen] == [[NSScreen screens] objectAtIndex:0] && isOnActiveSpace) |
| [self requestExitFullscreenWithAnimation:NO]; |
| } |
| |
| |
| // MARK: - |
| // MARK: Exposed Interface |
| |
| static void constrainFrameToRatioOfFrame(NSRect *frameToConstrain, const NSRect *frame) |
| { |
| // Keep a constrained aspect ratio for the destination window |
| double originalRatio = frame->size.width / frame->size.height; |
| double newRatio = frameToConstrain->size.width / frameToConstrain->size.height; |
| if (newRatio > originalRatio) { |
| double newWidth = originalRatio * frameToConstrain->size.height; |
| double diff = frameToConstrain->size.width - newWidth; |
| frameToConstrain->size.width = newWidth; |
| frameToConstrain->origin.x += diff / 2; |
| } else { |
| double newHeight = frameToConstrain->size.width / originalRatio; |
| double diff = frameToConstrain->size.height - newHeight; |
| frameToConstrain->size.height = newHeight; |
| frameToConstrain->origin.y += diff / 2; |
| } |
| } |
| |
| static NSWindow *createBackgroundFullscreenWindow(NSRect frame, int level) |
| { |
| NSWindow *window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; |
| [window setOpaque:YES]; |
| [window setBackgroundColor:[NSColor blackColor]]; |
| [window setLevel:level]; |
| [window setReleasedWhenClosed:NO]; |
| return window; |
| } |
| |
| - (void)setupFadeAnimationIfNeededAndFadeIn:(BOOL)fadeIn |
| { |
| CGFloat initialAlpha = fadeIn ? 0 : 1; |
| if (_fadeAnimation) { |
| // Make sure we support queuing animation if the previous one isn't over yet |
| initialAlpha = [self clearFadeAnimation]; |
| } |
| if (!_forceDisableAnimation) |
| _fadeAnimation = [[WebWindowFadeAnimation alloc] initWithDuration:0.2 window:_backgroundFullscreenWindow initialAlpha:initialAlpha finalAlpha:fadeIn ? 1 : 0]; |
| } |
| |
| - (void)enterFullscreen:(NSScreen *)screen |
| { |
| if (!screen) |
| screen = [NSScreen mainScreen]; |
| |
| NSRect frame = [self mediaElementRect]; |
| NSRect endFrame = [screen frame]; |
| constrainFrameToRatioOfFrame(&endFrame, &frame); |
| |
| // Create a black window if needed |
| if (!_backgroundFullscreenWindow) |
| _backgroundFullscreenWindow = createBackgroundFullscreenWindow([screen frame], [[self window] level]-1); |
| else |
| [_backgroundFullscreenWindow setFrame:[screen frame] display:NO]; |
| |
| [self setupFadeAnimationIfNeededAndFadeIn:YES]; |
| if (_forceDisableAnimation) { |
| // This will disable scale animation |
| frame = NSZeroRect; |
| } |
| [[self fullscreenWindow] animateFromRect:frame toRect:endFrame withSubAnimation:_fadeAnimation controllerAction:@selector(windowDidEnterFullscreen)]; |
| |
| [_backgroundFullscreenWindow orderWindow:NSWindowBelow relativeTo:[[self fullscreenWindow] windowNumber]]; |
| } |
| |
| - (void)exitFullscreen |
| { |
| if (_isEndingFullscreen) |
| return; |
| _isEndingFullscreen = YES; |
| [_hudController closeWindow]; |
| |
| NSRect endFrame = [self mediaElementRect]; |
| |
| [self setupFadeAnimationIfNeededAndFadeIn:NO]; |
| if (_forceDisableAnimation) { |
| // This will disable scale animation |
| endFrame = NSZeroRect; |
| } |
| |
| // We have to retain ourselves because we want to be alive for the end of the animation. |
| // If our owner releases us we could crash if this is not the case. |
| // Balanced in windowDidExitFullscreen |
| [self retain]; |
| |
| [[self fullscreenWindow] animateFromRect:[[self window] frame] toRect:endFrame withSubAnimation:_fadeAnimation controllerAction:@selector(windowDidExitFullscreen)]; |
| } |
| |
| - (void)applicationDidChangeScreenParameters:(NSNotification*)notification |
| { |
| // The user may have changed the main screen by moving the menu bar, or they may have changed |
| // the Dock's size or location, or they may have changed the fullscreen screen's dimensions. |
| // Update our presentation parameters, and ensure that the full screen window occupies the |
| // entire screen: |
| [self updateMenuAndDockForFullscreen]; |
| [[self window] setFrame:[[[self window] screen] frame] display:YES]; |
| } |
| |
| - (void)updateMenuAndDockForFullscreen |
| { |
| // NSApplicationPresentationOptions is available on > 10.6 only: |
| #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) |
| NSApplicationPresentationOptions options = NSApplicationPresentationDefault; |
| NSScreen* fullscreenScreen = [[self window] screen]; |
| |
| if (!_isEndingFullscreen) { |
| // Auto-hide the menu bar if the fullscreenScreen contains the menu bar: |
| // NOTE: if the fullscreenScreen contains the menu bar but not the dock, we must still |
| // auto-hide the dock, or an exception will be thrown. |
| if ([[NSScreen screens] objectAtIndex:0] == fullscreenScreen) |
| options |= (NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock); |
| // Check if the current screen contains the dock by comparing the screen's frame to its |
| // visibleFrame; if a dock is present, the visibleFrame will differ. If the current screen |
| // contains the dock, hide it. |
| else if (!NSEqualRects([fullscreenScreen frame], [fullscreenScreen visibleFrame])) |
| options |= NSApplicationPresentationAutoHideDock; |
| } |
| |
| if ([NSApp respondsToSelector:@selector(setPresentationOptions:)]) |
| [NSApp setPresentationOptions:options]; |
| else |
| #endif |
| SetSystemUIMode(_isEndingFullscreen ? kUIModeNormal : kUIModeAllHidden, 0); |
| } |
| |
| #if !defined(BUILDING_ON_TIGER) // IOPMAssertionCreateWithName not defined on < 10.5 |
| - (void)_disableIdleDisplaySleep |
| { |
| if (_idleDisplaySleepAssertion == kIOPMNullAssertionID) |
| #if defined(BUILDING_ON_LEOPARD) // IOPMAssertionCreateWithName is not defined in the 10.5 SDK |
| IOPMAssertionCreate(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, &_idleDisplaySleepAssertion); |
| #else // IOPMAssertionCreate is depreciated in > 10.5 |
| IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, CFSTR("WebKit playing a video fullscreen."), &_idleDisplaySleepAssertion); |
| #endif |
| } |
| |
| - (void)_enableIdleDisplaySleep |
| { |
| if (_idleDisplaySleepAssertion != kIOPMNullAssertionID) { |
| IOPMAssertionRelease(_idleDisplaySleepAssertion); |
| _idleDisplaySleepAssertion = kIOPMNullAssertionID; |
| } |
| } |
| |
| - (void)_disableIdleSystemSleep |
| { |
| if (_idleSystemSleepAssertion == kIOPMNullAssertionID) |
| #if defined(BUILDING_ON_LEOPARD) // IOPMAssertionCreateWithName is not defined in the 10.5 SDK |
| IOPMAssertionCreate(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, &_idleSystemSleepAssertion); |
| #else // IOPMAssertionCreate is depreciated in > 10.5 |
| IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, CFSTR("WebKit playing a video fullscreen."), &_idleSystemSleepAssertion); |
| #endif |
| } |
| |
| - (void)_enableIdleSystemSleep |
| { |
| if (_idleSystemSleepAssertion != kIOPMNullAssertionID) { |
| IOPMAssertionRelease(_idleSystemSleepAssertion); |
| _idleSystemSleepAssertion = kIOPMNullAssertionID; |
| } |
| } |
| |
| - (void)_enableTickleTimer |
| { |
| [_tickleTimer invalidate]; |
| [_tickleTimer release]; |
| _tickleTimer = [[NSTimer scheduledTimerWithTimeInterval:tickleTimerInterval target:self selector:@selector(_tickleTimerFired) userInfo:nil repeats:YES] retain]; |
| } |
| |
| - (void)_disableTickleTimer |
| { |
| [_tickleTimer invalidate]; |
| [_tickleTimer release]; |
| _tickleTimer = nil; |
| } |
| |
| - (void)_tickleTimerFired |
| { |
| UpdateSystemActivity(OverallAct); |
| } |
| #endif |
| |
| - (void)updatePowerAssertions |
| { |
| #if !defined(BUILDING_ON_TIGER) |
| float rate = 0; |
| if (_mediaElement && _mediaElement->platformMedia().type == WebCore::PlatformMedia::QTMovieType) |
| rate = [_mediaElement->platformMedia().media.qtMovie rate]; |
| |
| if (rate && !_isEndingFullscreen) { |
| [self _disableIdleSystemSleep]; |
| [self _disableIdleDisplaySleep]; |
| [self _enableTickleTimer]; |
| } else { |
| [self _enableIdleSystemSleep]; |
| [self _enableIdleDisplaySleep]; |
| [self _disableTickleTimer]; |
| } |
| #endif |
| } |
| |
| // MARK: - |
| // MARK: Window callback |
| |
| - (void)_requestExit |
| { |
| if (_mediaElement) |
| _mediaElement->exitFullscreen(); |
| _forceDisableAnimation = NO; |
| } |
| |
| - (void)requestExitFullscreenWithAnimation:(BOOL)animation |
| { |
| if (_isEndingFullscreen) |
| return; |
| |
| _forceDisableAnimation = !animation; |
| [self performSelector:@selector(_requestExit) withObject:nil afterDelay:0]; |
| |
| } |
| |
| - (void)requestExitFullscreen |
| { |
| [self requestExitFullscreenWithAnimation:YES]; |
| } |
| |
| - (void)fadeHUDIn |
| { |
| [_hudController fadeWindowIn]; |
| } |
| |
| // MARK: - |
| // MARK: QTMovie callbacks |
| |
| - (void)rateChanged:(NSNotification *)unusedNotification |
| { |
| UNUSED_PARAM(unusedNotification); |
| [_hudController updateRate]; |
| [self updatePowerAssertions]; |
| } |
| |
| @end |
| |
| @implementation WebVideoFullscreenWindow |
| |
| - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag |
| { |
| UNUSED_PARAM(aStyle); |
| self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:flag]; |
| if (!self) |
| return nil; |
| [self setOpaque:NO]; |
| [self setBackgroundColor:[NSColor clearColor]]; |
| [self setIgnoresMouseEvents:NO]; |
| [self setAcceptsMouseMovedEvents:YES]; |
| return self; |
| } |
| |
| - (void)dealloc |
| { |
| ASSERT(!_fullscreenAnimation); |
| [super dealloc]; |
| } |
| |
| - (BOOL)resignFirstResponder |
| { |
| return NO; |
| } |
| |
| - (BOOL)canBecomeKeyWindow |
| { |
| return NO; |
| } |
| |
| - (void)mouseDown:(NSEvent *)theEvent |
| { |
| UNUSED_PARAM(theEvent); |
| } |
| |
| - (void)cancelOperation:(id)sender |
| { |
| UNUSED_PARAM(sender); |
| [[self windowController] requestExitFullscreen]; |
| } |
| |
| - (void)animatedResizeDidEnd |
| { |
| // Call our windowController. |
| if (_controllerActionOnAnimationEnd) |
| [[self windowController] performSelector:_controllerActionOnAnimationEnd]; |
| _controllerActionOnAnimationEnd = NULL; |
| } |
| |
| // |
| // This function will animate a change of frame rectangle |
| // We support queuing animation, that means that we'll correctly |
| // interrupt the running animation, and queue the next one. |
| // |
| - (void)animateFromRect:(NSRect)startRect toRect:(NSRect)endRect withSubAnimation:(NSAnimation *)subAnimation controllerAction:(SEL)controllerAction |
| { |
| _controllerActionOnAnimationEnd = controllerAction; |
| |
| BOOL wasAnimating = NO; |
| if (_fullscreenAnimation) { |
| wasAnimating = YES; |
| |
| // Interrupt any running animation. |
| [_fullscreenAnimation stopAnimation]; |
| |
| // Save the current rect to ensure a smooth transition. |
| startRect = [_fullscreenAnimation currentFrame]; |
| [_fullscreenAnimation release]; |
| _fullscreenAnimation = nil; |
| } |
| |
| if (NSIsEmptyRect(startRect) || NSIsEmptyRect(endRect)) { |
| // Fakely end the subanimation. |
| [subAnimation setCurrentProgress:1.0]; |
| // And remove the weak link to the window. |
| [subAnimation stopAnimation]; |
| |
| [self setFrame:endRect display:NO]; |
| [self makeKeyAndOrderFront:self]; |
| [self animatedResizeDidEnd]; |
| return; |
| } |
| |
| if (!wasAnimating) { |
| // We'll downscale the window during the animation based on the higher resolution rect |
| BOOL higherResolutionIsEndRect = startRect.size.width < endRect.size.width && startRect.size.height < endRect.size.height; |
| [self setFrame:higherResolutionIsEndRect ? endRect : startRect display:NO]; |
| } |
| |
| ASSERT(!_fullscreenAnimation); |
| _fullscreenAnimation = [[WebWindowScaleAnimation alloc] initWithHintedDuration:0.2 window:self initalFrame:startRect finalFrame:endRect]; |
| [_fullscreenAnimation setSubAnimation:subAnimation]; |
| [_fullscreenAnimation setDelegate:self]; |
| |
| // Make sure the animation has scaled the window before showing it. |
| [_fullscreenAnimation setCurrentProgress:0]; |
| [self makeKeyAndOrderFront:self]; |
| |
| [_fullscreenAnimation startAnimation]; |
| } |
| |
| - (void)animationDidEnd:(NSAnimation *)animation |
| { |
| #if !defined(BUILDING_ON_TIGER) // Animations are never threaded on Tiger. |
| if (![NSThread isMainThread]) { |
| [self performSelectorOnMainThread:@selector(animationDidEnd:) withObject:animation waitUntilDone:NO]; |
| return; |
| } |
| #endif |
| if (animation != _fullscreenAnimation) |
| return; |
| |
| // The animation is not really over and was interrupted |
| // Don't send completion events. |
| if ([animation currentProgress] < 1.0) |
| return; |
| |
| // Ensure that animation (and subanimation) don't keep |
| // the weak reference to the window ivar that may be destroyed from |
| // now on. |
| [_fullscreenAnimation setWindow:nil]; |
| |
| [_fullscreenAnimation autorelease]; |
| _fullscreenAnimation = nil; |
| |
| [self animatedResizeDidEnd]; |
| } |
| |
| - (void)mouseMoved:(NSEvent *)theEvent |
| { |
| [[self windowController] fadeHUDIn]; |
| } |
| |
| @end |
| |
| #endif /* ENABLE(VIDEO) */ |