]> git.sesse.net Git - vlc/blobdiff - modules/gui/macosx/misc.m
enable the macosx GUI to handle negative stop-time
[vlc] / modules / gui / macosx / misc.m
index d1211c9a816c82cdea0699aa7480a03be9e58d70..b20ab77fff7d42f949b825ae1c0d0185e5438308 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * misc.m: code not specific to vlc
  *****************************************************************************
- * Copyright (C) 2003-2011 VLC authors and VideoLAN
+ * Copyright (C) 2003-2014 VLC authors and VideoLAN
  * $Id$
  *
  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-#import <Cocoa/Cocoa.h>
-#import <Carbon/Carbon.h>
-
 #import "CompatibilityFixes.h"
+#import "misc.h"
 #import "intf.h"                                          /* VLCApplication */
 #import "MainWindow.h"
-#import "misc.h"
-#import "playlist.h"
+#import "ControlsBar.h"
 #import "controls.h"
-#import <vlc_url.h>
+#import "CoreInteraction.h"
+#import <CoreAudio/CoreAudio.h>
+#import <vlc_keys.h>
+
+
+/*****************************************************************************
+ * NSSound (VLCAdditions)
+ *
+ * added code to change the system volume, needed for the apple remote code
+ * this is simplified code, which won't let you set the exact volume
+ * (that's what the audio output is for after all), but just the system volume
+ * in steps of 1/16 (matching the default AR or volume key implementation).
+ *****************************************************************************/
+
+@implementation NSSound (VLCAdditions)
+
++ (float)systemVolumeForChannel:(int)channel
+{
+    AudioDeviceID i_device;
+    float f_volume;
+    OSStatus err;
+    UInt32 i_size;
+
+    i_size = sizeof( i_device );
+    AudioObjectPropertyAddress deviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
+    err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &deviceAddress, 0, NULL, &i_size, &i_device );
+    if (err != noErr) {
+        msg_Warn( VLCIntf, "couldn't get main audio output device" );
+        return .0;
+    }
+
+    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, channel };
+    i_size = sizeof( f_volume );
+    err = AudioObjectGetPropertyData(i_device, &propertyAddress, 0, NULL, &i_size, &f_volume);
+    if (err != noErr) {
+        msg_Warn( VLCIntf, "couldn't get volume value" );
+        return .0;
+    }
+
+    return f_volume;
+}
+
++ (bool)setSystemVolume:(float)f_volume forChannel:(int)i_channel
+{
+    /* the following code will fail on S/PDIF devices. there is an easy work-around, but we'd like to match the OS behavior */
+
+    AudioDeviceID i_device;
+    OSStatus err;
+    UInt32 i_size;
+    Boolean b_writeable;
+
+    i_size = sizeof( i_device );
+    AudioObjectPropertyAddress deviceAddress = { kAudioHardwarePropertyDefaultOutputDevice, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
+    err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &deviceAddress, 0, NULL, &i_size, &i_device );
+    if (err != noErr) {
+        msg_Warn( VLCIntf, "couldn't get main audio output device" );
+        return NO;
+    }
+
+    AudioObjectPropertyAddress propertyAddress = { kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, i_channel };
+    i_size = sizeof( f_volume );
+    err = AudioObjectIsPropertySettable( i_device, &propertyAddress, &b_writeable );
+    if (err != noErr || !b_writeable ) {
+        msg_Warn( VLCIntf, "we can't set the main audio devices' volume" );
+        return NO;
+    }
+    err = AudioObjectSetPropertyData(i_device, &propertyAddress, 0, NULL, i_size, &f_volume);
+
+    return YES;
+}
+
++ (void)increaseSystemVolume
+{
+    float f_volume = [NSSound systemVolumeForChannel:1]; // we trust that mono is always available and that all channels got the same volume
+    f_volume += .0625; // 1/16 to match the OS
+    bool b_returned = YES;
+
+    /* since core audio doesn't provide a reasonable way to see how many channels we got, let's see how long we can do this */
+    for (NSUInteger x = 1; b_returned ; x++)
+        b_returned = [NSSound setSystemVolume: f_volume forChannel:x];
+}
+
++ (void)decreaseSystemVolume
+{
+    float f_volume = [NSSound systemVolumeForChannel:1]; // we trust that mono is always available and that all channels got the same volume
+    f_volume -= .0625; // 1/16 to match the OS
+    bool b_returned = YES;
+
+    /* since core audio doesn't provide a reasonable way to see how many channels we got, let's see how long we can do this */
+    for (NSUInteger x = 1; b_returned ; x++)
+        b_returned = [NSSound setSystemVolume: f_volume forChannel:x];
+}
+
+@end
 
 /*****************************************************************************
  * NSAnimation (VLCAdditions)
@@ -76,28 +166,57 @@ static NSMapTable *VLCAdditions_userInfo = NULL;
 
 static NSMutableArray *blackoutWindows = NULL;
 
+static bool b_old_spaces_style = YES;
+
 + (void)load
 {
     /* init our fake object attribute */
     blackoutWindows = [[NSMutableArray alloc] initWithCapacity:1];
