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