]> git.sesse.net Git - vlc/blobdiff - modules/gui/macosx/MainWindow.m
macosx: allow the user to hide the sidebar (close #6088)
[vlc] / modules / gui / macosx / MainWindow.m
index c5330bc725207bc35671e7ad9b1da48798c73424..808018d8b96417c268dd85df960486027210a53d 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * MainWindow.m: MacOS X interface module
  *****************************************************************************
- * Copyright (C) 2002-2011 VLC authors and VideoLAN
+ * Copyright (C) 2002-2012 VLC authors and VideoLAN
  * $Id$
  *
  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
 #import "MainMenu.h"
 #import "open.h"
 #import "controls.h" // TODO: remove me
+#import "playlist.h"
 #import "SideBarItem.h"
-#import "MainWindowTitle.h"
 #import <vlc_playlist.h>
 #import <vlc_aout_intf.h>
 #import <vlc_url.h>
 #import <vlc_strings.h>
 #import <vlc_services_discovery.h>
+#import <vlc_aout_intf.h>
 
 @implementation VLCMainWindow
 static VLCMainWindow *_o_sharedInstance = nil;
@@ -75,7 +76,10 @@ static VLCMainWindow *_o_sharedInstance = nil;
     if (b_dark_interface)
     {
 #ifdef MAC_OS_X_VERSION_10_7
-        styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
+        if (OSX_LION)
+            styleMask = NSBorderlessWindowMask | NSResizableWindowMask;
+        else
+            styleMask = NSBorderlessWindowMask;
 #else
         styleMask = NSBorderlessWindowMask;
 #endif
@@ -108,18 +112,25 @@ static VLCMainWindow *_o_sharedInstance = nil;
 
 - (void)dealloc
 {
+    if (b_dark_interface)
+        [o_color_backdrop release];
+
     [[NSNotificationCenter defaultCenter] removeObserver: self];
-    config_PutInt( VLCIntf->p_libvlc, "volume", i_lastShownVolume );
-    [self saveFrameUsingName: [self frameAutosaveName]];
     [o_sidebaritems release];
     [super dealloc];
 }
 
 - (void)awakeFromNib
 {
+    BOOL b_splitviewShouldBeHidden = NO;
     /* setup the styled interface */
-    b_nativeFullscreenMode = config_GetInt( VLCIntf, "macosx-nativefullscreenmode" );
+    b_nativeFullscreenMode = NO;
+#ifdef MAC_OS_X_VERSION_10_7
+    if( config_GetInt( VLCIntf, "embedded-video" ))
+        b_nativeFullscreenMode = config_GetInt( VLCIntf, "macosx-nativefullscreenmode" );
+#endif
     i_lastShownVolume = -1;
+    t_hide_mouse_timer = nil;
 
     [o_play_btn setToolTip: _NS("Play/Pause")];
     [o_bwd_btn setToolTip: _NS("Backward")];
@@ -139,7 +150,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [o_dropzone_lbl setStringValue: _NS("Drop media here")];
 
     if (!b_dark_interface) {
-        [o_bottombar_view setImage: [NSImage imageNamed:@"bottom-background"]];
+        [o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottom-background"] middle: [NSImage imageNamed:@"bottom-background"] right: [NSImage imageNamed:@"bottom-background"]];
         [o_bwd_btn setImage: [NSImage imageNamed:@"back"]];
         [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed"]];
         o_play_img = [[NSImage imageNamed:@"play"] retain];
@@ -162,9 +173,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
         o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed"] retain];
         o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue"] retain];
         o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed"] retain];
-        [o_time_sld_left_view setImage: [NSImage imageNamed:@"progression-track-wrapper-left"]];
-        [o_time_sld_middle_view setImage: [NSImage imageNamed:@"progression-track-wrapper-middle"]];
-        [o_time_sld_right_view setImage: [NSImage imageNamed:@"progression-track-wrapper-right"]];
+        [o_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle"] right: [NSImage imageNamed:@"progression-track-wrapper-right"]];
         [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low"]];
         [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track"]];
         [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high"]];
@@ -180,11 +189,11 @@ static VLCMainWindow *_o_sharedInstance = nil;
         }
         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons"]];
         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed"]];
-        [o_time_sld_fancygradient_view loadImagesInDarkStyle:NO];
+        [o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progression-fill-left"] middle:[NSImage imageNamed:@"progression-fill-middle"] right:[NSImage imageNamed:@"progression-fill-right"]];
     }
     else
     {
-        [o_bottombar_view setImage: [NSImage imageNamed:@"bottom-background_dark"]];
+        [o_bottombar_view setImagesLeft: [NSImage imageNamed:@"bottomdark-left"] middle: [NSImage imageNamed:@"bottom-background_dark"] right: [NSImage imageNamed:@"bottomdark-right"]];
         [o_bwd_btn setImage: [NSImage imageNamed:@"back_dark"]];
         [o_bwd_btn setAlternateImage: [NSImage imageNamed:@"back-pressed_dark"]];
         o_play_img = [[NSImage imageNamed:@"play_dark"] retain];
@@ -207,10 +216,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
         o_shuffle_pressed_img = [[NSImage imageNamed:@"shuffle-pressed_dark"] retain];
         o_shuffle_on_img = [[NSImage imageNamed:@"shuffle-blue_dark"] retain];
         o_shuffle_on_pressed_img = [[NSImage imageNamed:@"shuffle-blue-pressed_dark"] retain];
-        [o_time_fld setTextColor: [NSColor colorWithCalibratedRed:229.0 green:229.0 blue:229.0 alpha:100.0]];
-        [o_time_sld_left_view setImage: [NSImage imageNamed:@"progression-track-wrapper-left_dark"]];
-        [o_time_sld_middle_view setImage: [NSImage imageNamed:@"progression-track-wrapper-middle_dark"]];
-        [o_time_sld_right_view setImage: [NSImage imageNamed:@"progression-track-wrapper-right_dark"]];
+        [o_time_sld_background setImagesLeft: [NSImage imageNamed:@"progression-track-wrapper-left_dark"] middle: [NSImage imageNamed:@"progression-track-wrapper-middle_dark"] right: [NSImage imageNamed:@"progression-track-wrapper-right_dark"]];
         [o_volume_down_btn setImage: [NSImage imageNamed:@"volume-low_dark"]];
         [o_volume_track_view setImage: [NSImage imageNamed:@"volume-slider-track_dark"]];
         [o_volume_up_btn setImage: [NSImage imageNamed:@"volume-high_dark"]];
@@ -222,11 +228,11 @@ static VLCMainWindow *_o_sharedInstance = nil;
         else
         {
             [o_effects_btn setImage: [NSImage imageNamed:@"effects-double-buttons_dark"]];
-            [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed_dark"]];            
+            [o_effects_btn setAlternateImage: [NSImage imageNamed:@"effects-double-buttons-pressed_dark"]];
         }
         [o_fullscreen_btn setImage: [NSImage imageNamed:@"fullscreen-double-buttons_dark"]];
         [o_fullscreen_btn setAlternateImage: [NSImage imageNamed:@"fullscreen-double-buttons-pressed_dark"]];
-        [o_time_sld_fancygradient_view loadImagesInDarkStyle:YES];
+        [o_time_sld_fancygradient_view setImagesLeft:[NSImage imageNamed:@"progressbar-fill-left_dark"] middle:[NSImage imageNamed:@"progressbar-fill-middle_dark"] right:[NSImage imageNamed:@"progressbar-fill-right_dark"]];
     }
     [o_repeat_btn setImage: o_repeat_img];
     [o_repeat_btn setAlternateImage: o_repeat_pressed_img];
@@ -234,26 +240,33 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [o_shuffle_btn setAlternateImage: o_shuffle_pressed_img];
     [o_play_btn setImage: o_play_img];
     [o_play_btn setAlternateImage: o_play_pressed_img];
+    BOOL b_mute = ![[VLCCoreInteraction sharedInstance] isMuted];
+    [o_volume_sld setEnabled: b_mute];
+    [o_volume_up_btn setEnabled: b_mute];
 
     /* interface builder action */
+    if ([self frame].size.height < 100)
+        b_splitviewShouldBeHidden = YES;
     [self setDelegate: self];
     [self setExcludedFromWindowsMenu: YES];
     [self setAcceptsMouseMovedEvents: YES];
     // Set that here as IB seems to be buggy
     if (b_dark_interface)
-        [self setContentMinSize:NSMakeSize(500., (288. + [o_titlebar_view frame].size.height))];
+        [self setContentMinSize:NSMakeSize(604., (288. + [o_titlebar_view frame].size.height))];
     else
-        [self setContentMinSize:NSMakeSize(500., 288.)];
+        [self setContentMinSize:NSMakeSize(604., 288.)];
     [self setTitle: _NS("VLC media player")];
-    [o_playlist_btn setEnabled:NO];
+    [o_time_fld setAlignment: NSCenterTextAlignment];
+    [o_time_fld setNeedsDisplay:YES];
+    b_dropzone_active = YES;
     o_temp_view = [[NSView alloc] init];
     [o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
     [o_dropzone_view setFrame: [o_playlist_table frame]];
     [o_left_split_view setFrame: [o_sidebar_view frame]];
     if (OSX_LION && b_nativeFullscreenMode)
     {
-        [self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
         NSRect frame;
+        [self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
         float f_width = [o_fullscreen_btn frame].size.width;
 
         #define moveItem( item ) \
@@ -267,7 +280,6 @@ static VLCMainWindow *_o_sharedInstance = nil;
         moveItem( o_volume_track_view );
         moveItem( o_volume_down_btn );
         moveItem( o_time_fld );
-        moveItem( o_time_sld_right_view );
         #undef moveItem
 
         #define enlargeItem( item ) \
@@ -277,7 +289,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
 
         enlargeItem( o_time_sld );
         enlargeItem( o_progress_bar );
-        enlargeItem( o_time_sld_middle_view );
+        enlargeItem( o_time_sld_background );
         enlargeItem( o_time_sld_fancygradient_view );
         #undef enlargeItem
 
@@ -301,6 +313,8 @@ static VLCMainWindow *_o_sharedInstance = nil;
     SideBarItem *libraryItem = [SideBarItem itemWithTitle:_NS("LIBRARY") identifier:@"library"];
     SideBarItem *playlistItem = [SideBarItem itemWithTitle:_NS("Playlist") identifier:@"playlist"];
     [playlistItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
+    SideBarItem *medialibraryItem = [SideBarItem itemWithTitle:_NS("Media Library") identifier:@"medialibrary"];
+    [medialibraryItem setIcon: [NSImage imageNamed:@"sidebar-playlist"]];
     SideBarItem *mycompItem = [SideBarItem itemWithTitle:_NS("MY COMPUTER") identifier:@"mycomputer"];
     SideBarItem *devicesItem = [SideBarItem itemWithTitle:_NS("DEVICES") identifier:@"devices"];
     SideBarItem *lanItem = [SideBarItem itemWithTitle:_NS("LOCAL NETWORK") identifier:@"localnetwork"];
@@ -322,32 +336,38 @@ static VLCMainWindow *_o_sharedInstance = nil;
     for (; *ppsz_name; ppsz_name++, ppsz_longname++, p_category++)
     {
         o_identifier = [NSString stringWithCString: *ppsz_name encoding: NSUTF8StringEncoding];
-        o_identifier = [[o_identifier componentsSeparatedByString:@"{"] objectAtIndex:0];
         switch (*p_category) {
             case SD_CAT_INTERNET:
                 {
-                    [internetItems addObject: [SideBarItem itemWithTitle: [NSString stringWithCString: *ppsz_longname encoding: NSUTF8StringEncoding] identifier: o_identifier]];
+                    [internetItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
                     if (!strncmp( *ppsz_name, "podcast", 7 ))
-                        [[internetItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-podcast"]];
+                        [internetItems removeLastObject]; // we don't support podcasts at this point (see #6017)
+//                        [[internetItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-podcast"]];
                     else
                         [[internetItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
+                    [[internetItems lastObject] setSdtype: SD_CAT_INTERNET];
+                    [[internetItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
                 }
                 break;
             case SD_CAT_DEVICES:
                 {
-                    [devicesItems addObject: [SideBarItem itemWithTitle: [NSString stringWithCString: *ppsz_longname encoding: NSUTF8StringEncoding] identifier: o_identifier]];
+                    [devicesItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
                     [[devicesItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
+                    [[devicesItems lastObject] setSdtype: SD_CAT_DEVICES];
+                    [[devicesItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
                 }
                 break;
             case SD_CAT_LAN:
                 {
-                    [lanItems addObject: [SideBarItem itemWithTitle: [NSString stringWithCString: *ppsz_longname encoding: NSUTF8StringEncoding] identifier: o_identifier]];
+                    [lanItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
                     [[lanItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-local"]];
+                    [[lanItems lastObject] setSdtype: SD_CAT_LAN];
+                    [[lanItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
                 }
                 break;
             case SD_CAT_MYCOMPUTER:
                 {
-                    [mycompItems addObject: [SideBarItem itemWithTitle: [NSString stringWithCString: *ppsz_longname encoding: NSUTF8StringEncoding] identifier: o_identifier]];
+                    [mycompItems addObject: [SideBarItem itemWithTitle: _NS(*ppsz_longname) identifier: o_identifier]];
                     if (!strncmp( *ppsz_name, "video_dir", 9 ))
                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-movie"]];
                     else if (!strncmp( *ppsz_name, "audio_dir", 9 ))
@@ -356,6 +376,8 @@ static VLCMainWindow *_o_sharedInstance = nil;
                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"sidebar-pictures"]];
                     else
                         [[mycompItems lastObject] setIcon: [NSImage imageNamed:@"NSApplicationIcon"]];
+                    [[mycompItems lastObject] setUntranslatedTitle: [NSString stringWithUTF8String: *ppsz_longname]];
+                    [[mycompItems lastObject] setSdtype: SD_CAT_MYCOMPUTER];
                 }
                 break;
             default:
@@ -378,7 +400,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
     free( ppsz_longnames );
     free( p_categories );
 
-    [libraryItem setChildren: [NSArray arrayWithObject: playlistItem]];
+    [libraryItem setChildren: [NSArray arrayWithObjects: playlistItem, medialibraryItem, nil]];
     [o_sidebaritems addObject: libraryItem];
     if ([mycompItem hasChildren])
         [o_sidebaritems addObject: mycompItem];
@@ -390,39 +412,81 @@ static VLCMainWindow *_o_sharedInstance = nil;
         [o_sidebaritems addObject: internetItem];
 
     [o_sidebar_view reloadData];
-    [o_sidebar_view selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:YES];
+    NSUInteger i_sidebaritem_count = [o_sidebaritems count];
+    for (NSUInteger x = 0; x < i_sidebaritem_count; x++)
+        [o_sidebar_view expandItem: [o_sidebaritems objectAtIndex: x] expandChildren: YES];
+    [o_sidebar_view selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
 
     if( b_dark_interface )
     {
         [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidResizeNotification object: nil];
         [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowResizedOrMoved:) name: NSWindowDidMoveNotification object: nil];
 
-        NSRect winrect;
+        [self setBackgroundColor: [NSColor clearColor]];
+        [self setOpaque: NO];
+        [self display];
+        [self setHasShadow:NO];
+        [self setHasShadow:YES];
+
+        NSRect winrect = [self frame];
         CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
-        winrect = [self frame];
 
         [o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
                                               winrect.size.width, f_titleBarHeight )];
-        [[self contentView] addSubview: o_titlebar_view];
+        [[self contentView] addSubview: o_titlebar_view positioned: NSWindowAbove relativeTo: o_split_view];
+
+        if (winrect.size.height > 100)
+        {
+            [self setFrame: winrect display:YES animate:YES];
+            previousSavedFrame = winrect;
+        }
 
-        winrect.size.height = winrect.size.height + f_titleBarHeight;
-        [self setFrame: winrect display:NO animate:NO];
         winrect = [o_split_view frame];
         winrect.size.height = winrect.size.height - f_titleBarHeight;
         [o_split_view setFrame: winrect];
         [o_video_view setFrame: winrect];
-        previousSavedFrame = winrect;
 
-        if (OSX_LION)
-            [o_resize_view setImage: NULL];
-
-        if ([self styleMask] & NSResizableWindowMask)
-            [o_resize_view removeFromSuperviewWithoutNeedingDisplay];
-
-        [self display];
+        o_color_backdrop = [[VLCColorView alloc] initWithFrame: [o_split_view frame]];
+        [[self contentView] addSubview: o_color_backdrop positioned: NSWindowBelow relativeTo: o_split_view];
+        [o_color_backdrop setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
     }
     else
+    {
+        NSRect frame;
+        frame = [o_time_sld_fancygradient_view frame];
+        frame.size.height = frame.size.height - 1;
+        frame.origin.y = frame.origin.y + 1;
+        [o_time_sld_fancygradient_view setFrame: frame];
+
         [o_video_view setFrame: [o_split_view frame]];
+        [o_playlist_table setBorderType: NSNoBorder];
+        [o_sidebar_scrollview setBorderType: NSNoBorder];
+    }
+
+    NSRect frame;
+    frame = [o_time_sld_fancygradient_view frame];
+    frame.size.width = 0;
+    [o_time_sld_fancygradient_view setFrame: frame];
+
+    if (OSX_LION)
+        [o_resize_view setImage: NULL];
+
+    if ([self styleMask] & NSResizableWindowMask)
+        [o_resize_view removeFromSuperviewWithoutNeedingDisplay];
+
+    if (OSX_LEOPARD)
+        [o_time_sld_fancygradient_view removeFromSuperviewWithoutNeedingDisplay];
+
+    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillClose:) name: NSWindowWillCloseNotification object: nil];
+    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(someWindowWillMiniaturize:) name: NSWindowWillMiniaturizeNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(applicationWillTerminate:) name: NSApplicationWillTerminateNotification object: nil];
+    [[VLCMain sharedInstance] playbackModeUpdated];
+
+    if (b_splitviewShouldBeHidden)
+    {
+        i_lastSplitViewHeight = [o_split_view frame].size.height;
+        [self hideSplitView];
+    }
 }
 
 #pragma mark -
@@ -436,7 +500,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
 - (void)resetPreviousButton
 {
     if (([NSDate timeIntervalSinceReferenceDate] - last_bwd_event) >= 0.35) {
-        // seems like no further event occured, so let's switch the playback item
+        // seems like no further event occurred, so let's switch the playback item
         [[VLCCoreInteraction sharedInstance] previous];
         just_triggered_previous = NO;
     }
@@ -460,10 +524,10 @@ static VLCMainWindow *_o_sharedInstance = nil;
     }
     else
     {
-        if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.12 )
+        if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16 )
         {
-            // we just skipped 3 "continous" events, otherwise we are too fast
-            [[VLCCoreInteraction sharedInstance] backward];
+            // we just skipped 4 "continous" events, otherwise we are too fast
+            [[VLCCoreInteraction sharedInstance] backwardExtraShort];
             last_bwd_event = [NSDate timeIntervalSinceReferenceDate];
             [self performSelector:@selector(resetBackwardSkip)
                        withObject: NULL
@@ -475,7 +539,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
 - (void)resetNextButton
 {
     if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) >= 0.35) {
-        // seems like no further event occured, so let's switch the playback item
+        // seems like no further event occurred, so let's switch the playback item
         [[VLCCoreInteraction sharedInstance] next];
         just_triggered_next = NO;
     }
@@ -499,10 +563,10 @@ static VLCMainWindow *_o_sharedInstance = nil;
     }
     else
     {
-        if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.12 )
+        if (([NSDate timeIntervalSinceReferenceDate] - last_fwd_event) > 0.16 )
         {
-            // we just skipped 3 "continous" events, otherwise we are too fast
-            [[VLCCoreInteraction sharedInstance] forward];
+            // we just skipped 4 "continous" events, otherwise we are too fast
+            [[VLCCoreInteraction sharedInstance] forwardExtraShort];
             last_fwd_event = [NSDate timeIntervalSinceReferenceDate];
             [self performSelector:@selector(resetForwardSkip)
                        withObject: NULL
@@ -516,26 +580,55 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [[VLCCoreInteraction sharedInstance] stop];
 }
 
+- (void)resizePlaylistAfterCollapse
+{
+    NSRect plrect;
+    plrect = [[o_playlist_table animator] frame];
+    plrect.size.height = i_lastSplitViewHeight - 19.0; // actual pl top bar height, which differs from its frame
+    [[o_playlist_table animator] setFrame: plrect];
+}
+
 - (IBAction)togglePlaylist:(id)sender
 {
-    if (!b_nonembedded)
+    if ( ((([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) != 0) && !b_splitview_removed && ![[VLCMain sharedInstance] activeVideoPlayback]) || (b_nonembedded && [[VLCMain sharedInstance] activeVideoPlayback] && sender != nil) )
+    {
+        [self hideSplitView];
+    }
+    else
     {
-        if ([o_video_view isHidden] && [o_playlist_btn isEnabled]) {
-            [o_split_view setHidden: YES];
-            [o_video_view setHidden: NO];
+        if (b_splitview_removed)
+        {
+            if( !b_nonembedded ||( sender != nil && b_nonembedded))
+                [self showSplitView];
+        }
+
+        if (b_dropzone_active && ![[VLCMain sharedInstance] activeVideoPlayback])
+        {
+            b_dropzone_active = NO;
+            [self hideDropZone];
+        }
+
+        if (!b_nonembedded)
+        {
+            if ([o_video_view isHidden] && [[VLCMain sharedInstance] activeVideoPlayback]) {
+                [o_split_view setHidden: YES];
+                [o_video_view setHidden: NO];
+                [self makeFirstResponder: o_video_view];
+            }
+            else
+            {
+                [o_video_view setHidden: YES];
+                [o_split_view setHidden: NO];
+                [self makeFirstResponder: nil];
+            }
         }
         else
         {
-            [o_video_view setHidden: YES];
             [o_split_view setHidden: NO];
+            [o_playlist_table setHidden: NO];
+            [o_video_view setHidden: ![[VLCMain sharedInstance] activeVideoPlayback]];
         }
     }
-    else
-    {
-        [o_split_view setHidden: NO];
-        [o_playlist_table setHidden: NO];
-        [o_video_view setHidden: ![[VLCMain sharedInstance] activeVideoPlayback]];
-    }
 }
 
 - (void)setRepeatOne
@@ -590,7 +683,8 @@ static VLCMainWindow *_o_sharedInstance = nil;
     bool b_value;
     playlist_t *p_playlist = pl_Get( VLCIntf );
     b_value = var_GetBool( p_playlist, "random" );
-       if(b_value) {
+
+    if(b_value) {
         [o_shuffle_btn setImage: o_shuffle_on_img];
         [o_shuffle_btn setAlternateImage: o_shuffle_on_pressed_img];
     }
@@ -649,7 +743,6 @@ static VLCMainWindow *_o_sharedInstance = nil;
         [o_fspanel setStreamPos: f_updated andTime: o_time];
         vlc_object_release( p_input );
     }
-    [self drawFancyGradientEffectForTimeSlider];
 }
 
 - (IBAction)volumeAction:(id)sender
@@ -657,9 +750,11 @@ static VLCMainWindow *_o_sharedInstance = nil;
     if (sender == o_volume_sld)
         [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
     else if (sender == o_volume_down_btn)
+    {
         [[VLCCoreInteraction sharedInstance] mute];
+    }
     else
-        [[VLCCoreInteraction sharedInstance] setVolume: 400];
+        [[VLCCoreInteraction sharedInstance] setVolume: AOUT_VOLUME_MAX];
 }
 
 - (IBAction)effects:(id)sender
@@ -684,13 +779,59 @@ static VLCMainWindow *_o_sharedInstance = nil;
     return YES;
 }
 
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
+{
+    SEL s_menuAction = [menuItem action];
+
+    if ((s_menuAction == @selector(performClose:)) || (s_menuAction == @selector(performMiniaturize:)) || (s_menuAction == @selector(performZoom:)))
+            return YES;
+
+    return [super validateMenuItem:menuItem];
+}
+
 - (void)setTitle:(NSString *)title
 {
     if (b_dark_interface)
         [o_titlebar_view setWindowTitle: title];
+    if (b_nonembedded && [[VLCMain sharedInstance] activeVideoPlayback])
+        [o_nonembedded_window setTitle: title];
     [super setTitle: title];
 }
 
+- (void)performClose:(id)sender
+{
+    NSWindow *o_key_window = [NSApp keyWindow];
+
+    if (b_dark_interface)
+    {
+        [o_key_window orderOut: sender];
+        if ( [[VLCMain sharedInstance] activeVideoPlayback] && ( !b_nonembedded || o_key_window != self ))
+            [[VLCCoreInteraction sharedInstance] stop];
+    }
+    else
+    {
+        if( b_nonembedded && o_key_window != self )
+            [o_nonembedded_window performClose: sender];
+        else
+            [super performClose: sender];
+    }
+}
+
+- (void)performMiniaturize:(id)sender
+{
+    if (b_dark_interface)
+    {
+        [self miniaturize: sender];
+        if (config_GetInt( VLCIntf, "macosx-pause-minimized" ))
+        {
+            if ([[VLCMain sharedInstance] activeVideoPlayback])
+                [[VLCCoreInteraction sharedInstance] pause];
+        }
+    }
+    else
+        [super performMiniaturize: sender];
+}
+
 - (void)performZoom:(id)sender
 {
     if (b_dark_interface)
@@ -811,10 +952,40 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [self saveFrameUsingName: [self frameAutosaveName]];
 }
 
+- (void)applicationWillTerminate:(NSNotification *)notification
+{
+    if( config_GetInt( VLCIntf, "macosx-autosave-volume" ))
+        config_PutInt( VLCIntf->p_libvlc, "volume", i_lastShownVolume );
+
+    [self saveFrameUsingName: [self frameAutosaveName]];
+}
+
+- (void)someWindowWillClose:(NSNotification *)notification
+{
+    if([notification object] == o_nonembedded_window || ([notification object] == self && !b_nonembedded))
+    {
+        if ([[VLCMain sharedInstance] activeVideoPlayback])
+            [[VLCCoreInteraction sharedInstance] stop];
+    }
+}
+
+- (void)someWindowWillMiniaturize:(NSNotification *)notification
+{
+    if (config_GetInt( VLCIntf, "macosx-pause-minimized" ))
+    {
+        if([notification object] == o_nonembedded_window || [notification object] == self)
+        {
+            if([[VLCMain sharedInstance] activeVideoPlayback])
+                [[VLCCoreInteraction sharedInstance] pause];
+        }
+    }
+}
+
 #pragma mark -
 #pragma mark Update interface and respond to foreign events
 - (void)showDropZone
 {
+    b_dropzone_active = YES;
     [o_right_split_view addSubview: o_dropzone_view];
     [o_dropzone_view setFrame: [o_playlist_table frame]];
     [[o_playlist_table animator] setHidden:YES];
@@ -826,6 +997,49 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [[o_playlist_table animator] setHidden: NO];
 }
 
+- (void)hideSplitView
+{
+    NSRect winrect = [self frame];
+    i_lastSplitViewHeight = [o_split_view frame].size.height;
+    winrect.size.height = winrect.size.height - i_lastSplitViewHeight;
+    winrect.origin.y = winrect.origin.y + i_lastSplitViewHeight;
+    [self setFrame: winrect display: YES animate: YES];
+    [self performSelector:@selector(hideDropZone) withObject:nil afterDelay:0.1];
+    if (b_dark_interface)
+    {
+        [self setContentMinSize: NSMakeSize( 604., [o_bottombar_view frame].size.height + [o_titlebar_view frame].size.height )];
+        [self setContentMaxSize: NSMakeSize( FLT_MAX, [o_bottombar_view frame].size.height + [o_titlebar_view frame].size.height )];
+    }
+    else
+    {
+        [self setContentMinSize: NSMakeSize( 604., [o_bottombar_view frame].size.height )];
+        [self setContentMaxSize: NSMakeSize( FLT_MAX, [o_bottombar_view frame].size.height )];
+    }
+    if (i_lastSplitViewHeight < 100)
+        i_lastSplitViewHeight = 300; // random reasonable size
+    b_splitview_removed = YES;
+}
+
+- (void)showSplitView
+{
+    if (b_dark_interface)
+        [self setContentMinSize:NSMakeSize( 604., 288. + [o_titlebar_view frame].size.height )];
+    else
+        [self setContentMinSize:NSMakeSize( 604., 288. )];
+    [self setContentMaxSize: NSMakeSize( FLT_MAX, FLT_MAX )];
+
+    NSRect winrect;
+    winrect = [self frame];
+    winrect.size.height = winrect.size.height + i_lastSplitViewHeight;
+    winrect.origin.y = winrect.origin.y - i_lastSplitViewHeight;
+    [self setFrame: winrect display: YES animate: YES];
+
+    [self performSelector:@selector(resizePlaylistAfterCollapse) withObject: nil afterDelay:0.75];
+    [self performSelector:@selector(updateWindow) withObject: nil afterDelay:0.3];
+
+    b_splitview_removed = NO;
+}
+
 - (void)updateTimeSlider
 {
     input_thread_t * p_input;
@@ -855,9 +1069,11 @@ static VLCMainWindow *_o_sharedInstance = nil;
         if (dur == -1) {
             [o_time_sld setEnabled: NO];
             [o_time_sld setHidden: YES];
+            [o_time_sld_fancygradient_view setHidden: YES];
         } else {
             [o_time_sld setEnabled: YES];
             [o_time_sld setHidden: NO];
+            [o_time_sld_fancygradient_view setHidden: NO];
         }
 
         [o_time_fld setStringValue: o_time];
@@ -871,9 +1087,8 @@ static VLCMainWindow *_o_sharedInstance = nil;
         [o_time_fld setStringValue: @"00:00"];
         [o_time_sld setEnabled: NO];
         [o_time_sld setHidden: YES];
+        [o_time_sld_fancygradient_view setHidden: YES];
     }
-        
-    [self performSelectorOnMainThread:@selector(drawFancyGradientEffectForTimeSlider) withObject:nil waitUntilDone:NO];
 }
 
 - (void)updateVolumeSlider
@@ -882,15 +1097,19 @@ static VLCMainWindow *_o_sharedInstance = nil;
     playlist_t * p_playlist = pl_Get( VLCIntf );
 
     i_volume = aout_VolumeGet( p_playlist );
+    BOOL b_muted = [[VLCCoreInteraction sharedInstance] isMuted];
 
-    if( i_volume != i_lastShownVolume )
+    if( !b_muted )
     {
         i_lastShownVolume = i_volume;
-        int i_volume_step = 0;
-        i_volume_step = config_GetInt( VLCIntf->p_libvlc, "volume-step" );
-        [o_volume_sld setFloatValue: (float)i_lastShownVolume / i_volume_step];
-        [o_fspanel setVolumeLevel: (float)i_lastShownVolume / i_volume_step];
+        [o_volume_sld setIntValue: i_volume];
+        [o_fspanel setVolumeLevel: i_volume];
     }
+    else
+        [o_volume_sld setIntValue: 0];
+
+    [o_volume_sld setEnabled: !b_muted];
+    [o_volume_up_btn setEnabled: !b_muted];
 }
 
 - (void)updateName
@@ -926,6 +1145,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
 
         [self setTitle: aString];
         [o_fspanel setStreamTitle: aString];
+        vlc_object_release( p_input );
     }
     else
     {
@@ -970,8 +1190,9 @@ static VLCMainWindow *_o_sharedInstance = nil;
         /* chapters & titles */
         //FIXME! b_chapters = p_input->stream.i_area_nb > 1;
 
-        if (cachedInputState == PLAYING_S || b_buffering == YES)
-            [self makeKeyAndOrderFront: nil];
+        if (( cachedInputState == PLAYING_S || b_buffering == YES ) && [[VLCMain sharedInstance] activeVideoPlayback] )
+            [[o_video_view window] makeKeyAndOrderFront: nil];
+
         vlc_object_release( p_input );
     }
 
@@ -995,11 +1216,12 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [o_fspanel setSeekable: b_seekable];
 
     PL_LOCK;
-    if (playlist_CurrentSize( p_playlist ) >= 1)
+    if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
         [self hideDropZone];
     else
         [self showDropZone];
     PL_UNLOCK;
+    [o_sidebar_view setNeedsDisplay:YES];
 }
 
 - (void)setPause
@@ -1020,20 +1242,30 @@ static VLCMainWindow *_o_sharedInstance = nil;
 
 - (void)drawFancyGradientEffectForTimeSlider
 {
+    if (OSX_LEOPARD)
+        return;
+
     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
-    float f_value = [o_time_sld_middle_view frame].size.width * ([o_time_sld intValue] / [o_time_sld maxValue]);
-    if (f_value > 5.0)
+    CGFloat f_value = [o_time_sld knobPosition];
+    if (f_value > 7.5)
     {
-        if (f_value != [o_time_sld_fancygradient_view frame].size.width)
+        NSRect oldFrame = [o_time_sld_fancygradient_view frame];
+        if (f_value != oldFrame.size.width)
         {
-            [o_time_sld_fancygradient_view setHidden: NO];
-            [o_time_sld_fancygradient_view setFrame: NSMakeRect( [o_time_sld_fancygradient_view frame].origin.x, [o_time_sld_fancygradient_view frame].origin.y, f_value, [o_time_sld_fancygradient_view frame].size.height )];
-            [o_time_sld_fancygradient_view setNeedsDisplay:YES];
-            [o_time_sld_middle_view setNeedsDisplay:YES];
+            if ([o_time_sld_fancygradient_view isHidden])
+                [o_time_sld_fancygradient_view setHidden: NO];
+            [o_time_sld_fancygradient_view setFrame: NSMakeRect( oldFrame.origin.x, oldFrame.origin.y, f_value, oldFrame.size.height )];
         }
     }
     else
     {
+        NSRect frame;
+        frame = [o_time_sld_fancygradient_view frame];
+        if (frame.size.width > 0)
+        {
+            frame.size.width = 0;
+            [o_time_sld_fancygradient_view setFrame: frame];
+        }
         [o_time_sld_fancygradient_view setHidden: YES];
     }
     [o_pool release];
@@ -1041,8 +1273,12 @@ static VLCMainWindow *_o_sharedInstance = nil;
 
 #pragma mark -
 #pragma mark Video Output handling
-
 - (id)videoView
+{
+    return o_video_view;
+}
+
+- (id)setupVideoView
 {
     vout_thread_t *p_vout = getVout();
     if (config_GetInt( VLCIntf, "embedded-video" ))
@@ -1057,11 +1293,12 @@ static VLCMainWindow *_o_sharedInstance = nil;
     }
     else
     {
-        [o_video_view removeFromSuperviewWithoutNeedingDisplay];
+        if ([o_video_view superview] != NULL)
+            [o_video_view removeFromSuperviewWithoutNeedingDisplay];
         if (o_nonembedded_window)
             [o_nonembedded_window release];
 
-        o_nonembedded_window = [[VLCWindow alloc] initWithContentRect:[o_video_view frame] styleMask: NSBorderlessWindowMask|NSResizableWindowMask backing:NSBackingStoreBuffered defer:YES];
+        o_nonembedded_window = [[VLCWindow alloc] initWithContentRect:[o_video_view frame] styleMask: NSTitledWindowMask|NSClosableWindowMask|NSResizableWindowMask|NSMiniaturizableWindowMask backing:NSBackingStoreBuffered defer:YES];
         [o_nonembedded_window setFrame:[o_video_view frame] display:NO];
         [o_nonembedded_window setBackgroundColor: [NSColor blackColor]];
         [o_nonembedded_window setMovableByWindowBackground: YES];
@@ -1092,48 +1329,49 @@ static VLCMainWindow *_o_sharedInstance = nil;
 {
     BOOL b_videoPlayback = [[VLCMain sharedInstance] activeVideoPlayback];
 
-    if (!b_nonembedded)
-        [o_playlist_btn setEnabled: b_videoPlayback];
-    else
-    {
-        [o_playlist_btn setEnabled: NO];
-        if (!b_videoPlayback)
-            [o_nonembedded_window orderOut: nil];
-    }
+    if (!b_videoPlayback)
+        [o_nonembedded_window orderOut: nil];
     if( OSX_LION && b_nativeFullscreenMode )
     {
-        if( [NSApp presentationOptions] == NSApplicationPresentationFullScreen )
+        if( [NSApp presentationOptions] & NSApplicationPresentationFullScreen )
             [o_bottombar_view setHidden: b_videoPlayback];
         else
             [o_bottombar_view setHidden: NO];
         if (!b_videoPlayback)
             [o_fspanel setNonActive: nil];
     }
+    if (b_videoPlayback)
+        [self makeFirstResponder: o_video_view];
+    else
+        [self makeFirstResponder: nil];
+
+    if (!b_videoPlayback && b_fullscreen)
+    {
+        if (!b_nativeFullscreenMode || !OSX_LION)
+            [[VLCCoreInteraction sharedInstance] toggleFullscreen];
+    }
 }
 
 - (void)resizeWindow
 {
-    if ( !b_fullscreen && !(OSX_LION && [NSApp presentationOptions] == NSApplicationPresentationFullScreen && b_nativeFullscreenMode) )
-    {
-        NSPoint topleftbase;
-        NSPoint topleftscreen;
-        NSRect new_frame;
-        topleftbase.x = 0;
-        topleftbase.y = [self frame].size.height;
-        topleftscreen = [self convertBaseToScreen: topleftbase];
+    if ( b_fullscreen || (OSX_LION && [NSApp presentationOptions] & NSApplicationPresentationFullScreen && b_nativeFullscreenMode) )
+        return;
 
-        /* Calculate the window's new size */
-        new_frame.size.width = [self frame].size.width - [o_video_view frame].size.width + nativeVideoSize.width;
-        if (b_dark_interface)
-            new_frame.size.height = [self frame].size.height - [o_video_view frame].size.height + nativeVideoSize.height + [o_titlebar_view frame].size.height;
-        else
-            new_frame.size.height = [self frame].size.height - [o_video_view frame].size.height + nativeVideoSize.height;
+    NSPoint topleftbase = NSMakePoint(0, [self frame].size.height);
+    NSPoint topleftscreen = [self convertBaseToScreen: topleftbase];
 
-        new_frame.origin.x = topleftscreen.x;
-        new_frame.origin.y = topleftscreen.y - new_frame.size.height;
+    /* Calculate the window's new size */
+    float w = [self frame].size.width  - [o_video_view frame].size.width
+        + nativeVideoSize.width;
+    float h = [self frame].size.height - [o_video_view frame].size.height
+        + nativeVideoSize.height;
 
-        [[self animator] setFrame:new_frame display:YES];
-    }
+    if (b_dark_interface)
+        h += [o_titlebar_view frame].size.height;
+
+    NSRect new_frame = NSMakeRect(topleftscreen.x, topleftscreen.y - h, w, h);
+
+    [[self animator] setFrame:new_frame display:YES];
 }
 
 - (void)setNativeVideoSize:(NSSize)size
@@ -1145,6 +1383,36 @@ static VLCMainWindow *_o_sharedInstance = nil;
     }
 }
 
+//  Called automatically if window's acceptsMouseMovedEvents property is true
+- (void)mouseMoved:(NSEvent *)theEvent
+{
+    if (b_fullscreen)
+        [self recreateHideMouseTimer];
+
+    [super mouseMoved: theEvent];
+}
+
+- (void)recreateHideMouseTimer
+{
+    if (t_hide_mouse_timer != nil) {
+        [t_hide_mouse_timer invalidate];
+        [t_hide_mouse_timer release];
+    }
+
+    t_hide_mouse_timer = [NSTimer scheduledTimerWithTimeInterval:2
+                                                          target:self
+                                                        selector:@selector(hideMouseCursor:)
+                                                        userInfo:nil
+                                                         repeats:NO];
+    [t_hide_mouse_timer retain];
+}
+
+//  NSTimer selectors require this function signature as per Apple's docs
+- (void)hideMouseCursor:(NSTimer *)timer
+{
+    [NSCursor setHiddenUntilMouseMoves: YES];
+}
+
 #pragma mark -
 #pragma mark Fullscreen support
 - (void)showFullscreenController
@@ -1176,16 +1444,17 @@ static VLCMainWindow *_o_sharedInstance = nil;
     NSRect rect;
     vout_thread_t *p_vout = getVout();
     BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
+    id o_videoWindow = b_nonembedded ? o_nonembedded_window : self;
 
     if( p_vout )
-        screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_GetInteger( p_vout, "video-device" )];
+        screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)config_GetInt( VLCIntf, "macosx-vdev" )];
 
     [self lockFullscreenAnimation];
 
     if (!screen)
     {
         msg_Dbg( VLCIntf, "chosen screen isn't present, using current screen for fullscreen mode" );
-        screen = [self screen];
+        screen = [o_videoWindow screen];
     }
     if (!screen)
     {
@@ -1200,14 +1469,14 @@ static VLCMainWindow *_o_sharedInstance = nil;
 
     [o_fullscreen_btn setState: YES];
 
-    [NSCursor setHiddenUntilMouseMoves: YES];
+    [self recreateHideMouseTimer];
 
     if( blackout_other_displays )
         [screen blackoutOtherScreens];
 
     /* Make sure we don't see the window flashes in float-on-top mode */
-    i_originalLevel = [self level];
-    [self setLevel:NSNormalWindowLevel];
+    i_originalLevel = [o_videoWindow level];
+    [o_videoWindow setLevel:NSNormalWindowLevel];
 
     /* Only create the o_fullscreen_window if we are not in the middle of the zooming animation */
     if (!o_fullscreen_window)
@@ -1215,13 +1484,14 @@ static VLCMainWindow *_o_sharedInstance = nil;
         /* We can't change the styleMask of an already created NSWindow, so we create another window, and do eye catching stuff */
 
         rect = [[o_video_view superview] convertRect: [o_video_view frame] toView: nil]; /* Convert to Window base coord */
-        rect.origin.x += [self frame].origin.x;
-        rect.origin.y += [self frame].origin.y;
+        rect.origin.x += [o_videoWindow frame].origin.x;
+        rect.origin.y += [o_videoWindow frame].origin.y;
         o_fullscreen_window = [[VLCWindow alloc] initWithContentRect:rect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
+        [o_fullscreen_window setFullscreen: YES];
         [o_fullscreen_window setBackgroundColor: [NSColor blackColor]];
         [o_fullscreen_window setCanBecomeKeyWindow: YES];
 
-        if (![self isVisible] || [self alphaValue] == 0.0)
+        if (![o_videoWindow isVisible] || [o_videoWindow alphaValue] == 0.0)
         {
             /* We don't animate if we are not visible, instead we
              * simply fade the display */
@@ -1276,7 +1546,11 @@ static VLCMainWindow *_o_sharedInstance = nil;
     if (b_fullscreen)
     {
         /* Make sure we are hidden */
-        [super orderOut: self];
+        if( b_nonembedded )
+            [o_nonembedded_window orderOut: self];
+        else
+            [super orderOut: self];
+
         [self unlockFullscreenAnimation];
         return;
     }
@@ -1303,7 +1577,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
     dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
     dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];
 
-    [dict1 setObject:self forKey:NSViewAnimationTargetKey];
+    [dict1 setObject:o_videoWindow forKey:NSViewAnimationTargetKey];
     [dict1 setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
 
     [dict2 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
@@ -1345,9 +1619,12 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [o_fspanel setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]];
     [o_fspanel setActive: nil];
 
-    if([self isVisible])
+    if( !b_nonembedded && [self isVisible] )
         [super orderOut: self];
 
+    if( b_nonembedded && [o_nonembedded_window isVisible] )
+        [o_nonembedded_window orderOut: self];
+
     [o_fspanel setActive: nil];
 
     b_fullscreen = YES;
@@ -1371,8 +1648,8 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [o_fullscreen_btn setState: NO];
 
     /* We always try to do so */
-    if (!(OSX_LION && b_nativeFullscreenMode))
-        [NSScreen unblackoutScreens];
+    [NSScreen unblackoutScreens];
+
     vout_thread_t *p_vout = getVout();
     if (p_vout)
     {
@@ -1407,7 +1684,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
         if (OSX_LEOPARD)
             SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
         else
-            [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
+            [NSApp setPresentationOptions: NSApplicationPresentationDefault];
 
         /* Will release the lock */
         [self hasEndedFullscreen];
@@ -1425,8 +1702,10 @@ static VLCMainWindow *_o_sharedInstance = nil;
         return;
     }
 
-    [self setAlphaValue: 0.0];
-    [self orderFront: self];
+    id o_videoWindow = b_nonembedded ? o_nonembedded_window : self;
+
+    [o_videoWindow setAlphaValue: 0.0];
+    [o_videoWindow orderFront: self];
     [[o_video_view window] orderFront: self];
 
     [o_fspanel setNonActive: nil];
@@ -1447,11 +1726,11 @@ static VLCMainWindow *_o_sharedInstance = nil;
     }
 
     frame = [[o_temp_view superview] convertRect: [o_temp_view frame] toView: nil]; /* Convert to Window base coord */
-    frame.origin.x += [self frame].origin.x;
-    frame.origin.y += [self frame].origin.y;
+    frame.origin.x += [o_videoWindow frame].origin.x;
+    frame.origin.y += [o_videoWindow frame].origin.y;
 
     dict2 = [[NSMutableDictionary alloc] initWithCapacity:2];
-    [dict2 setObject:self forKey:NSViewAnimationTargetKey];
+    [dict2 setObject:o_videoWindow forKey:NSViewAnimationTargetKey];
     [dict2 setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
 
     o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict2, nil]];
@@ -1494,15 +1773,24 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [[o_temp_view superview] replaceSubview:o_temp_view with:o_video_view];
     [o_video_view release];
     [o_video_view setFrame:[o_temp_view frame]];
-    [self makeFirstResponder: o_video_view];
-    if ([self isVisible])
-        [super makeKeyAndOrderFront:self]; /* our version contains a workaround */
+    [[o_video_view window] makeFirstResponder: o_video_view];
+    if( [[o_video_view window] isVisible] )
+    {
+        if( !b_nonembedded )
+            [super makeKeyAndOrderFront:self]; /* our version contains a workaround */
+        else
+            [[o_video_view window] makeKeyAndOrderFront: self];
+    }
     [o_fullscreen_window orderOut: self];
     NSEnableScreenUpdates();
 
     [o_fullscreen_window release];
     o_fullscreen_window = nil;
-    [self setLevel:i_originalLevel];
+    [[o_video_view window] setLevel:i_originalLevel];
+
+    // if we quit fullscreen because there is no video anymore, make sure non-embedded window is not visible
+    if( ![[VLCMain sharedInstance] activeVideoPlayback] && b_nonembedded )
+        [o_nonembedded_window orderOut: self];
 
     [self unlockFullscreenAnimation];
 }
@@ -1536,7 +1824,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
 - (void)orderOut: (id)sender
 {
     /* Make sure we leave fullscreen */
-    if (!(OSX_LION && b_nativeFullscreenMode))
+    if (!(OSX_LION || !b_nativeFullscreenMode))
         [self leaveFullscreenAndFadeOut: YES];
 
     [super orderOut: sender];
@@ -1625,9 +1913,13 @@ static VLCMainWindow *_o_sharedInstance = nil;
 - (void)windowWillEnterFullScreen:(NSNotification *)notification
 {
     [o_video_view setFrame: [[self contentView] frame]];
-    [NSCursor setHiddenUntilMouseMoves: YES];
     b_fullscreen = YES;
     [o_fspanel setVoutWasUpdated: (int)[[self screen] displayID]];
+    [o_fspanel setActive: nil];
+
+    [self recreateHideMouseTimer];
+    i_originalLevel = [self level];
+    [self setLevel:NSNormalWindowLevel];
 
     if (b_dark_interface)
     {
@@ -1643,6 +1935,9 @@ static VLCMainWindow *_o_sharedInstance = nil;
         winrect.size.height = winrect.size.height + f_titleBarHeight;
         [o_split_view setFrame: winrect];
     }
+
+    if ([[VLCMain sharedInstance] activeVideoPlayback])
+        [o_bottombar_view setHidden: YES];
 }
 
 - (void)windowWillExitFullScreen:(NSNotification *)notification
@@ -1650,6 +1945,7 @@ static VLCMainWindow *_o_sharedInstance = nil;
     [o_video_view setFrame: [o_split_view frame]];
     [NSCursor setHiddenUntilMouseMoves: NO];
     [o_fspanel setNonActive: nil];
+    [self setLevel:i_originalLevel];
     b_fullscreen = NO;
 
     if (b_dark_interface)
@@ -1657,11 +1953,11 @@ static VLCMainWindow *_o_sharedInstance = nil;
         NSRect winrect;
         CGFloat f_titleBarHeight = [o_titlebar_view frame].size.height;
         winrect = [self frame];
-        
+
         [o_titlebar_view setFrame: NSMakeRect( 0, winrect.size.height - f_titleBarHeight,
                                               winrect.size.width, f_titleBarHeight )];
         [[self contentView] addSubview: o_titlebar_view];
-        
+
         winrect.size.height = winrect.size.height + f_titleBarHeight;
         [self setFrame: winrect display:NO animate:NO];
         winrect = [o_split_view frame];
@@ -1669,18 +1965,13 @@ static VLCMainWindow *_o_sharedInstance = nil;
         [o_split_view setFrame: winrect];
         [o_video_view setFrame: winrect];
     }
+
+    if ([[VLCMain sharedInstance] activeVideoPlayback])
+        [o_bottombar_view setHidden: NO];
 }
 
 #pragma mark -
 #pragma mark split view delegate
-- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex
-{
-    if (dividerIndex == 0)
-        return 200.0;
-    else
-        return proposedMin;
-}
-
 - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex
 {
     if (dividerIndex == 0)
@@ -1694,89 +1985,124 @@ static VLCMainWindow *_o_sharedInstance = nil;
 /* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
 - (NSUInteger)sourceList:(PXSourceList*)sourceList numberOfChildrenOfItem:(id)item
 {
-       //Works the same way as the NSOutlineView data source: `nil` means a parent item
-       if(item==nil) {
-               return [o_sidebaritems count];
-       }
-       else {
-               return [[item children] count];
-       }
+    //Works the same way as the NSOutlineView data source: `nil` means a parent item
+    if(item==nil)
+        return [o_sidebaritems count];
+    else
+        return [[item children] count];
 }
 
 
 - (id)sourceList:(PXSourceList*)aSourceList child:(NSUInteger)index ofItem:(id)item
 {
     //Works the same way as the NSOutlineView data source: `nil` means a parent item
-       if(item==nil) {
-               return [o_sidebaritems objectAtIndex:index];
-       }
-       else {
-               return [[item children] objectAtIndex:index];
-       }
+    if(item==nil)
+        return [o_sidebaritems objectAtIndex:index];
+    else
+        return [[item children] objectAtIndex:index];
 }
 
 
 - (id)sourceList:(PXSourceList*)aSourceList objectValueForItem:(id)item
 {
-       return [item title];
+    return [item title];
 }
 
 - (void)sourceList:(PXSourceList*)aSourceList setObjectValue:(id)object forItem:(id)item
 {
-       [item setTitle:object];
+    [item setTitle:object];
 }
 
 - (BOOL)sourceList:(PXSourceList*)aSourceList isItemExpandable:(id)item
 {
-       return [item hasChildren];
+    return [item hasChildren];
 }
 
 
 - (BOOL)sourceList:(PXSourceList*)aSourceList itemHasBadge:(id)item
 {
-    if ([[item identifier] isEqualToString: @"playlist"])
+    if ([[item identifier] isEqualToString: @"playlist"] || [[item identifier] isEqualToString: @"medialibrary"])
         return YES;
 
-       return [item hasBadge];
+    return [item hasBadge];
 }
 
 
 - (NSInteger)sourceList:(PXSourceList*)aSourceList badgeValueForItem:(id)item
 {
-    if ([[item identifier] isEqualToString: @"playlist"]) {
-        playlist_t * p_playlist = pl_Get( VLCIntf );
-        NSInteger i_playlist_size;
+    playlist_t * p_playlist = pl_Get( VLCIntf );
+    NSInteger i_playlist_size;
+
+    if ([[item identifier] isEqualToString: @"playlist"])
+    {
+        PL_LOCK;
+        i_playlist_size = p_playlist->p_local_category->i_children;
+        PL_UNLOCK;
 
+        return i_playlist_size;
+    }
+    if ([[item identifier] isEqualToString: @"medialibrary"])
+    {
         PL_LOCK;
-        i_playlist_size = playlist_CurrentSize( p_playlist );
+        i_playlist_size = p_playlist->p_ml_category->i_children;
         PL_UNLOCK;
 
         return i_playlist_size;
     }
-       return [item badgeValue];
+
+    return [item badgeValue];
 }
 
 
 - (BOOL)sourceList:(PXSourceList*)aSourceList itemHasIcon:(id)item
 {
-       return [item hasIcon];
+    return [item hasIcon];
 }
 
 
 - (NSImage*)sourceList:(PXSourceList*)aSourceList iconForItem:(id)item
 {
-       return [item icon];
+    return [item icon];
 }
 
 - (NSMenu*)sourceList:(PXSourceList*)aSourceList menuForEvent:(NSEvent*)theEvent item:(id)item
 {
-       if ([theEvent type] == NSRightMouseDown || ([theEvent type] == NSLeftMouseDown && ([theEvent modifierFlags] & NSControlKeyMask) == NSControlKeyMask)) {
-               NSMenu * m = [[NSMenu alloc] init];
-               if (item != nil)
-                       [m addItemWithTitle:[item title] action:nil keyEquivalent:@""];
-               return [m autorelease];
-       }
-       return nil;
+    if ([theEvent type] == NSRightMouseDown || ([theEvent type] == NSLeftMouseDown && ([theEvent modifierFlags] & NSControlKeyMask) == NSControlKeyMask))
+    {
+        if (item != nil)
+        {
+            NSMenu * m;
+            if ([item sdtype] > 0)
+            {
+                m = [[NSMenu alloc] init];
+                playlist_t * p_playlist = pl_Get( VLCIntf );
+                BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [[item identifier] UTF8String] );
+                if (!sd_loaded)
+                    [m addItemWithTitle:_NS("Enable") action:@selector(sdmenuhandler:) keyEquivalent:@""];
+                else
+                    [m addItemWithTitle:_NS("Disable") action:@selector(sdmenuhandler:) keyEquivalent:@""];
+                [[m itemAtIndex:0] setRepresentedObject: [item identifier]];
+            }
+            return [m autorelease];
+        }
+    }
+
+    return nil;
+}
+
+- (IBAction)sdmenuhandler:(id)sender
+{
+    NSString * identifier = [sender representedObject];
+    if ([identifier length] > 0 && ![identifier isEqualToString:@"lua{sd='freebox',longname='Freebox TV'}"])
+    {
+        playlist_t * p_playlist = pl_Get( VLCIntf );
+        BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [identifier UTF8String] );
+
+        if (!sd_loaded)
+            playlist_ServicesDiscoveryAdd( p_playlist, [identifier UTF8String] );
+        else
+            playlist_ServicesDiscoveryRemove( p_playlist, [identifier UTF8String] );
+    }
 }
 
 #pragma mark -
@@ -1784,57 +2110,55 @@ static VLCMainWindow *_o_sharedInstance = nil;
 /* taken under BSD-new from the PXSourceList sample project, adapted for VLC */
 - (BOOL)sourceList:(PXSourceList*)aSourceList isGroupAlwaysExpanded:(id)group
 {
-       if([[group identifier] isEqualToString:@"library"])
-               return YES;
+    if ([[group identifier] isEqualToString:@"library"])
+        return YES;
 
-       return NO;
+    return NO;
 }
 
 - (void)sourceListSelectionDidChange:(NSNotification *)notification
 {
-       NSIndexSet *selectedIndexes = [o_sidebar_view selectedRowIndexes];
+    playlist_t * p_playlist = pl_Get( VLCIntf );
 
-       //Set the label text to represent the new selection
-    if([selectedIndexes count]==1) {
-               NSString *title = [[o_sidebar_view itemAtRow:[selectedIndexes firstIndex]] title];
+    NSIndexSet *selectedIndexes = [o_sidebar_view selectedRowIndexes];
+    id item = [o_sidebar_view itemAtRow:[selectedIndexes firstIndex]];
 
-               [o_chosen_category_lbl setStringValue:title];
-       }
-       else {
-               [o_chosen_category_lbl setStringValue:@"(none)"];
-       }
-}
 
-@end
+    //Set the label text to represent the new selection
+    if ([item sdtype] > -1 && [[item identifier] length] > 0)
+    {
+        BOOL sd_loaded = playlist_IsServicesDiscoveryLoaded( p_playlist, [[item identifier] UTF8String] );
+        if (!sd_loaded)
+        {
+            playlist_ServicesDiscoveryAdd( p_playlist, [[item identifier] UTF8String] );
+        }
+    }
 
-@implementation VLCProgressBarGradientEffect
-- (void)dealloc
-{
-    [o_time_sld_gradient_left_img release];
-    [o_time_sld_gradient_middle_img release];
-    [o_time_sld_gradient_right_img release];
-    [super dealloc];
-}
+    [o_chosen_category_lbl setStringValue:[item title]];
 
-- (void)loadImagesInDarkStyle: (BOOL)b_value
-{
-    if (b_value)
+    if ([[item identifier] isEqualToString:@"playlist"])
+    {
+        [[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_local_category];
+    }
+    else if([[item identifier] isEqualToString:@"medialibrary"])
     {
-        o_time_sld_gradient_left_img = [[NSImage imageNamed:@"progressbar-fill-left_dark"] retain];
-        o_time_sld_gradient_middle_img = [[NSImage imageNamed:@"progressbar-fill-middle_dark"] retain];
-        o_time_sld_gradient_right_img = [[NSImage imageNamed:@"progressbar-fill-right_dark"] retain];
+        [[[VLCMain sharedInstance] playlist] setPlaylistRoot:p_playlist->p_ml_category];
     }
     else
     {
-        o_time_sld_gradient_left_img = [[NSImage imageNamed:@"progression-fill-left"] retain];
-        o_time_sld_gradient_middle_img = [[NSImage imageNamed:@"progression-fill-middle"] retain];
-        o_time_sld_gradient_right_img = [[NSImage imageNamed:@"progression-fill-right"] retain];
+        playlist_item_t * pl_item;
+        PL_LOCK;
+        pl_item = playlist_ChildSearchName( p_playlist->p_root, [[item untranslatedTitle] UTF8String] );
+        PL_UNLOCK;
+        [[[VLCMain sharedInstance] playlist] setPlaylistRoot: pl_item];
     }
-}
 
-- (void)drawRect:(NSRect)rect
-{
-    NSRect bnds = [self bounds];
-    NSDrawThreePartImage( bnds, o_time_sld_gradient_left_img, o_time_sld_gradient_middle_img, o_time_sld_gradient_right_img, NO, NSCompositeSourceOver, 1, NO );
+    PL_LOCK;
+    if ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] != p_playlist->p_local_category || p_playlist->p_local_category->i_children > 0)
+        [self hideDropZone];
+    else
+        [self showDropZone];
+    PL_UNLOCK;
 }
+
 @end