+
+    if (OSX_MAVERICKS || OSX_YOSEMITE) {
+        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] init];
+        [userDefaults addSuiteNamed:@"com.apple.spaces"];
+        /* this is system settings -> mission control -> monitors using different spaces */
+        NSNumber *o_span_displays = [userDefaults objectForKey:@"spans-displays"];
+
+        b_old_spaces_style = [o_span_displays boolValue];
+        [userDefaults release];
+    }
 }
 
 + (NSScreen *)screenWithDisplayID: (CGDirectDisplayID)displayID
 {
     NSUInteger count = [[NSScreen screens] count];
 
-    for( NSUInteger i = 0; i < count; i++ )
-    {
-        NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
-        if([screen displayID] == displayID)
+    for ( NSUInteger i = 0; i < count; i++ ) {
+        NSScreen *screen = [[NSScreen screens] objectAtIndex:i];
+        if ([screen displayID] == displayID)
             return screen;
     }
     return nil;
 }
 
-- (BOOL)isMainScreen
+- (BOOL)hasMenuBar
 {
-    return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
+    if (b_old_spaces_style)
+        return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
+    else
+        return YES;
+}
+
+- (BOOL)hasDock
+{
+    NSRect screen_frame = [self frame];
+    NSRect screen_visible_frame = [self visibleFrame];
+    CGFloat f_menu_bar_thickness = [self hasMenuBar] ? [[NSStatusBar systemStatusBar] thickness] : 0.0;
+
+    BOOL b_found_dock = NO;
+    if (screen_visible_frame.size.width < screen_frame.size.width)
+        b_found_dock = YES;
+    else if (screen_visible_frame.size.height + f_menu_bar_thickness < screen_frame.size.height)
+        b_found_dock = YES;
+
+    return b_found_dock;
 }
 
 - (BOOL)isScreen: (NSScreen*)screen
@@ -107,7 +226,7 @@ static NSMutableArray *blackoutWindows = NULL;
 
 - (CGDirectDisplayID)displayID
 {
-       return (CGDirectDisplayID)[[[self deviceDescription] objectForKey: @"NSScreenNumber"] intValue];
+    return (CGDirectDisplayID)[[[self deviceDescription] objectForKey: @"NSScreenNumber"] intValue];
 }
 
 - (void)blackoutOtherScreens
@@ -117,13 +236,12 @@ static NSMutableArray *blackoutWindows = NULL;
     [blackoutWindows removeAllObjects];
 
     NSUInteger screenCount = [[NSScreen screens] count];
-    for(NSUInteger i = 0; i < screenCount; i++)
-    {
-        NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
+    for (NSUInteger i = 0; i < screenCount; i++) {
+        NSScreen *screen = [[NSScreen screens] objectAtIndex:i];
         VLCWindow *blackoutWindow;
         NSRect screen_rect;
 
-        if([self isScreen: screen])
+        if ([self isScreen: screen])
             continue;
 
         screen_rect = [screen frame];
@@ -137,6 +255,7 @@ static NSMutableArray *blackoutWindows = NULL;
                 backing: NSBackingStoreBuffered defer: NO screen: screen];
         [blackoutWindow setBackgroundColor:[NSColor blackColor]];
         [blackoutWindow setLevel: NSFloatingWindowLevel]; /* Disappear when Expose is triggered */
+        [blackoutWindow setReleasedWhenClosed:NO]; // window is released when deleted from array above
 
         [blackoutWindow displayIfNeeded];
         [blackoutWindow orderFront: self animate: YES];
@@ -144,16 +263,7 @@ static NSMutableArray *blackoutWindows = NULL;
         [blackoutWindows addObject: blackoutWindow];
         [blackoutWindow release];
 
-        if( [screen isMainScreen ] )
-        {
-            if ([screen isMainScreen])
-            {
-                if (OSX_LEOPARD)
-                    SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
-                else
-                    [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
-            }
-        }
+        [screen setFullscreenPresentationOptions];
     }
 }
 
@@ -161,225 +271,78 @@ static NSMutableArray *blackoutWindows = NULL;
 {
     NSUInteger blackoutWindowCount = [blackoutWindows count];
 
-    for(NSUInteger i = 0; i < blackoutWindowCount; i++)
-    {
-        VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex: i];
+    for (NSUInteger i = 0; i < blackoutWindowCount; i++) {
+        VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex:i];
+        [[blackoutWindow screen] setNonFullscreenPresentationOptions];
         [blackoutWindow closeAndAnimate: YES];
     }
-
-    if (OSX_LEOPARD)
-        SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
-    else
-        [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
 }
 
-@end
-
-/*****************************************************************************
- * VLCWindow
- *
- *  Missing extension to NSWindow
- *****************************************************************************/
-
-@implementation VLCWindow
-- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
-    backing:(NSBackingStoreType)backingType defer:(BOOL)flag
+- (void)setFullscreenPresentationOptions
 {
-    self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
-    if( self )
-    {
-        b_isFullscreen = NO;
-        b_isset_canBecomeKeyWindow = NO;
-        /* we don't want this window to be restored on relaunch */
-        if (OSX_LION)
-            [self setRestorable:NO];
-    }
-    return self;
-}
-- (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
-{
-    b_isset_canBecomeKeyWindow = YES;
-    b_canBecomeKeyWindow = canBecomeKey;
+    NSApplicationPresentationOptions presentationOpts = [NSApp presentationOptions];
+    if ([self hasMenuBar])
+        presentationOpts |= NSApplicationPresentationAutoHideMenuBar;
+    if ([self hasMenuBar] || [self hasDock])
+        presentationOpts |= NSApplicationPresentationAutoHideDock;
+    [NSApp setPresentationOptions:presentationOpts];
 }
 
-- (BOOL)canBecomeKeyWindow
+- (void)setNonFullscreenPresentationOptions
 {
-    if(b_isset_canBecomeKeyWindow)
-        return b_canBecomeKeyWindow;
-
-    return [super canBecomeKeyWindow];
+    NSApplicationPresentationOptions presentationOpts = [NSApp presentationOptions];
+    if ([self hasMenuBar])
+        presentationOpts &= (~NSApplicationPresentationAutoHideMenuBar);
+    if ([self hasMenuBar] || [self hasDock])
+        presentationOpts &= (~NSApplicationPresentationAutoHideDock);
+    [NSApp setPresentationOptions:presentationOpts];
 }
 
-- (void)closeAndAnimate: (BOOL)animate
-{
-    NSInvocation *invoc;
-
-    if (!animate)
-    {
-        [super close];
-        return;
-    }
-
-    invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(close)]];
-    [invoc setTarget: self];
+@end
 
-    if (![self isVisible] || [self alphaValue] == 0.0)
-    {
-        [super close];
-        return;
-    }
+/*****************************************************************************
+ * VLCDragDropView
+ *****************************************************************************/
 
-    [self orderOut: self animate: YES callback: invoc];
-}
+@implementation VLCDropDisabledImageView
 
