WebKit/mac/WebView/WebVideoFullscreenController.mm
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2009 Apple Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  * 1. Redistributions of source code must retain the above copyright
       
     8  *    notice, this list of conditions and the following disclaimer.
       
     9  * 2. Redistributions in binary form must reproduce the above copyright
       
    10  *    notice, this list of conditions and the following disclaimer in the
       
    11  *    documentation and/or other materials provided with the distribution.
       
    12  *
       
    13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
       
    14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
       
    15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
       
    17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
       
    18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
       
    19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
       
    20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
       
    21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
       
    22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
       
    23  * THE POSSIBILITY OF SUCH DAMAGE.
       
    24  */
       
    25 
       
    26 #if ENABLE(VIDEO)
       
    27 
       
    28 #import "WebVideoFullscreenController.h"
       
    29 
       
    30 #import "WebTypesInternal.h"
       
    31 #import "WebVideoFullscreenHUDWindowController.h"
       
    32 #import "WebWindowAnimation.h"
       
    33 #import <IOKit/pwr_mgt/IOPMLib.h>
       
    34 #import <QTKit/QTKit.h>
       
    35 #import <WebCore/HTMLMediaElement.h>
       
    36 #import <WebCore/SoftLinking.h>
       
    37 #import <objc/objc-runtime.h>
       
    38 #import <wtf/UnusedParam.h>
       
    39 
       
    40 SOFT_LINK_FRAMEWORK(QTKit)
       
    41 SOFT_LINK_CLASS(QTKit, QTMovieLayer)
       
    42 
       
    43 SOFT_LINK_POINTER(QTKit, QTMovieRateDidChangeNotification, NSString *)
       
    44 
       
    45 #define QTMovieRateDidChangeNotification getQTMovieRateDidChangeNotification()
       
    46 
       
    47 @interface WebVideoFullscreenWindow : NSWindow
       
    48 #if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER)
       
    49 <NSAnimationDelegate>
       
    50 #endif
       
    51 {
       
    52     SEL _controllerActionOnAnimationEnd;
       
    53     WebWindowScaleAnimation *_fullscreenAnimation; // (retain)
       
    54 }
       
    55 - (void)animateFromRect:(NSRect)startRect toRect:(NSRect)endRect withSubAnimation:(NSAnimation *)subAnimation controllerAction:(SEL)controllerAction;
       
    56 @end
       
    57 
       
    58 @interface WebVideoFullscreenController(HUDWindowControllerDelegate) <WebVideoFullscreenHUDWindowControllerDelegate>
       
    59 - (void)requestExitFullscreenWithAnimation:(BOOL)animation;
       
    60 - (void)updateMenuAndDockForFullscreen;
       
    61 - (void)updatePowerAssertions;
       
    62 @end
       
    63 
       
    64 @interface NSWindow(IsOnActiveSpaceAdditionForTigerAndLeopard)
       
    65 - (BOOL)isOnActiveSpace;
       
    66 @end
       
    67 
       
    68 @implementation WebVideoFullscreenController
       
    69 - (id)init
       
    70 {
       
    71     // Do not defer window creation, to make sure -windowNumber is created (needed by WebWindowScaleAnimation).
       
    72     NSWindow *window = [[WebVideoFullscreenWindow alloc] initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
       
    73     self = [super initWithWindow:window];
       
    74     [window release];
       
    75     if (!self)
       
    76         return nil;
       
    77     [self windowDidLoad];
       
    78     return self;
       
    79     
       
    80 }
       
    81 - (void)dealloc
       
    82 {
       
    83     ASSERT(!_backgroundFullscreenWindow);
       
    84     ASSERT(!_fadeAnimation);
       
    85     [[NSNotificationCenter defaultCenter] removeObserver:self];
       
    86     [super dealloc];
       
    87 }
       
    88 
       
    89 - (WebVideoFullscreenWindow *)fullscreenWindow
       
    90 {
       
    91     return (WebVideoFullscreenWindow *)[super window];
       
    92 }
       
    93 
       
    94 - (void)windowDidLoad
       
    95 {
       
    96 #ifdef BUILDING_ON_TIGER
       
    97     // WebVideoFullscreenController is not supported on Tiger:
       
    98     ASSERT_NOT_REACHED();
       
    99 #else
       
   100     WebVideoFullscreenWindow *window = [self fullscreenWindow];
       
   101     QTMovieLayer *layer = [[getQTMovieLayerClass() alloc] init];
       
   102     [[window contentView] setLayer:layer];
       
   103     [[window contentView] setWantsLayer:YES];
       
   104     if (_mediaElement && _mediaElement->platformMedia().type == WebCore::PlatformMedia::QTMovieType)
       
   105         [layer setMovie:_mediaElement->platformMedia().media.qtMovie];
       
   106     [window setHasShadow:YES]; // This is nicer with a shadow.
       
   107     [window setLevel:NSPopUpMenuWindowLevel-1];
       
   108     [layer release];
       
   109     
       
   110     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidResignActive:) name:NSApplicationDidResignActiveNotification object:NSApp];
       
   111     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidChangeScreenParameters:) name:NSApplicationDidChangeScreenParametersNotification object:NSApp];
       
   112 #endif
       
   113 }
       
   114 
       
   115 - (WebCore::HTMLMediaElement*)mediaElement
       
   116 {
       
   117     return _mediaElement.get();
       
   118 }
       
   119 
       
   120 - (void)setMediaElement:(WebCore::HTMLMediaElement*)mediaElement
       
   121 {
       
   122 #ifdef BUILDING_ON_TIGER
       
   123     // WebVideoFullscreenController is not supported on Tiger:
       
   124     ASSERT_NOT_REACHED();
       
   125 #else
       
   126     _mediaElement = mediaElement;
       
   127     if ([self isWindowLoaded]) {
       
   128         QTMovie *movie = _mediaElement->platformMedia().type == WebCore::PlatformMedia::QTMovieType ? _mediaElement->platformMedia().media.qtMovie : 0;
       
   129         QTMovieLayer *movieLayer = (QTMovieLayer *)[[[self fullscreenWindow] contentView] layer];
       
   130 
       
   131         ASSERT(movieLayer && [movieLayer isKindOfClass:[getQTMovieLayerClass() class]]);
       
   132         ASSERT(movie);
       
   133         [movieLayer setMovie:movie];
       
   134         [[NSNotificationCenter defaultCenter] addObserver:self
       
   135                                                  selector:@selector(rateChanged:) 
       
   136                                                      name:QTMovieRateDidChangeNotification 
       
   137                                                    object:movie];
       
   138     }
       
   139 #endif
       
   140 }
       
   141 
       
   142 - (id <WebVideoFullscreenControllerDelegate>)delegate
       
   143 {
       
   144     return _delegate;
       
   145 }
       
   146 
       
   147 - (void)setDelegate:(id <WebVideoFullscreenControllerDelegate>)delegate
       
   148 {
       
   149     _delegate = delegate;
       
   150 }
       
   151 
       
   152 - (CGFloat)clearFadeAnimation
       
   153 {
       
   154     [_fadeAnimation stopAnimation];
       
   155     CGFloat previousAlpha = [_fadeAnimation currentAlpha];
       
   156     [_fadeAnimation setWindow:nil];
       
   157     [_fadeAnimation release];
       
   158     _fadeAnimation = nil;
       
   159     return previousAlpha;
       
   160 }
       
   161 
       
   162 - (void)windowDidExitFullscreen
       
   163 {
       
   164     [self clearFadeAnimation];
       
   165     [[self window] close];
       
   166     [self setWindow:nil];
       
   167     [self updateMenuAndDockForFullscreen];   
       
   168     [self updatePowerAssertions];
       
   169     [_hudController setDelegate:nil];
       
   170     [_hudController release];
       
   171     _hudController = nil;
       
   172     [_backgroundFullscreenWindow close];
       
   173     [_backgroundFullscreenWindow release];
       
   174     _backgroundFullscreenWindow = nil;
       
   175     
       
   176     [self autorelease]; // Associated -retain is in -exitFullscreen.
       
   177     _isEndingFullscreen = NO;
       
   178 }
       
   179 
       
   180 - (void)windowDidEnterFullscreen
       
   181 {
       
   182     [self clearFadeAnimation];
       
   183 
       
   184     ASSERT(!_hudController);
       
   185     _hudController = [[WebVideoFullscreenHUDWindowController alloc] init];
       
   186     [_hudController setDelegate:self];
       
   187 
       
   188     [self updateMenuAndDockForFullscreen];
       
   189     [self updatePowerAssertions];
       
   190     [NSCursor setHiddenUntilMouseMoves:YES];
       
   191     
       
   192     // Give the HUD keyboard focus initially
       
   193     [_hudController fadeWindowIn];
       
   194 }
       
   195 
       
   196 - (NSRect)mediaElementRect
       
   197 {
       
   198     return _mediaElement->screenRect();
       
   199 }
       
   200 
       
   201 - (void)applicationDidResignActive:(NSNotification*)notification
       
   202 {   
       
   203     // Check to see if the fullscreenWindow is on the active space; this function is available
       
   204     // on 10.6 and later, so default to YES if the function is not available:
       
   205     NSWindow* fullscreenWindow = [self fullscreenWindow];
       
   206     BOOL isOnActiveSpace = ([fullscreenWindow respondsToSelector:@selector(isOnActiveSpace)] ? [fullscreenWindow isOnActiveSpace] : YES);
       
   207 
       
   208     // Replicate the QuickTime Player (X) behavior when losing active application status:
       
   209     // Is the fullscreen screen the main screen? (Note: this covers the case where only a 
       
   210     // single screen is available.)  Is the fullscreen screen on the current space? IFF so, 
       
   211     // then exit fullscreen mode.    
       
   212     if ([fullscreenWindow screen] == [[NSScreen screens] objectAtIndex:0] && isOnActiveSpace)
       
   213          [self requestExitFullscreenWithAnimation:NO];
       
   214 }
       
   215          
       
   216          
       
   217 #pragma mark -
       
   218 #pragma mark Exposed Interface
       
   219 
       
   220 static void constrainFrameToRatioOfFrame(NSRect *frameToConstrain, const NSRect *frame)
       
   221 {
       
   222     // Keep a constrained aspect ratio for the destination window
       
   223     double originalRatio = frame->size.width / frame->size.height;
       
   224     double newRatio = frameToConstrain->size.width / frameToConstrain->size.height;
       
   225     if (newRatio > originalRatio) {
       
   226         double newWidth = originalRatio * frameToConstrain->size.height;
       
   227         double diff = frameToConstrain->size.width - newWidth;
       
   228         frameToConstrain->size.width = newWidth;
       
   229         frameToConstrain->origin.x += diff / 2;
       
   230     } else {
       
   231         double newHeight = frameToConstrain->size.width / originalRatio;
       
   232         double diff = frameToConstrain->size.height - newHeight;
       
   233         frameToConstrain->size.height = newHeight;
       
   234         frameToConstrain->origin.y += diff / 2;
       
   235     }    
       
   236 }
       
   237 
       
   238 static NSWindow *createBackgroundFullscreenWindow(NSRect frame, int level)
       
   239 {
       
   240     NSWindow *window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
       
   241     [window setOpaque:YES];
       
   242     [window setBackgroundColor:[NSColor blackColor]];
       
   243     [window setLevel:level];
       
   244     [window setHidesOnDeactivate:YES];
       
   245     [window setReleasedWhenClosed:NO];
       
   246     return window;
       
   247 }
       
   248 
       
   249 - (void)setupFadeAnimationIfNeededAndFadeIn:(BOOL)fadeIn
       
   250 {
       
   251     CGFloat initialAlpha = fadeIn ? 0 : 1;
       
   252     if (_fadeAnimation) {
       
   253         // Make sure we support queuing animation if the previous one isn't over yet
       
   254         initialAlpha = [self clearFadeAnimation];
       
   255     }
       
   256     if (!_forceDisableAnimation)
       
   257         _fadeAnimation = [[WebWindowFadeAnimation alloc] initWithDuration:0.2 window:_backgroundFullscreenWindow initialAlpha:initialAlpha finalAlpha:fadeIn ? 1 : 0];
       
   258 }
       
   259 
       
   260 - (void)enterFullscreen:(NSScreen *)screen
       
   261 {
       
   262     if (!screen)
       
   263         screen = [NSScreen mainScreen];
       
   264 
       
   265     NSRect frame = [self mediaElementRect];
       
   266     NSRect endFrame = [screen frame];
       
   267     constrainFrameToRatioOfFrame(&endFrame, &frame);
       
   268 
       
   269     // Create a black window if needed
       
   270     if (!_backgroundFullscreenWindow)
       
   271         _backgroundFullscreenWindow = createBackgroundFullscreenWindow([screen frame], [[self window] level]-1);
       
   272     else
       
   273         [_backgroundFullscreenWindow setFrame:[screen frame] display:NO];
       
   274 
       
   275     [self setupFadeAnimationIfNeededAndFadeIn:YES];
       
   276     if (_forceDisableAnimation) {
       
   277         // This will disable scale animation
       
   278         frame = NSZeroRect;
       
   279     }
       
   280     [[self fullscreenWindow] animateFromRect:frame toRect:endFrame withSubAnimation:_fadeAnimation controllerAction:@selector(windowDidEnterFullscreen)];
       
   281 
       
   282     [_backgroundFullscreenWindow orderWindow:NSWindowBelow relativeTo:[[self fullscreenWindow] windowNumber]];
       
   283 }
       
   284 
       
   285 - (void)exitFullscreen
       
   286 {
       
   287     if (_isEndingFullscreen)
       
   288         return;
       
   289     _isEndingFullscreen = YES;
       
   290     [_hudController closeWindow];
       
   291 
       
   292     NSRect endFrame = [self mediaElementRect];
       
   293 
       
   294     [self setupFadeAnimationIfNeededAndFadeIn:NO];
       
   295     if (_forceDisableAnimation) {
       
   296         // This will disable scale animation
       
   297         endFrame = NSZeroRect;
       
   298     }
       
   299     
       
   300     // We have to retain ourselves because we want to be alive for the end of the animation.
       
   301     // If our owner releases us we could crash if this is not the case.
       
   302     // Balanced in windowDidExitFullscreen
       
   303     [self retain];    
       
   304     
       
   305     [[self fullscreenWindow] animateFromRect:[[self window] frame] toRect:endFrame withSubAnimation:_fadeAnimation controllerAction:@selector(windowDidExitFullscreen)];
       
   306 }
       
   307 
       
   308 - (void)applicationDidChangeScreenParameters:(NSNotification*)notification
       
   309 {
       
   310     // The user may have changed the main screen by moving the menu bar, or they may have changed
       
   311     // the Dock's size or location, or they may have changed the fullscreen screen's dimensions.  
       
   312     // Update our presentation parameters, and ensure that the full screen window occupies the 
       
   313     // entire screen:
       
   314     [self updateMenuAndDockForFullscreen];
       
   315     [[self window] setFrame:[[[self window] screen] frame] display:YES];
       
   316 }
       
   317 
       
   318 - (void)updateMenuAndDockForFullscreen
       
   319 {
       
   320     // NSApplicationPresentationOptions is available on > 10.6 only:
       
   321 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
       
   322     NSApplicationPresentationOptions options = NSApplicationPresentationDefault;
       
   323     NSScreen* fullscreenScreen = [[self window] screen];
       
   324 
       
   325     if (!_isEndingFullscreen) {
       
   326         // Auto-hide the menu bar if the fullscreenScreen contains the menu bar:
       
   327         // NOTE: if the fullscreenScreen contains the menu bar but not the dock, we must still 
       
   328         // auto-hide the dock, or an exception will be thrown.
       
   329         if ([[NSScreen screens] objectAtIndex:0] == fullscreenScreen)
       
   330             options |= (NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock);
       
   331         // Check if the current screen contains the dock by comparing the screen's frame to its
       
   332         // visibleFrame; if a dock is present, the visibleFrame will differ.  If the current screen
       
   333         // contains the dock, hide it.
       
   334         else if (!NSEqualRects([fullscreenScreen frame], [fullscreenScreen visibleFrame]))
       
   335             options |= NSApplicationPresentationAutoHideDock;
       
   336     }
       
   337 
       
   338     if ([NSApp respondsToSelector:@selector(setPresentationOptions:)])
       
   339         [NSApp setPresentationOptions:options];
       
   340     else
       
   341 #endif
       
   342         SetSystemUIMode(_isEndingFullscreen ? kUIModeNormal : kUIModeAllHidden, 0);
       
   343 }
       
   344 
       
   345 #if !defined(BUILDING_ON_TIGER) // IOPMAssertionCreateWithName not defined on < 10.5
       
   346 - (void)_disableIdleDisplaySleep
       
   347 {
       
   348     if (_idleDisplaySleepAssertion == kIOPMNullAssertionID) 
       
   349 #if defined(BUILDING_ON_LEOPARD) // IOPMAssertionCreateWithName is not defined in the 10.5 SDK
       
   350         IOPMAssertionCreate(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, &_idleDisplaySleepAssertion);
       
   351 #else // IOPMAssertionCreate is depreciated in > 10.5
       
   352         IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, CFSTR("WebKit playing a video fullscreen."), &_idleDisplaySleepAssertion);
       
   353 #endif
       
   354 }
       
   355 
       
   356 - (void)_enableIdleDisplaySleep
       
   357 {
       
   358     if (_idleDisplaySleepAssertion != kIOPMNullAssertionID) {
       
   359         IOPMAssertionRelease(_idleDisplaySleepAssertion);
       
   360         _idleDisplaySleepAssertion = kIOPMNullAssertionID;
       
   361     }
       
   362 }
       
   363 
       
   364 - (void)_disableIdleSystemSleep
       
   365 {
       
   366     if (_idleSystemSleepAssertion == kIOPMNullAssertionID) 
       
   367 #if defined(BUILDING_ON_LEOPARD) // IOPMAssertionCreateWithName is not defined in the 10.5 SDK
       
   368         IOPMAssertionCreate(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, &_idleSystemSleepAssertion);
       
   369 #else // IOPMAssertionCreate is depreciated in > 10.5
       
   370     IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, CFSTR("WebKit playing a video fullscreen."), &_idleSystemSleepAssertion);
       
   371 #endif
       
   372 }
       
   373 
       
   374 - (void)_enableIdleSystemSleep
       
   375 {
       
   376     if (_idleSystemSleepAssertion != kIOPMNullAssertionID) {
       
   377         IOPMAssertionRelease(_idleSystemSleepAssertion);
       
   378         _idleSystemSleepAssertion = kIOPMNullAssertionID;
       
   379     }
       
   380 }
       
   381 #endif
       
   382 
       
   383 - (void)updatePowerAssertions
       
   384 {
       
   385 #if !defined(BUILDING_ON_TIGER) 
       
   386     float rate = 0;
       
   387     if (_mediaElement && _mediaElement->platformMedia().type == WebCore::PlatformMedia::QTMovieType)
       
   388         rate = [_mediaElement->platformMedia().media.qtMovie rate];
       
   389     
       
   390     if (rate && !_isEndingFullscreen) {
       
   391         [self _disableIdleSystemSleep];
       
   392         [self _disableIdleDisplaySleep];
       
   393     } else {
       
   394         [self _enableIdleSystemSleep];
       
   395         [self _enableIdleDisplaySleep];
       
   396     }
       
   397 #endif
       
   398 }
       
   399 
       
   400 #pragma mark -
       
   401 #pragma mark Window callback
       
   402 
       
   403 - (void)_requestExit
       
   404 {
       
   405     if (_mediaElement)
       
   406         _mediaElement->exitFullscreen();
       
   407     _forceDisableAnimation = NO;
       
   408 }
       
   409 
       
   410 - (void)requestExitFullscreenWithAnimation:(BOOL)animation
       
   411 {
       
   412     if (_isEndingFullscreen)
       
   413         return;
       
   414 
       
   415     _forceDisableAnimation = !animation;
       
   416     [self performSelector:@selector(_requestExit) withObject:nil afterDelay:0];
       
   417 
       
   418 }
       
   419 
       
   420 - (void)requestExitFullscreen
       
   421 {
       
   422     [self requestExitFullscreenWithAnimation:YES];
       
   423 }
       
   424 
       
   425 - (void)fadeHUDIn
       
   426 {
       
   427     [_hudController fadeWindowIn];
       
   428 }
       
   429 
       
   430 #pragma mark -
       
   431 #pragma mark QTMovie callbacks
       
   432 
       
   433 - (void)rateChanged:(NSNotification *)unusedNotification
       
   434 {
       
   435     UNUSED_PARAM(unusedNotification);
       
   436     [_hudController updateRate];
       
   437     [self updatePowerAssertions];
       
   438 }
       
   439 
       
   440 @end
       
   441 
       
   442 @implementation WebVideoFullscreenWindow
       
   443 
       
   444 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
       
   445 {
       
   446     UNUSED_PARAM(aStyle);
       
   447     self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:flag];
       
   448     if (!self)
       
   449         return nil;
       
   450     [self setOpaque:NO];
       
   451     [self setBackgroundColor:[NSColor clearColor]];
       
   452     [self setHidesOnDeactivate:YES];
       
   453     [self setIgnoresMouseEvents:NO];
       
   454     [self setAcceptsMouseMovedEvents:YES];
       
   455     return self;
       
   456 }
       
   457 
       
   458 - (void)dealloc
       
   459 {
       
   460     ASSERT(!_fullscreenAnimation);
       
   461     [super dealloc];
       
   462 }
       
   463 
       
   464 - (BOOL)resignFirstResponder
       
   465 {
       
   466     return NO;
       
   467 }
       
   468 
       
   469 - (BOOL)canBecomeKeyWindow
       
   470 {
       
   471     return NO;
       
   472 }
       
   473 
       
   474 - (void)mouseDown:(NSEvent *)theEvent
       
   475 {
       
   476     UNUSED_PARAM(theEvent);
       
   477 }
       
   478 
       
   479 - (void)cancelOperation:(id)sender
       
   480 {
       
   481     UNUSED_PARAM(sender);
       
   482     [[self windowController] requestExitFullscreen];
       
   483 }
       
   484 
       
   485 - (void)animatedResizeDidEnd
       
   486 {
       
   487     // Call our windowController.
       
   488     if (_controllerActionOnAnimationEnd)
       
   489         [[self windowController] performSelector:_controllerActionOnAnimationEnd];
       
   490     _controllerActionOnAnimationEnd = NULL;
       
   491 }
       
   492 
       
   493 //
       
   494 // This function will animate a change of frame rectangle
       
   495 // We support queuing animation, that means that we'll correctly
       
   496 // interrupt the running animation, and queue the next one.
       
   497 //
       
   498 - (void)animateFromRect:(NSRect)startRect toRect:(NSRect)endRect withSubAnimation:(NSAnimation *)subAnimation controllerAction:(SEL)controllerAction
       
   499 {
       
   500     _controllerActionOnAnimationEnd = controllerAction;
       
   501 
       
   502     BOOL wasAnimating = NO;
       
   503     if (_fullscreenAnimation) {
       
   504         wasAnimating = YES;
       
   505 
       
   506         // Interrupt any running animation.
       
   507         [_fullscreenAnimation stopAnimation];
       
   508 
       
   509         // Save the current rect to ensure a smooth transition.
       
   510         startRect = [_fullscreenAnimation currentFrame];
       
   511         [_fullscreenAnimation release];
       
   512         _fullscreenAnimation = nil;
       
   513     }
       
   514     
       
   515     if (NSIsEmptyRect(startRect) || NSIsEmptyRect(endRect)) {
       
   516         // Fakely end the subanimation.
       
   517         [subAnimation setCurrentProgress:1.0];
       
   518         // And remove the weak link to the window.
       
   519         [subAnimation stopAnimation];
       
   520 
       
   521         [self setFrame:endRect display:NO];
       
   522         [self makeKeyAndOrderFront:self];
       
   523         [self animatedResizeDidEnd];
       
   524         return;
       
   525     }
       
   526 
       
   527     if (!wasAnimating) {
       
   528         // We'll downscale the window during the animation based on the higher resolution rect
       
   529         BOOL higherResolutionIsEndRect = startRect.size.width < endRect.size.width && startRect.size.height < endRect.size.height;
       
   530         [self setFrame:higherResolutionIsEndRect ? endRect : startRect display:NO];        
       
   531     }
       
   532     
       
   533     ASSERT(!_fullscreenAnimation);
       
   534     _fullscreenAnimation = [[WebWindowScaleAnimation alloc] initWithHintedDuration:0.2 window:self initalFrame:startRect finalFrame:endRect];
       
   535     [_fullscreenAnimation setSubAnimation:subAnimation];
       
   536     [_fullscreenAnimation setDelegate:self];
       
   537     
       
   538     // Make sure the animation has scaled the window before showing it.
       
   539     [_fullscreenAnimation setCurrentProgress:0];
       
   540     [self makeKeyAndOrderFront:self];
       
   541 
       
   542     [_fullscreenAnimation startAnimation];
       
   543 }
       
   544 
       
   545 - (void)animationDidEnd:(NSAnimation *)animation
       
   546 {
       
   547 #if !defined(BUILDING_ON_TIGER) // Animations are never threaded on Tiger.
       
   548     if (![NSThread isMainThread]) {
       
   549         [self performSelectorOnMainThread:@selector(animationDidEnd:) withObject:animation waitUntilDone:NO];
       
   550         return;
       
   551     }
       
   552 #endif
       
   553     if (animation != _fullscreenAnimation)
       
   554         return;
       
   555 
       
   556     // The animation is not really over and was interrupted
       
   557     // Don't send completion events.
       
   558     if ([animation currentProgress] < 1.0)
       
   559         return;
       
   560 
       
   561     // Ensure that animation (and subanimation) don't keep
       
   562     // the weak reference to the window ivar that may be destroyed from
       
   563     // now on.
       
   564     [_fullscreenAnimation setWindow:nil];
       
   565 
       
   566     [_fullscreenAnimation autorelease];
       
   567     _fullscreenAnimation = nil;
       
   568 
       
   569     [self animatedResizeDidEnd];
       
   570 }
       
   571 
       
   572 - (void)mouseMoved:(NSEvent *)theEvent
       
   573 {
       
   574     [[self windowController] fadeHUDIn];
       
   575 }
       
   576 
       
   577 @end
       
   578 
       
   579 #endif /* ENABLE(VIDEO) */