WebKit/mac/WebView/WebVideoFullscreenHUDWindowController.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'' AND ANY
       
    14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
       
    20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    23  */
       
    24 
       
    25 #if ENABLE(VIDEO)
       
    26 
       
    27 #import "WebVideoFullscreenHUDWindowController.h"
       
    28 
       
    29 #import "WebKitSystemInterface.h"
       
    30 #import "WebTypesInternal.h"
       
    31 #import <JavaScriptCore/RetainPtr.h>
       
    32 #import <JavaScriptCore/UnusedParam.h>
       
    33 #import <WebCore/HTMLMediaElement.h>
       
    34 
       
    35 using namespace WebCore;
       
    36 using namespace std;
       
    37 
       
    38 static inline CGFloat webkit_CGFloor(CGFloat value)
       
    39 {
       
    40     if (sizeof(value) == sizeof(float))
       
    41         return floorf(value);
       
    42     return floor(value);
       
    43 }
       
    44 
       
    45 #define HAVE_MEDIA_CONTROL (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
       
    46 
       
    47 @interface WebVideoFullscreenHUDWindowController (Private) <NSWindowDelegate>
       
    48 
       
    49 - (void)updateTime;
       
    50 - (void)timelinePositionChanged:(id)sender;
       
    51 - (float)currentTime;
       
    52 - (void)setCurrentTime:(float)currentTime;
       
    53 - (double)duration;
       
    54 
       
    55 - (void)volumeChanged:(id)sender;
       
    56 - (double)maxVolume;
       
    57 - (double)volume;
       
    58 - (void)setVolume:(double)volume;
       
    59 - (void)decrementVolume;
       
    60 - (void)incrementVolume;
       
    61 
       
    62 - (void)updatePlayButton;
       
    63 - (void)togglePlaying:(id)sender;
       
    64 - (BOOL)playing;
       
    65 - (void)setPlaying:(BOOL)playing;
       
    66 
       
    67 - (void)rewind:(id)sender;
       
    68 - (void)fastForward:(id)sender;
       
    69 
       
    70 - (NSString *)remainingTimeText;
       
    71 - (NSString *)elapsedTimeText;
       
    72 
       
    73 - (void)exitFullscreen:(id)sender;
       
    74 @end
       
    75 
       
    76 @interface WebVideoFullscreenHUDWindow : NSWindow
       
    77 @end
       
    78 
       
    79 @implementation WebVideoFullscreenHUDWindow
       
    80 
       
    81 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
       
    82 {
       
    83     UNUSED_PARAM(aStyle);
       
    84     self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:flag];
       
    85     if (!self)
       
    86         return nil;
       
    87 
       
    88     [self setOpaque:NO];
       
    89     [self setBackgroundColor:[NSColor clearColor]];
       
    90     [self setLevel:NSPopUpMenuWindowLevel];
       
    91     [self setAcceptsMouseMovedEvents:YES];
       
    92     [self setIgnoresMouseEvents:NO];
       
    93     [self setMovableByWindowBackground:YES];
       
    94     [self setHidesOnDeactivate:YES];
       
    95 
       
    96     return self;
       
    97 }
       
    98 
       
    99 - (BOOL)canBecomeKeyWindow
       
   100 {
       
   101     return YES;
       
   102 }
       
   103 
       
   104 - (void)cancelOperation:(id)sender
       
   105 {
       
   106     [[self windowController] exitFullscreen:self];
       
   107 }
       
   108 
       
   109 - (void)center
       
   110 {
       
   111     NSRect hudFrame = [self frame];
       
   112     NSRect screenFrame = [[NSScreen mainScreen] frame];
       
   113     [self setFrameTopLeftPoint:NSMakePoint(screenFrame.origin.x + (screenFrame.size.width - hudFrame.size.width) / 2,
       
   114                                            screenFrame.origin.y + (screenFrame.size.height - hudFrame.size.height) / 6)];
       
   115 }
       
   116 
       
   117 - (void)keyDown:(NSEvent *)event
       
   118 {
       
   119     [super keyDown:event];
       
   120     [[self windowController] fadeWindowIn];
       
   121 }
       
   122 
       
   123 - (BOOL)resignFirstResponder
       
   124 {
       
   125     return NO;
       
   126 }
       
   127 
       
   128 - (BOOL)performKeyEquivalent:(NSEvent *)event
       
   129 {
       
   130     // Block all command key events while the fullscreen window is up.
       
   131     if ([event type] != NSKeyDown)
       
   132         return NO;
       
   133     
       
   134     if (!([event modifierFlags] & NSCommandKeyMask))
       
   135         return NO;
       
   136     
       
   137     return YES;
       
   138 }
       
   139 
       
   140 @end
       
   141 
       
   142 static const CGFloat windowHeight = 59;
       
   143 static const CGFloat windowWidth = 438;
       
   144 
       
   145 static const NSTimeInterval HUDWindowFadeOutDelay = 3;
       
   146 
       
   147 @implementation WebVideoFullscreenHUDWindowController
       
   148 
       
   149 - (id)init
       
   150 {
       
   151     NSWindow *window = [[WebVideoFullscreenHUDWindow alloc] initWithContentRect:NSMakeRect(0, 0, windowWidth, windowHeight)
       
   152                             styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
       
   153     self = [super initWithWindow:window];
       
   154     [window setDelegate:self];
       
   155     [window release];
       
   156     if (!self)
       
   157         return nil;
       
   158     [self windowDidLoad];
       
   159     return self;
       
   160 }
       
   161 
       
   162 - (void)dealloc
       
   163 {
       
   164     ASSERT(!_timelineUpdateTimer);
       
   165 #if !defined(BUILDING_ON_TIGER)
       
   166     ASSERT(!_area);
       
   167 #endif
       
   168     ASSERT(!_isScrubbing);
       
   169     [_timeline release];
       
   170     [_remainingTimeText release];
       
   171     [_elapsedTimeText release];
       
   172     [_volumeSlider release];
       
   173     [_playButton release];
       
   174     [super dealloc];
       
   175 }
       
   176 
       
   177 #if !defined(BUILDING_ON_TIGER)
       
   178 - (void)setArea:(NSTrackingArea *)area
       
   179 {
       
   180     if (area == _area)
       
   181         return;
       
   182     [_area release];
       
   183     _area = [area retain];
       
   184 }
       
   185 #endif
       
   186 
       
   187 - (void)keyDown:(NSEvent *)event
       
   188 {
       
   189     NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers];
       
   190     if ([charactersIgnoringModifiers length] == 1) {
       
   191         switch ([charactersIgnoringModifiers characterAtIndex:0]) {
       
   192             case ' ':
       
   193                 [self togglePlaying:nil];
       
   194                 return;
       
   195             case NSUpArrowFunctionKey:
       
   196                 if ([event modifierFlags] & NSAlternateKeyMask)
       
   197                     [self setVolume:[self maxVolume]];
       
   198                 else
       
   199                     [self incrementVolume];
       
   200                 return;
       
   201             case NSDownArrowFunctionKey:
       
   202                 if ([event modifierFlags] & NSAlternateKeyMask)
       
   203                     [self setVolume:0];
       
   204                 else
       
   205                     [self decrementVolume];
       
   206                 return;
       
   207             default:
       
   208                 break;
       
   209         }
       
   210     }
       
   211 
       
   212     [super keyDown:event];
       
   213 }
       
   214 
       
   215 - (id <WebVideoFullscreenHUDWindowControllerDelegate>)delegate
       
   216 {
       
   217     return _delegate;
       
   218 }
       
   219 
       
   220 - (void)setDelegate:(id <WebVideoFullscreenHUDWindowControllerDelegate>)delegate
       
   221 {
       
   222     _delegate = delegate;
       
   223 }
       
   224 
       
   225 - (void)scheduleTimeUpdate
       
   226 {
       
   227     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(unscheduleTimeUpdate) object:self];
       
   228 
       
   229     // First, update right away, then schedule future update
       
   230     [self updateTime];
       
   231     [self updatePlayButton];
       
   232 
       
   233     [_timelineUpdateTimer invalidate];
       
   234     [_timelineUpdateTimer release];
       
   235 
       
   236     // Note that this creates a retain cycle between the window and us.
       
   237     _timelineUpdateTimer = [[NSTimer timerWithTimeInterval:0.25 target:self selector:@selector(updateTime) userInfo:nil repeats:YES] retain];
       
   238 #if defined(BUILDING_ON_TIGER)
       
   239     [[NSRunLoop currentRunLoop] addTimer:_timelineUpdateTimer forMode:(NSString *)kCFRunLoopCommonModes];
       
   240 #else
       
   241     [[NSRunLoop currentRunLoop] addTimer:_timelineUpdateTimer forMode:NSRunLoopCommonModes];
       
   242 #endif
       
   243 }
       
   244 
       
   245 - (void)unscheduleTimeUpdate
       
   246 {
       
   247     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(unscheduleTimeUpdate) object:nil];
       
   248 
       
   249     [_timelineUpdateTimer invalidate];
       
   250     [_timelineUpdateTimer release];
       
   251     _timelineUpdateTimer = nil;
       
   252 }
       
   253 
       
   254 - (void)fadeWindowIn
       
   255 {
       
   256     NSWindow *window = [self window];
       
   257     if (![window isVisible])
       
   258         [window setAlphaValue:0];
       
   259 
       
   260     [window makeKeyAndOrderFront:self];
       
   261 #if defined(BUILDING_ON_TIGER)
       
   262     [window setAlphaValue:1];
       
   263 #else
       
   264     [[window animator] setAlphaValue:1];
       
   265 #endif
       
   266     [self scheduleTimeUpdate];
       
   267 
       
   268     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(fadeWindowOut) object:nil];
       
   269     if (!_mouseIsInHUD && [self playing])   // Don't fade out when paused.
       
   270         [self performSelector:@selector(fadeWindowOut) withObject:nil afterDelay:HUDWindowFadeOutDelay];
       
   271 }
       
   272 
       
   273 - (void)fadeWindowOut
       
   274 {
       
   275     [NSCursor setHiddenUntilMouseMoves:YES];
       
   276 #if defined(BUILDING_ON_TIGER)
       
   277     [[self window] setAlphaValue:0];
       
   278 #else
       
   279     [[[self window] animator] setAlphaValue:0];
       
   280 #endif
       
   281     [self performSelector:@selector(unscheduleTimeUpdate) withObject:nil afterDelay:1];
       
   282 }
       
   283 
       
   284 - (void)closeWindow
       
   285 {
       
   286     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(fadeWindowOut) object:nil];
       
   287     [self unscheduleTimeUpdate];
       
   288     NSWindow *window = [self window];
       
   289 #if !defined(BUILDING_ON_TIGER)
       
   290     [[window contentView] removeTrackingArea:_area];
       
   291     [self setArea:nil];
       
   292 #endif
       
   293     [window close];
       
   294     [window setDelegate:nil];
       
   295     [self setWindow:nil];
       
   296 }
       
   297 
       
   298 #ifndef HAVE_MEDIA_CONTROL
       
   299 enum {
       
   300     WKMediaUIControlPlayPauseButton,
       
   301     WKMediaUIControlRewindButton,
       
   302     WKMediaUIControlFastForwardButton,
       
   303     WKMediaUIControlExitFullscreenButton,
       
   304     WKMediaUIControlVolumeDownButton,
       
   305     WKMediaUIControlSlider,
       
   306     WKMediaUIControlVolumeUpButton,
       
   307     WKMediaUIControlTimeline
       
   308 };
       
   309 #endif
       
   310 
       
   311 static NSControl *createControlWithMediaUIControlType(int controlType, NSRect frame)
       
   312 {
       
   313 #ifdef HAVE_MEDIA_CONTROL
       
   314     NSControl *control = WKCreateMediaUIControl(controlType);
       
   315     [control setFrame:frame];
       
   316     return control;
       
   317 #else
       
   318     if (controlType == WKMediaUIControlSlider)
       
   319         return [[NSSlider alloc] initWithFrame:frame];
       
   320     return [[NSControl alloc] initWithFrame:frame];
       
   321 #endif
       
   322 }
       
   323 
       
   324 static NSTextField *createTimeTextField(NSRect frame)
       
   325 {
       
   326     NSTextField *textField = [[NSTextField alloc] initWithFrame:frame];
       
   327     [textField setTextColor:[NSColor whiteColor]];
       
   328     [textField setBordered:NO];
       
   329     [textField setFont:[NSFont boldSystemFontOfSize:10]];
       
   330     [textField setDrawsBackground:NO];
       
   331     [textField setBezeled:NO];
       
   332     [textField setEditable:NO];
       
   333     [textField setSelectable:NO];
       
   334     return textField;
       
   335 }
       
   336 
       
   337 - (void)windowDidLoad
       
   338 {
       
   339     static const CGFloat horizontalMargin = 10;
       
   340     static const CGFloat playButtonWidth = 41;
       
   341     static const CGFloat playButtonHeight = 35;
       
   342     static const CGFloat playButtonTopMargin = 4;
       
   343     static const CGFloat volumeSliderWidth = 50;
       
   344     static const CGFloat volumeSliderHeight = 13;
       
   345     static const CGFloat volumeButtonWidth = 18;
       
   346     static const CGFloat volumeButtonHeight = 16;
       
   347     static const CGFloat volumeUpButtonLeftMargin = 4;
       
   348     static const CGFloat volumeControlsTopMargin = 13;
       
   349     static const CGFloat exitFullscreenButtonWidth = 25;
       
   350     static const CGFloat exitFullscreenButtonHeight = 21;
       
   351     static const CGFloat exitFullscreenButtonTopMargin = 11;
       
   352     static const CGFloat timelineWidth = 315;
       
   353     static const CGFloat timelineHeight = 14;
       
   354     static const CGFloat timelineBottomMargin = 7;
       
   355     static const CGFloat timeTextFieldWidth = 54;
       
   356     static const CGFloat timeTextFieldHeight = 13;
       
   357     static const CGFloat timeTextFieldHorizontalMargin = 7;
       
   358 
       
   359     NSWindow *window = [self window];
       
   360     ASSERT(window);
       
   361 
       
   362 #ifdef HAVE_MEDIA_CONTROL
       
   363     NSView *background = WKCreateMediaUIBackgroundView();
       
   364 #else
       
   365     NSView *background = [[NSView alloc] init];
       
   366 #endif
       
   367     [window setContentView:background];
       
   368 #if !defined(BUILDING_ON_TIGER)
       
   369     _area = [[NSTrackingArea alloc] initWithRect:[background bounds] options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways owner:self userInfo:nil];
       
   370     [background addTrackingArea:_area];
       
   371 #endif
       
   372     [background release];    
       
   373 
       
   374     NSView *contentView = [window contentView];
       
   375 
       
   376     CGFloat center = webkit_CGFloor((windowWidth - playButtonWidth) / 2);
       
   377     _playButton = (NSButton *)createControlWithMediaUIControlType(WKMediaUIControlPlayPauseButton, NSMakeRect(center, windowHeight - playButtonTopMargin - playButtonHeight, playButtonWidth, playButtonHeight));
       
   378     ASSERT([_playButton isKindOfClass:[NSButton class]]);
       
   379     [_playButton setTarget:self];
       
   380     [_playButton setAction:@selector(togglePlaying:)];
       
   381     [contentView addSubview:_playButton];
       
   382 
       
   383     CGFloat closeToRight = windowWidth - horizontalMargin - exitFullscreenButtonWidth;
       
   384     NSControl *exitFullscreenButton = createControlWithMediaUIControlType(WKMediaUIControlExitFullscreenButton, NSMakeRect(closeToRight, windowHeight - exitFullscreenButtonTopMargin - exitFullscreenButtonHeight, exitFullscreenButtonWidth, exitFullscreenButtonHeight));
       
   385     [exitFullscreenButton setAction:@selector(exitFullscreen:)];
       
   386     [exitFullscreenButton setTarget:self];
       
   387     [contentView addSubview:exitFullscreenButton];
       
   388     [exitFullscreenButton release];
       
   389     
       
   390     CGFloat volumeControlsBottom = windowHeight - volumeControlsTopMargin - volumeButtonHeight;
       
   391     CGFloat left = horizontalMargin;
       
   392     NSControl *volumeDownButton = createControlWithMediaUIControlType(WKMediaUIControlVolumeDownButton, NSMakeRect(left, volumeControlsBottom, volumeButtonWidth, volumeButtonHeight));
       
   393     [contentView addSubview:volumeDownButton];
       
   394     [volumeDownButton setTarget:self];
       
   395     [volumeDownButton setAction:@selector(setVolumeToZero:)];
       
   396     [volumeDownButton release];
       
   397 
       
   398     left += volumeButtonWidth;
       
   399     _volumeSlider = createControlWithMediaUIControlType(WKMediaUIControlSlider, NSMakeRect(left, volumeControlsBottom + webkit_CGFloor((volumeButtonHeight - volumeSliderHeight) / 2), volumeSliderWidth, volumeSliderHeight));
       
   400     [_volumeSlider setValue:[NSNumber numberWithDouble:[self maxVolume]] forKey:@"maxValue"];
       
   401     [_volumeSlider setTarget:self];
       
   402     [_volumeSlider setAction:@selector(volumeChanged:)];
       
   403     [contentView addSubview:_volumeSlider];
       
   404 
       
   405     left += volumeSliderWidth + volumeUpButtonLeftMargin;
       
   406     NSControl *volumeUpButton = createControlWithMediaUIControlType(WKMediaUIControlVolumeUpButton, NSMakeRect(left, volumeControlsBottom, volumeButtonWidth, volumeButtonHeight));
       
   407     [volumeUpButton setTarget:self];
       
   408     [volumeUpButton setAction:@selector(setVolumeToMaximum:)];
       
   409     [contentView addSubview:volumeUpButton];
       
   410     [volumeUpButton release];
       
   411 
       
   412 #ifdef HAVE_MEDIA_CONTROL
       
   413     _timeline = WKCreateMediaUIControl(WKMediaUIControlTimeline);
       
   414 #else
       
   415     _timeline = [[NSSlider alloc] init];
       
   416 #endif
       
   417     [_timeline setTarget:self];
       
   418     [_timeline setAction:@selector(timelinePositionChanged:)];
       
   419     [_timeline setFrame:NSMakeRect(webkit_CGFloor((windowWidth - timelineWidth) / 2), timelineBottomMargin, timelineWidth, timelineHeight)];
       
   420     [contentView addSubview:_timeline];
       
   421 
       
   422     _elapsedTimeText = createTimeTextField(NSMakeRect(timeTextFieldHorizontalMargin, timelineBottomMargin, timeTextFieldWidth, timeTextFieldHeight));
       
   423     [_elapsedTimeText setAlignment:NSLeftTextAlignment];
       
   424     [contentView addSubview:_elapsedTimeText];
       
   425 
       
   426     _remainingTimeText = createTimeTextField(NSMakeRect(windowWidth - timeTextFieldHorizontalMargin - timeTextFieldWidth, timelineBottomMargin, timeTextFieldWidth, timeTextFieldHeight));
       
   427     [_remainingTimeText setAlignment:NSRightTextAlignment];
       
   428     [contentView addSubview:_remainingTimeText];
       
   429 
       
   430     [window recalculateKeyViewLoop];
       
   431     [window setInitialFirstResponder:_playButton];
       
   432     [window center];
       
   433 }
       
   434 
       
   435 - (void)updateVolume
       
   436 {
       
   437     [_volumeSlider setDoubleValue:[self volume]];
       
   438 }
       
   439 
       
   440 - (void)updateTime
       
   441 {
       
   442     [self updateVolume];
       
   443 
       
   444     [_timeline setFloatValue:[self currentTime]];
       
   445     [_timeline setValue:[NSNumber numberWithDouble:[self duration]] forKey:@"maxValue"];
       
   446 
       
   447     [_remainingTimeText setStringValue:[self remainingTimeText]];
       
   448     [_elapsedTimeText setStringValue:[self elapsedTimeText]];
       
   449 }
       
   450 
       
   451 - (void)endScrubbing
       
   452 {
       
   453     ASSERT(_isScrubbing);
       
   454     _isScrubbing = NO;
       
   455     if (HTMLMediaElement* mediaElement = [_delegate mediaElement])
       
   456         mediaElement->endScrubbing();
       
   457 }
       
   458 
       
   459 - (void)timelinePositionChanged:(id)sender
       
   460 {
       
   461     [self setCurrentTime:[_timeline floatValue]];
       
   462     if (!_isScrubbing) {
       
   463         _isScrubbing = YES;
       
   464         if (HTMLMediaElement* mediaElement = [_delegate mediaElement])
       
   465             mediaElement->beginScrubbing();
       
   466         static NSArray *endScrubbingModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, nil];
       
   467         // Schedule -endScrubbing for when leaving mouse tracking mode.
       
   468         [[NSRunLoop currentRunLoop] performSelector:@selector(endScrubbing) target:self argument:nil order:0 modes:endScrubbingModes];
       
   469     }
       
   470 }
       
   471 
       
   472 - (float)currentTime
       
   473 {
       
   474     return [_delegate mediaElement] ? [_delegate mediaElement]->currentTime() : 0;
       
   475 }
       
   476 
       
   477 - (void)setCurrentTime:(float)currentTime
       
   478 {
       
   479     if (![_delegate mediaElement])
       
   480         return;
       
   481     WebCore::ExceptionCode e;
       
   482     [_delegate mediaElement]->setCurrentTime(currentTime, e);
       
   483     [self updateTime];
       
   484 }
       
   485 
       
   486 - (double)duration
       
   487 {
       
   488     return [_delegate mediaElement] ? [_delegate mediaElement]->duration() : 0;
       
   489 }
       
   490 
       
   491 - (double)maxVolume
       
   492 {
       
   493     // Set the volume slider resolution
       
   494     return 100;
       
   495 }
       
   496 
       
   497 - (void)volumeChanged:(id)sender
       
   498 {
       
   499     [self setVolume:[_volumeSlider doubleValue]];
       
   500 }
       
   501 
       
   502 - (void)setVolumeToZero:(id)sender
       
   503 {
       
   504     [self setVolume:0];
       
   505 }
       
   506 
       
   507 - (void)setVolumeToMaximum:(id)sender
       
   508 {
       
   509     [self setVolume:[self maxVolume]];
       
   510 }
       
   511 
       
   512 - (void)decrementVolume
       
   513 {
       
   514     if (![_delegate mediaElement])
       
   515         return;
       
   516 
       
   517     double volume = [self volume] - 10;
       
   518     [self setVolume:max(volume, 0.)];
       
   519 }
       
   520 
       
   521 - (void)incrementVolume
       
   522 {
       
   523     if (![_delegate mediaElement])
       
   524         return;
       
   525 
       
   526     double volume = [self volume] + 10;
       
   527     [self setVolume:min(volume, [self maxVolume])];
       
   528 }
       
   529 
       
   530 - (double)volume
       
   531 {
       
   532     return [_delegate mediaElement] ? [_delegate mediaElement]->volume() * [self maxVolume] : 0;
       
   533 }
       
   534 
       
   535 - (void)setVolume:(double)volume
       
   536 {
       
   537     if (![_delegate mediaElement])
       
   538         return;
       
   539     WebCore::ExceptionCode e;
       
   540     if ([_delegate mediaElement]->muted())
       
   541         [_delegate mediaElement]->setMuted(false);
       
   542     [_delegate mediaElement]->setVolume(volume / [self maxVolume], e);
       
   543     [self updateVolume];
       
   544 }
       
   545 
       
   546 - (void)updatePlayButton
       
   547 {
       
   548     [_playButton setIntValue:[self playing]];
       
   549 }
       
   550 
       
   551 - (void)updateRate
       
   552 {
       
   553     BOOL playing = [self playing];
       
   554 
       
   555     // Keep the HUD visible when paused.
       
   556     if (!playing)
       
   557         [self fadeWindowIn];
       
   558     else if (!_mouseIsInHUD) {
       
   559         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(fadeWindowOut) object:nil];
       
   560         [self performSelector:@selector(fadeWindowOut) withObject:nil afterDelay:HUDWindowFadeOutDelay];
       
   561     }
       
   562     [self updatePlayButton];
       
   563 }
       
   564 
       
   565 - (void)togglePlaying:(id)sender
       
   566 {
       
   567     [self setPlaying:![self playing]];
       
   568 }
       
   569 
       
   570 - (BOOL)playing
       
   571 {
       
   572     HTMLMediaElement* mediaElement = [_delegate mediaElement];
       
   573     if (!mediaElement)
       
   574         return NO;
       
   575 
       
   576     return !mediaElement->canPlay();
       
   577 }
       
   578 
       
   579 - (void)setPlaying:(BOOL)playing
       
   580 {
       
   581     HTMLMediaElement* mediaElement = [_delegate mediaElement];
       
   582 
       
   583     if (!mediaElement)
       
   584         return;
       
   585 
       
   586     if (playing)
       
   587         mediaElement->play(mediaElement->processingUserGesture());
       
   588     else
       
   589         mediaElement->pause(mediaElement->processingUserGesture());
       
   590 }
       
   591 
       
   592 static NSString *timeToString(double time)
       
   593 {
       
   594     ASSERT_ARG(time, time >= 0);
       
   595 
       
   596     if (!isfinite(time))
       
   597         time = 0;
       
   598 
       
   599     int seconds = fabs(time); 
       
   600     int hours = seconds / (60 * 60);
       
   601     int minutes = (seconds / 60) % 60;
       
   602     seconds %= 60;
       
   603 
       
   604     if (hours)
       
   605         return [NSString stringWithFormat:@"%d:%02d:%02d", hours, minutes, seconds];
       
   606 
       
   607     return [NSString stringWithFormat:@"%02d:%02d", minutes, seconds];    
       
   608 }
       
   609 
       
   610 - (NSString *)remainingTimeText
       
   611 {
       
   612     HTMLMediaElement* mediaElement = [_delegate mediaElement];
       
   613     if (!mediaElement)
       
   614         return @"";
       
   615 
       
   616     return [@"-" stringByAppendingString:timeToString(mediaElement->duration() - mediaElement->currentTime())];
       
   617 }
       
   618 
       
   619 - (NSString *)elapsedTimeText
       
   620 {
       
   621     if (![_delegate mediaElement])
       
   622         return @"";
       
   623 
       
   624     return timeToString([_delegate mediaElement]->currentTime());
       
   625 }
       
   626 
       
   627 #pragma mark NSResponder
       
   628 
       
   629 - (void)mouseEntered:(NSEvent *)theEvent
       
   630 {
       
   631     // Make sure the HUD won't be hidden from now
       
   632     _mouseIsInHUD = YES;
       
   633     [self fadeWindowIn];
       
   634 }
       
   635 
       
   636 - (void)mouseExited:(NSEvent *)theEvent
       
   637 {
       
   638     _mouseIsInHUD = NO;
       
   639     [self fadeWindowIn];
       
   640 }
       
   641 
       
   642 - (void)rewind:(id)sender
       
   643 {
       
   644     if (![_delegate mediaElement])
       
   645         return;
       
   646     [_delegate mediaElement]->rewind(30);
       
   647 }
       
   648 
       
   649 - (void)fastForward:(id)sender
       
   650 {
       
   651     if (![_delegate mediaElement])
       
   652         return;
       
   653 }
       
   654 
       
   655 - (void)exitFullscreen:(id)sender
       
   656 {
       
   657     if (_isEndingFullscreen)
       
   658         return;
       
   659     _isEndingFullscreen = YES;
       
   660     [_delegate requestExitFullscreen]; 
       
   661 }
       
   662 
       
   663 #pragma mark NSWindowDelegate
       
   664 
       
   665 - (void)windowDidExpose:(NSNotification *)notification
       
   666 {
       
   667     [self scheduleTimeUpdate];
       
   668 }
       
   669 
       
   670 - (void)windowDidClose:(NSNotification *)notification
       
   671 {
       
   672     [self unscheduleTimeUpdate];
       
   673 }
       
   674 
       
   675 @end
       
   676 
       
   677 #endif