-- (void)orderOut: (id)sender animate: (BOOL)animate
+- (void)awakeFromNib
 {
-    NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(orderOut:)]];
-    [invoc setTarget: self];
-    [invoc setArgument: sender atIndex: 0];
-    [self orderOut: sender animate: animate callback: invoc];
+    [self unregisterDraggedTypes];
 }
 
-- (void)orderOut: (id)sender animate: (BOOL)animate callback:(NSInvocation *)callback
-{
-    NSViewAnimation *anim;
-    NSViewAnimation *current_anim;
-    NSMutableDictionary *dict;
-
-    if (!animate)
-    {
-        [self orderOut: sender];
-        return;
-    }
-
-    dict = [[NSMutableDictionary alloc] initWithCapacity:2];
-
-    [dict setObject:self forKey:NSViewAnimationTargetKey];
+@end
 
-    [dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
-    anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
-    [dict release];
+/*****************************************************************************
+ * VLCDragDropView
+ *****************************************************************************/
 
-    [anim setAnimationBlockingMode:NSAnimationNonblocking];
-    [anim setDuration:0.9];
-    [anim setFrameRate:30];
-    [anim setUserInfo: callback];
+@implementation VLCDragDropView
 
-    @synchronized(self) {
-        current_anim = self->animation;
+@synthesize dropHandler=_dropHandler;
+@synthesize drawBorder;
 
-        if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating])
-        {
-            [anim release];
-        }
-        else
-        {
-            if (current_anim)
-            {
-                [current_anim stopAnimation];
-                [anim setCurrentProgress:1.0-[current_anim currentProgress]];
-                [current_anim release];
-            }
-            else
-                [anim setCurrentProgress:1.0 - [self alphaValue]];
-            self->animation = anim;
-            [self setDelegate: self];
-            [anim startAnimation];
-        }
-    }
-}
-
-- (void)orderFront: (id)sender animate: (BOOL)animate
+- (id)initWithFrame:(NSRect)frame
 {
-    NSViewAnimation *anim;
-    NSViewAnimation *current_anim;
-    NSMutableDictionary *dict;
-
-    if (!animate)
-    {
-        [super orderFront: sender];
-        [self setAlphaValue: 1.0];
-        return;
-    }
-
-    if (![self isVisible])
-    {
-        [self setAlphaValue: 0.0];
-        [super orderFront: sender];
+    self = [super initWithFrame:frame];
+    if (self) {
+        // default value
+        [self setDrawBorder:YES];
     }
-    else if ([self alphaValue] == 1.0)
-    {
-        [super orderFront: self];
-        return;
-    }
-
-    dict = [[NSMutableDictionary alloc] initWithCapacity:2];
-
-    [dict setObject:self forKey:NSViewAnimationTargetKey];
-
-    [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
-    anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
-    [dict release];
 
-    [anim setAnimationBlockingMode:NSAnimationNonblocking];
-    [anim setDuration:0.5];
-    [anim setFrameRate:30];
-
-    @synchronized(self) {
-        current_anim = self->animation;
-
-        if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating])
-        {
-            [anim release];
-        }
-        else
-        {
-            if (current_anim)
-            {
-                [current_anim stopAnimation];
-                [anim setCurrentProgress:1.0 - [current_anim currentProgress]];
-                [current_anim release];
-            }
-            else
-                [anim setCurrentProgress:[self alphaValue]];
-            self->animation = anim;
-            [self setDelegate: self];
-            [self orderFront: sender];
-            [anim startAnimation];
-        }
-    }
-}
-
-- (void)animationDidEnd:(NSAnimation*)anim
-{
-    if ([self alphaValue] <= 0.0)
-    {
-        NSInvocation * invoc;
-        [super orderOut: nil];
-        [self setAlphaValue: 1.0];
-        if ((invoc = [anim userInfo]))
-            [invoc invoke];
-    }
+    return self;
 }
 
-- (void)setFullscreen:(BOOL)b_var
+- (void)enablePlaylistItems
 {
-    b_isFullscreen = b_var;
+    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]];
 }
 
-- (BOOL)isFullscreen
+- (BOOL)mouseDownCanMoveWindow
 {
-    return b_isFullscreen;
+    return YES;
 }
 
-@end
-
-/*****************************************************************************
- * VLCControllerView
- *****************************************************************************/
-
-@implementation VLCControllerView
-
 - (void)dealloc
 {
     [self unregisterDraggedTypes];
@@ -388,156 +351,66 @@ static NSMutableArray *blackoutWindows = NULL;
 
 - (void)awakeFromNib
 {
-    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
-        NSFilenamesPboardType, nil]];
+    [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
 }
 
 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
 {
-    if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
-                == NSDragOperationGeneric)
-    {
-        return NSDragOperationGeneric;
-    }
-    else
-    {
-        return NSDragOperationNone;
+    if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) == NSDragOperationGeneric) {
+        b_activeDragAndDrop = YES;
+        [self setNeedsDisplay:YES];
+
+        return NSDragOperationCopy;
     }
-}
 
-- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
-{
-    return YES;
+    return NSDragOperationNone;
 }
 
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
+- (void)draggingEnded:(id < NSDraggingInfo >)sender
 {
-    NSPasteboard *o_paste = [sender draggingPasteboard];
-    NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
-    NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
-    NSData *o_carried_data = [o_paste dataForType:o_desired_type];
-
-    if( o_carried_data )
-    {
-        if ([o_desired_type isEqualToString:NSFilenamesPboardType])
-        {
-            NSArray *o_array = [NSArray array];
-            NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
-            NSUInteger count = [o_values count];
-
-            for( NSUInteger i = 0; i < count; i++)
-            {
-                NSDictionary *o_dic;
-                char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
-                if( !psz_uri )
-                    continue;
-
-                o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
-
-                free( psz_uri );
-                o_array = [o_array arrayByAddingObject: o_dic];
-            }
-            [(VLCPlaylist *)[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
-            return YES;
-        }
-    }
+    b_activeDragAndDrop = NO;
     [self setNeedsDisplay:YES];
-    return YES;
 }
 
-- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
+- (void)draggingExited:(id < NSDraggingInfo >)sender
 {
+    b_activeDragAndDrop = NO;
     [self setNeedsDisplay:YES];
 }
 
-@end
-
-/*****************************************************************************
- * VLBrushedMetalImageView
- *****************************************************************************/
-
-@implementation VLBrushedMetalImageView
-
-- (BOOL)mouseDownCanMoveWindow
+- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
 {
     return YES;
 }
 
-- (void)dealloc
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
 {
-    [self unregisterDraggedTypes];
-    [super dealloc];
-}
+    BOOL b_returned;
 
-- (void)awakeFromNib
-{
-    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
-        NSFilenamesPboardType, nil]];
-    [self setImageScaling: NSScaleToFit];
-    [self setImageFrameStyle: NSImageFrameNone];
-    [self setImageAlignment: NSImageAlignCenter];
-}
+    if (_dropHandler && [_dropHandler respondsToSelector:@selector(performDragOperation:)])
+        b_returned = [_dropHandler performDragOperation: sender];
+    else // default
+        b_returned = [[VLCCoreInteraction sharedInstance] performDragOperation: sender];
 
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
-{
-    if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
-                == NSDragOperationGeneric)
-    {
-        return NSDragOperationGeneric;
-    }
-    else
-    {
-        return NSDragOperationNone;
-    }
+    [self setNeedsDisplay:YES];
+    return b_returned;
 }
 
-- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
+- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
 {
-    return YES;
+    [self setNeedsDisplay:YES];
 }
 
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
+- (void)drawRect:(NSRect)dirtyRect
 {
-    NSPasteboard *o_paste = [sender draggingPasteboard];
-    NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
-    NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
-    NSData *o_carried_data = [o_paste dataForType:o_desired_type];
-    BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
+    if ([self drawBorder] && b_activeDragAndDrop) {
+        NSRect frameRect = [self bounds];
 
-    if( o_carried_data )
-    {
-        if ([o_desired_type isEqualToString:NSFilenamesPboardType])
-        {
-            NSArray *o_array = [NSArray array];
-            NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
-            NSUInteger count = [o_values count];
-
-            for( NSUInteger i = 0; i < count; i++)
-            {
-                NSDictionary *o_dic;
-                char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
-                if( !psz_uri )
-                    continue;
-
-                o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
-                free( psz_uri );
-
-                o_array = [o_array arrayByAddingObject: o_dic];
-            }
-            if( b_autoplay )
-                [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
-            else
-                [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
-            return YES;
-        }
+        [[NSColor selectedControlColor] set];
+        NSFrameRectWithWidthUsingOperation(frameRect, 2., NSCompositeHighlight);
     }
-    [self setNeedsDisplay:YES];
-    return YES;
-}
 
-- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
-{
-    [self setNeedsDisplay:YES];
+    [super drawRect:dirtyRect];
 }
 
 @end
@@ -607,6 +480,50 @@ void _drawFrameInRect(NSRect frameRect)
 
 @end
 
+/*****************************************************************************
+ * ProgressView
+ *****************************************************************************/
+
+@implementation VLCProgressView : NSView
+
+- (void)scrollWheel:(NSEvent *)o_event
+{
+    BOOL b_forward = NO;
+    CGFloat f_deltaY = [o_event deltaY];
+    CGFloat f_deltaX = [o_event deltaX];
+
+    if (!OSX_SNOW_LEOPARD && [o_event isDirectionInvertedFromDevice])
+        f_deltaX = -f_deltaX; // optimisation, actually double invertion of f_deltaY here
+    else
+        f_deltaY = -f_deltaY;
+
+    // positive for left / down, negative otherwise
+    CGFloat f_delta = f_deltaX + f_deltaY;
+    CGFloat f_abs;
+    int i_vlckey;
+
+    if (f_delta > 0.0f)
+        f_abs = f_delta;
+    else {
+        b_forward = YES;
+        f_abs = -f_delta;
+    }
+
+    for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++) {
+        if (b_forward)
+            [[VLCCoreInteraction sharedInstance] forwardExtraShort];
+        else
+            [[VLCCoreInteraction sharedInstance] backwardExtraShort];
+    }
+}
+
+- (BOOL)acceptsFirstResponder
+{
+    return YES;
+}
+
+@end
+
 /*****************************************************************************
  * TimeLineSlider
  *****************************************************************************/
@@ -615,10 +532,13 @@ void _drawFrameInRect(NSRect frameRect)
 
 - (void)awakeFromNib
 {
-    if (config_GetInt( VLCIntf, "macosx-interfacestyle" ))
-        o_knob_img = [NSImage imageNamed:@"progression-knob_dark"];
-    else
-        o_knob_img = [NSImage imageNamed:@"progression-knob"];
+    if (config_GetInt( VLCIntf, "macosx-interfacestyle" )) {
+        o_knob_img = imageFromRes(@"progression-knob_dark");
+        b_dark = YES;
+    } else {
+        o_knob_img = imageFromRes(@"progression-knob");
+        b_dark = NO;
+    }
     img_rect.size = [o_knob_img size];
     img_rect.origin.x = img_rect.origin.y = 0;
 }
@@ -646,6 +566,9 @@ void _drawFrameInRect(NSRect frameRect)
 
 - (void)drawRect:(NSRect)rect
 {
+    [[(VLCVideoWindowCommon *)[self window] controlsBar] drawFancyGradientEffectForTimeSlider];
+    msleep(10000); //wait for the gradient to draw completely
+
     /* Draw default to make sure the slider behaves correctly */
     [[NSGraphicsContext currentContext] saveGraphicsState];
     NSRectClip(NSZeroRect);
@@ -659,6 +582,100 @@ void _drawFrameInRect(NSRect frameRect)
 
 @end
 
+/*****************************************************************************
+ * VLCVolumeSliderCommon
+ *****************************************************************************/
+
+@implementation VLCVolumeSliderCommon : NSSlider
+
+@synthesize usesBrightArtwork = _usesBrightArtwork;
+
+- (void)scrollWheel:(NSEvent *)o_event
+{
+    BOOL b_up = NO;
+    CGFloat f_deltaY = [o_event deltaY];
+    CGFloat f_deltaX = [o_event deltaX];
+
+    if (!OSX_SNOW_LEOPARD && [o_event isDirectionInvertedFromDevice])
+        f_deltaX = -f_deltaX; // optimisation, actually double invertion of f_deltaY here
+    else
+        f_deltaY = -f_deltaY;
+
+    // positive for left / down, negative otherwise
+    CGFloat f_delta = f_deltaX + f_deltaY;
+    CGFloat f_abs;
+
+    if (f_delta > 0.0f)
+        f_abs = f_delta;
+    else {
+        b_up = YES;
+        f_abs = -f_delta;
+    }
+
+    for (NSUInteger i = 0; i < (int)(f_abs/4.+1.) && f_abs > 0.05 ; i++) {
+        if (b_up)
+            [[VLCCoreInteraction sharedInstance] volumeUp];
+        else
+            [[VLCCoreInteraction sharedInstance] volumeDown];
+    }
+}
+
+- (void)drawFullVolumeMarker
+{
+    CGFloat maxAudioVol = self.maxValue / AOUT_VOLUME_DEFAULT;
+    if (maxAudioVol < 1.)
+        return;
+
+    NSColor *drawingColor;
+    // for bright artwork, a black color is used and vice versa
+    if (_usesBrightArtwork)
+        drawingColor = [[NSColor blackColor] colorWithAlphaComponent:.4];
+    else
+        drawingColor = [[NSColor whiteColor] colorWithAlphaComponent:.4];
+
+    NSBezierPath* bezierPath = [NSBezierPath bezierPath];
+    [self drawFullVolBezierPath:bezierPath];
+    [bezierPath closePath];
+
+    bezierPath.lineWidth = 1.;
+    [drawingColor setStroke];
+    [bezierPath stroke];
+}
+
+- (CGFloat)fullVolumePos
+{
+    CGFloat maxAudioVol = self.maxValue / AOUT_VOLUME_DEFAULT;
+    CGFloat sliderRange = [self frame].size.width - [self knobThickness];
+    CGFloat sliderOrigin = [self knobThickness] / 2.;
+
+    return 1. / maxAudioVol * sliderRange + sliderOrigin;
+}
+
+- (void)drawFullVolBezierPath:(NSBezierPath*)bezierPath
+{
+    CGFloat fullVolPos = [self fullVolumePos];
+    [bezierPath moveToPoint:NSMakePoint(fullVolPos, [self frame].size.height - 3.)];
+    [bezierPath lineToPoint:NSMakePoint(fullVolPos, 2.)];
+}
+
+@end
+
+@implementation VolumeSliderCell
+
+- (BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSView *)controlView
+{
+    VLCVolumeSliderCommon *o_slider = (VLCVolumeSliderCommon *)controlView;
+    CGFloat fullVolumePos = [o_slider fullVolumePos] + 2.;
+
+    CGPoint snapToPoint = currentPoint;
+    if (ABS(fullVolumePos - currentPoint.x) <= 4.)
+        snapToPoint.x = fullVolumePos;
+
+    return [super continueTracking:lastPoint at:snapToPoint inView:controlView];
+}
+
+@end
+
 /*****************************************************************************
  * ITSlider
  *****************************************************************************/
@@ -669,9 +686,9 @@ void _drawFrameInRect(NSRect frameRect)
 {
     BOOL b_dark = config_GetInt( VLCIntf, "macosx-interfacestyle" );
     if (b_dark)
-        img = [NSImage imageNamed:@"volume-slider-knob_dark"];
+        img = imageFromRes(@"volume-slider-knob_dark");
     else
-        img = [NSImage imageNamed:@"volume-slider-knob"];
+        img = imageFromRes(@"volume-slider-knob");
 
     image_rect.size = [img size];
     image_rect.origin.x = 0;
@@ -698,6 +715,8 @@ void _drawFrameInRect(NSRect frameRect)
     [super drawRect:rect];
     [[NSGraphicsContext currentContext] restoreGraphicsState];
 
+    [self drawFullVolumeMarker];
+
     NSRect knobRect = [[self cell] knobRectFlipped:NO];
     knobRect.origin.y+=2;
     [self drawKnobInRect: knobRect];
@@ -712,23 +731,21 @@ void _drawFrameInRect(NSRect frameRect)
  *****************************************************************************/
 
 @implementation VLCTimeField
-+ (void)initialize{
++ (void)initialize
+{
     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
-    NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@"NO" forKey:@"DisplayTimeAsTimeRemaining"];
+    NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
+                                 @"NO", @"DisplayTimeAsTimeRemaining",
+                                 @"YES", @"DisplayFullscreenTimeAsTimeRemaining",
+                                 nil];
 
     [defaults registerDefaults:appDefaults];
 }
 
-- (void)awakeFromNib
+- (void)setRemainingIdentifier:(NSString *)o_string
 {
-    NSColor *o_string_color;
-    if (!config_GetInt( VLCIntf, "macosx-interfacestyle"))
-        o_string_color = [NSColor colorWithCalibratedRed:0.229 green:0.229 blue:0.229 alpha:100.0];
-    else
-        o_string_color = [NSColor colorWithCalibratedRed:0.64 green:0.64 blue:0.64 alpha:100.0];
-
-    textAlignment = NSCenterTextAlignment;
-    o_string_attributes_dict = [[NSDictionary dictionaryWithObjectsAndKeys: o_string_color, NSForegroundColorAttributeName, [NSFont titleBarFontOfSize:10.0], NSFontAttributeName, nil] retain];
+    o_remaining_identifier = o_string;
+    b_time_remaining = [[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier];
 }
 
 - (void)setAlignment:(NSTextAlignment)alignment
@@ -740,20 +757,19 @@ void _drawFrameInRect(NSRect frameRect)
 - (void)dealloc
 {
     [o_string_shadow release];
-    [o_string_attributes_dict release];
+    [super dealloc];
 }
 
 - (void)setStringValue:(NSString *)string
 {
-    if (!o_string_shadow)
-    {
+    if (!o_string_shadow) {
         o_string_shadow = [[NSShadow alloc] init];
         [o_string_shadow setShadowColor: [NSColor colorWithCalibratedWhite:1.0 alpha:0.5]];
-        [o_string_shadow setShadowOffset:NSMakeSize(0.0, -1.5)];
+        [o_string_shadow setShadowOffset:NSMakeSize(0.0, -1.0)];
         [o_string_shadow setShadowBlurRadius:0.0];
     }
 
-    NSMutableAttributedString *o_attributed_string = [[NSMutableAttributedString alloc] initWithString:string attributes: o_string_attributes_dict];
+    NSMutableAttributedString *o_attributed_string = [[NSMutableAttributedString alloc] initWithString:string attributes: nil];
     NSUInteger i_stringLength = [string length];
 
     [o_attributed_string addAttribute: NSShadowAttributeName value: o_string_shadow range: NSMakeRange(0, i_stringLength)];
@@ -764,21 +780,28 @@ void _drawFrameInRect(NSRect frameRect)
 
 - (void)mouseDown: (NSEvent *)ourEvent
 {
-    if( [ourEvent clickCount] > 1 )
+    if ( [ourEvent clickCount] > 1 )
         [[[VLCMain sharedInstance] controls] goToSpecificTime: nil];
     else
     {
-        if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayTimeAsTimeRemaining"])
-            [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"DisplayTimeAsTimeRemaining"];
-        else
-            [[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"DisplayTimeAsTimeRemaining"];
+        if (o_remaining_identifier) {
+            b_time_remaining = [[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier];
+            b_time_remaining = !b_time_remaining;
+            [[NSUserDefaults standardUserDefaults] setObject:(b_time_remaining ? @"YES" : @"NO") forKey:o_remaining_identifier];
+        } else {
+            b_time_remaining = !b_time_remaining;
+        }
     }
 }
 
 - (BOOL)timeRemaining
 {
-    return [[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayTimeAsTimeRemaining"];
+    if (o_remaining_identifier)
+        return [[NSUserDefaults standardUserDefaults] boolForKey:o_remaining_identifier];
+    else
+        return b_time_remaining;
 }
+
 @end
 
 /*****************************************************************************
@@ -799,29 +822,13 @@ void _drawFrameInRect(NSRect frameRect)
 {
     return 1.0;
 }
-
-- (void)adjustSubviews
-{
-    NSArray *o_subviews = [self subviews];
-    NSRect viewDimensions = [self frame];
-    NSRect leftViewDimensions = [[o_subviews objectAtIndex:0] frame];
-    NSRect rightViewDimensions = [[o_subviews objectAtIndex:1] frame];
-    CGFloat f_dividerThickness = [self dividerThickness];
-
-    leftViewDimensions.size.height = viewDimensions.size.height;
-    [[o_subviews objectAtIndex:0] setFrame: leftViewDimensions];
-
-    rightViewDimensions.origin.x = leftViewDimensions.size.width + f_dividerThickness;
-    rightViewDimensions.size.width = viewDimensions.size.width - leftViewDimensions.size.width - f_dividerThickness;
-    rightViewDimensions.size.height = viewDimensions.size.height;
-    [[o_subviews objectAtIndex:1] setFrame: rightViewDimensions];
-}
 @end
 
 /*****************************************************************************
  * VLCThreePartImageView interface
  *****************************************************************************/
 @implementation VLCThreePartImageView
+
 - (void)dealloc
 {
     [o_left_img release];
@@ -852,3 +859,144 @@ void _drawFrameInRect(NSRect frameRect)
 }
 
 @end
+
+
+@implementation PositionFormatter
+
+- (id)init
+{
+    self = [super init];
+    NSMutableCharacterSet *nonNumbers = [[[NSCharacterSet decimalDigitCharacterSet] invertedSet] mutableCopy];
+    [nonNumbers removeCharactersInString:@"-:"];
+    o_forbidden_characters = [nonNumbers copy];
+    [nonNumbers release];
+
+    return self;
+}
+
+- (void)dealloc
+{
+    [o_forbidden_characters release];
+    [super dealloc];
+}
+
+- (NSString*)stringForObjectValue:(id)obj
+{
+    if([obj isKindOfClass:[NSString class]])
+        return obj;
+    if([obj isKindOfClass:[NSNumber class]])
+        return [obj stringValue];
+
+    return nil;
+}
+
+- (BOOL)getObjectValue:(id*)obj forString:(NSString*)string errorDescription:(NSString**)error
+{
+    *obj = [[string copy] autorelease];
+    return YES;
+}
+
+- (BOOL)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error
+{
+    if ([partialString rangeOfCharacterFromSet:o_forbidden_characters options:NSLiteralSearch].location != NSNotFound) {
+        return NO;
+    } else {
+        return YES;
+    }
+}
+
+@end
+
+@implementation NSView (EnableSubviews)
+
+- (void)enableSubviews:(BOOL)b_enable
+{
+    for (NSView *o_view in [self subviews]) {
+        [o_view enableSubviews:b_enable];
+
+        // enable NSControl
+        if ([o_view respondsToSelector:@selector(setEnabled:)]) {
+            [(NSControl *)o_view setEnabled:b_enable];
+        }
+        // also "enable / disable" text views
+        if ([o_view respondsToSelector:@selector(setTextColor:)]) {
+            if (b_enable == NO) {
+                [(NSTextField *)o_view setTextColor:[NSColor disabledControlTextColor]];
+            } else {
+                [(NSTextField *)o_view setTextColor:[NSColor controlTextColor]];
+            }
+        }
+
+    }
+}
+
+@end
+
+/*****************************************************************************
+ * VLCByteCountFormatter addition
+ *****************************************************************************/
+
+@implementation VLCByteCountFormatter
+
++ (NSString *)stringFromByteCount:(long long)byteCount countStyle:(NSByteCountFormatterCountStyle)countStyle
+{
+    // Use native implementation on >= mountain lion
+    Class byteFormatterClass = NSClassFromString(@"NSByteCountFormatter");
+    if (byteFormatterClass && [byteFormatterClass respondsToSelector:@selector(stringFromByteCount:countStyle:)]) {
+        return [byteFormatterClass stringFromByteCount:byteCount countStyle:NSByteCountFormatterCountStyleFile];
+    }
+
+    float devider = 0.;
+    float returnValue = 0.;
+    NSString *suffix;
+
+    NSNumberFormatter *theFormatter = [[NSNumberFormatter alloc] init];
+    [theFormatter setLocale:[NSLocale currentLocale]];
+    [theFormatter setAllowsFloats:YES];
+
+    NSString *returnString = @"";
+
+    if (countStyle != NSByteCountFormatterCountStyleDecimal)
+        devider = 1024.;
+    else
+        devider = 1000.;
+
+    if (byteCount < 1000) {
+        returnValue = byteCount;
+        suffix = _NS("B");
+        [theFormatter setMaximumFractionDigits:0];
+        goto end;
+    }
+
+    if (byteCount < 1000000) {
+        returnValue = byteCount / devider;
+        suffix = _NS("KB");
+        [theFormatter setMaximumFractionDigits:0];
+        goto end;
+    }
+
+    if (byteCount < 1000000000) {
+        returnValue = byteCount / devider / devider;
+        suffix = _NS("MB");
+        [theFormatter setMaximumFractionDigits:1];
+        goto end;
+    }
+
+    [theFormatter setMaximumFractionDigits:2];
+    if (byteCount < 1000000000000) {
+        returnValue = byteCount / devider / devider / devider;
+        suffix = _NS("GB");
+        goto end;
+    }
+
+    returnValue = byteCount / devider / devider / devider / devider;
+    suffix = _NS("TB");
+
+end:
+    returnString = [NSString stringWithFormat:@"%@ %@", [theFormatter stringFromNumber:[NSNumber numberWithFloat:returnValue]], suffix];
+    [theFormatter release];
+
+    return returnString;
+}
+
+@end