]> git.sesse.net Git - vlc/blobdiff - modules/gui/macosx/intf.m
macosx: use CoreInteraction code for the media key triggers
[vlc] / modules / gui / macosx / intf.m
index 0256e1cfdc17d978efba81d9eb8b154c1f552146..f7e36d751283fbe11ef23fb0713b6fef958929c3 100644 (file)
@@ -39,6 +39,7 @@
 #include <vlc_dialog.h>
 #include <vlc_url.h>
 #include <vlc_modules.h>
+#include <vlc_plugin.h>
 #include <vlc_aout_intf.h>
 #include <vlc_vout_window.h>
 #include <unistd.h> /* execl() */
@@ -96,6 +97,7 @@ int OpenIntf ( vlc_object_t *p_this )
 {
     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
     [VLCApplication sharedApplication];
+
     intf_thread_t *p_intf = (intf_thread_t*) p_this;
 
     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
@@ -105,9 +107,9 @@ int OpenIntf ( vlc_object_t *p_this )
     memset( p_intf->p_sys, 0, sizeof( *p_intf->p_sys ) );
 
     /* subscribe to LibVLCCore's messages */
-    p_intf->p_sys->p_sub = vlc_Subscribe( MsgCallback, NULL );
-    p_intf->pf_run = Run;
-    p_intf->b_should_run_on_first_thread = true;
+    vlc_Subscribe( &p_intf->p_sys->sub, MsgCallback, NULL );
+
+    Run( p_intf );
 
     [o_pool release];
     return VLC_SUCCESS;
@@ -168,7 +170,8 @@ static int WindowControl( vout_window_t *p_wnd, int i_query, va_list args )
     else if( i_query == VOUT_WINDOW_SET_FULLSCREEN )
     {
         NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
-        [[VLCMain sharedInstance] fullscreenChanged];
+        // we already have our playlist "fullscreen" callback, do not repeat the same call here
+        //[[VLCMain sharedInstance] performSelectorOnMainThread:@selector(fullscreenChanged) withObject: nil waitUntilDone: NO];
         [o_pool release];
     }
     else
@@ -188,20 +191,9 @@ void WindowClose( vout_window_t *p_wnd )
  * Run: main loop
  *****************************************************************************/
 static NSLock * o_appLock = nil;    // controls access to f_appExit
-static int f_appExit = 0;           // set to 1 when application termination signaled
 
 static void Run( intf_thread_t *p_intf )
 {
-    sigset_t set;
-
-    /* Make sure the "force quit" menu item does quit instantly.
-     * VLC overrides SIGTERM which is sent by the "force quit"
-     * menu item to make sure daemon mode quits gracefully, so
-     * we un-override SIGTERM here. */
-    sigemptyset( &set );
-    sigaddset( &set, SIGTERM );
-    pthread_sigmask( SIG_UNBLOCK, &set, NULL );
-
     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
     [VLCApplication sharedApplication];
 
@@ -214,6 +206,8 @@ static void Run( intf_thread_t *p_intf )
     [[VLCMain sharedInstance] applicationWillTerminate:nil];
     [o_appLock release];
     [o_pool release];
+
+    raise(SIGTERM);
 }
 
 #pragma mark -
@@ -249,13 +243,13 @@ static int InputEvent( vlc_object_t *p_this, const char *psz_var,
     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
     switch (new_val.i_int) {
         case INPUT_EVENT_STATE:
-            [[VLCMain sharedInstance] playbackStatusUpdated];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(playbackStatusUpdated) withObject: nil waitUntilDone:NO];
             break;
         case INPUT_EVENT_RATE:
-            [[VLCMainMenu sharedInstance] performSelectorOnMainThread:@selector(updatePlaybackRate) withObject: nil waitUntilDone:NO];
+            [[[VLCMain sharedInstance] mainMenu] performSelectorOnMainThread:@selector(updatePlaybackRate) withObject: nil waitUntilDone:NO];
             break;
         case INPUT_EVENT_POSITION:
-            [[VLCMain sharedInstance] updatePlaybackPosition];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updatePlaybackPosition) withObject: nil waitUntilDone:NO];
             break;
         case INPUT_EVENT_TITLE:
         case INPUT_EVENT_CHAPTER:
@@ -278,8 +272,8 @@ static int InputEvent( vlc_object_t *p_this, const char *psz_var,
         case INPUT_EVENT_ITEM_META:
         case INPUT_EVENT_ITEM_INFO:
             [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updateMainMenu) withObject: nil waitUntilDone:NO];
-            [[VLCMain sharedInstance] updateName];
-            [[VLCMain sharedInstance] updateInfoandMetaPanel];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updateName) withObject: nil waitUntilDone:NO];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updateInfoandMetaPanel) withObject: nil waitUntilDone:NO];
             break;
         case INPUT_EVENT_BOOKMARK:
             break;
@@ -295,23 +289,23 @@ static int InputEvent( vlc_object_t *p_this, const char *psz_var,
             break;
 
         case INPUT_EVENT_ITEM_NAME:
-            [[VLCMain sharedInstance] updateName];
-            [[VLCMain sharedInstance] playlistUpdated];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updateName) withObject: nil waitUntilDone:NO];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(playlistUpdated) withObject: nil waitUntilDone:NO];
             break;
 
         case INPUT_EVENT_AUDIO_DELAY:
         case INPUT_EVENT_SUBTITLE_DELAY:
-            [[VLCMain sharedInstance] updateDelays];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updateDelays) withObject:nil waitUntilDone:NO];
             break;
 
         case INPUT_EVENT_DEAD:
-            [[VLCMain sharedInstance] updateName];
-            [[VLCMain sharedInstance] updatePlaybackPosition];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updateName) withObject: nil waitUntilDone:NO];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updatePlaybackPosition) withObject:nil waitUntilDone:NO];
             break;
 
         case INPUT_EVENT_ABORT:
-            [[VLCMain sharedInstance] updateName];
-            [[VLCMain sharedInstance] updatePlaybackPosition];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updateName) withObject: nil waitUntilDone:NO];
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updatePlaybackPosition) withObject:nil waitUntilDone:NO];
             break;
 
         default:
@@ -347,7 +341,7 @@ static int PlaybackModeUpdated( vlc_object_t *p_this, const char *psz_var,
                          vlc_value_t oldval, vlc_value_t new_val, void *param )
 {
     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
-    [[VLCMain sharedInstance] playbackModeUpdated];
+    [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(playbackModeUpdated) withObject:nil waitUntilDone:NO];
 
     [o_pool release];
     return VLC_SUCCESS;
@@ -374,7 +368,16 @@ static int ShowController( vlc_object_t *p_this, const char *psz_variable,
     intf_thread_t * p_intf = VLCIntf;
     if( p_intf && p_intf->p_sys )
     {
-//        [[[VLCMain sharedInstance] fspanel] makeKeyAndOrderFront: nil];
+        playlist_t * p_playlist = pl_Get( p_intf );
+        BOOL b_fullscreen = var_GetBool( p_playlist, "fullscreen" );
+        if( strcmp(psz_variable, "intf-toggle-fscontrol") || b_fullscreen )
+        {
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(showFullscreenController) withObject:nil waitUntilDone:NO];
+        }
+        else
+        {
+            [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(showMainWindow) withObject:nil waitUntilDone:NO];
+        }
     }
     return VLC_SUCCESS;
 }
@@ -390,7 +393,7 @@ static int FullscreenChanged( vlc_object_t *p_this, const char *psz_variable,
     if (p_intf)
     {
         NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
-        [[VLCMain sharedInstance] fullscreenChanged];
+        [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(fullscreenChanged) withObject:nil waitUntilDone:NO];
         [o_pool release];
     }
     return VLC_SUCCESS;
@@ -441,7 +444,7 @@ void updateProgressPanel (void *priv, const char *text, float value)
 void destroyProgressPanel (void *priv)
 {
     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
-    [[[VLCMain sharedInstance] coreDialogProvider] destroyProgressPanel];
+    [[[VLCMain sharedInstance] coreDialogProvider] performSelectorOnMainThread:@selector(destroyProgressPanel) withObject:nil waitUntilDone:NO];
     [o_pool release];
 }
 
@@ -516,6 +519,7 @@ static VLCMain *_o_sharedMainInstance = nil;
         _o_sharedMainInstance = [super init];
 
     p_intf = NULL;
+    p_current_input = NULL;
 
     o_msg_lock = [[NSLock alloc] init];
     o_msg_arr = [[NSMutableArray arrayWithCapacity: 600] retain];
@@ -570,7 +574,8 @@ static VLCMain *_o_sharedMainInstance = nil;
 
     var_AddCallback(p_playlist, "fullscreen", FullscreenChanged, self);
     var_AddCallback( p_intf->p_libvlc, "intf-toggle-fscontrol", ShowController, self);
-//    var_AddCallback(p_playlist, "item-change", PLItemChanged, self);
+    var_AddCallback( p_intf->p_libvlc, "intf-show", ShowController, self);
+    //    var_AddCallback(p_playlist, "item-change", PLItemChanged, self);
     var_AddCallback(p_playlist, "item-current", PLItemChanged, self);
     var_AddCallback(p_playlist, "activity", PLItemChanged, self);
     var_AddCallback(p_playlist, "leaf-to-parent", PlaylistUpdated, self);
@@ -584,7 +589,7 @@ static VLCMain *_o_sharedMainInstance = nil;
 
     if (OSX_LION)
     {
-        if ([NSApp currentSystemPresentationOptions] == NSApplicationPresentationFullScreen)
+        if ([NSApp currentSystemPresentationOptions] & NSApplicationPresentationFullScreen)
             var_SetBool( p_playlist, "fullscreen", YES );
     }
 
@@ -604,18 +609,41 @@ static VLCMain *_o_sharedMainInstance = nil;
     var_AddCallback( p_intf, "dialog-progress-bar", DialogCallback, self );
     dialog_Register( p_intf );
 
-    [self playbackModeUpdated];
-
     /* init Apple Remote support */
     o_remote = [[AppleRemote alloc] init];
     [o_remote setClickCountEnabledButtons: kRemoteButtonPlay];
     [o_remote setDelegate: _o_sharedMainInstance];
 
-    b_msg_live_update = [[NSUserDefaults standardUserDefaults] boolForKey:@"LiveUpdateTheMessagesPanel"];
-    [o_msgs_liveUpdate_ckb setState: b_msg_live_update];
+    [o_msgs_refresh_btn setImage: [NSImage imageNamed: NSImageNameRefreshTemplate]];
 
     /* yeah, we are done */
-    b_nativeFullscreenMode = config_GetInt( p_intf, "macosx-nativefullscreenmode" );
+    b_nativeFullscreenMode = NO;
+#ifdef MAC_OS_X_VERSION_10_7
+    if( OSX_LION )
+        b_nativeFullscreenMode = config_GetInt( p_intf, "macosx-nativefullscreenmode" );
+#endif
+
+    /* recover stored audio device, if set
+     * in case it was unplugged in the meantime, auhal will fall back on the default */
+    int i_value = config_GetInt( p_intf, "macosx-audio-device" );
+    if (i_value > 0)
+        var_SetInteger( pl_Get( VLCIntf ), "audio-device", i_value );
+
+    if (config_GetInt( VLCIntf, "macosx-icon-change"))
+    {
+        /* After day 354 of the year, the usual VLC cone is replaced by another cone
+         * wearing a Father Xmas hat.
+         * Note: this icon doesn't represent an endorsement of The Coca-Cola Company.
+         */
+        NSCalendar *gregorian =
+        [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
+        NSUInteger dayOfYear = [gregorian ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:[NSDate date]];
+        [gregorian release];
+
+        if (dayOfYear >= 354)
+            [[VLCApplication sharedApplication] setApplicationIconImage: [NSImage imageNamed:@"vlc-xmas"]];
+    }
+
     nib_main_loaded = TRUE;
 }
 
@@ -623,6 +651,13 @@ static VLCMain *_o_sharedMainInstance = nil;
 {
     if( !p_intf ) return;
 
+    [self updateCurrentlyUsedHotkeys];
+
+    [o_mainwindow updateWindow];
+    [o_mainwindow updateTimeSlider];
+    [o_mainwindow updateVolumeSlider];
+    [o_mainwindow makeKeyAndOrderFront: self];
+
     /* init media key support */
     b_mediaKeySupport = config_GetInt( VLCIntf, "macosx-mediakeys" );
     if( b_mediaKeySupport )
@@ -637,19 +672,15 @@ static VLCMain *_o_sharedMainInstance = nil;
 
     [self _removeOldPreferences];
 
-    [o_mainwindow updateWindow];
-    [o_mainwindow updateTimeSlider];
-    [o_mainwindow updateVolumeSlider];
-    [o_mainwindow makeKeyAndOrderFront: self];
-
     /* Handle sleep notification */
     [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(computerWillSleep:)
            name:NSWorkspaceWillSleepNotification object:nil];
 
     [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(lookForCrashLog) withObject:nil waitUntilDone:NO];
 
-       /* we will need this, so let's load it here so the interface appears to be more responsive */
-       nib_open_loaded = [NSBundle loadNibNamed:@"Open" owner: NSApp];
+    /* we will need this, so let's load it here so the interface appears to be more responsive */
+    nib_open_loaded = [NSBundle loadNibNamed:@"Open" owner: NSApp];
+    [self initStrings];
 }
 
 - (void)initStrings
@@ -660,7 +691,6 @@ static VLCMain *_o_sharedMainInstance = nil;
     [o_msgs_panel setTitle: _NS("Messages")];
     [o_msgs_crashlog_btn setTitle: _NS("Open CrashLog...")];
     [o_msgs_save_btn setTitle: _NS("Save this Log...")];
-    [o_msgs_liveUpdate_ckb setTitle: _NS("Live Update")];
 
     /* crash reporter panel */
     [o_crashrep_send_btn setTitle: _NS("Send")];
@@ -677,32 +707,38 @@ static VLCMain *_o_sharedMainInstance = nil;
 
 - (void)applicationWillTerminate:(NSNotification *)notification
 {
-    playlist_t * p_playlist;
-    vout_thread_t * p_vout;
-    int returnedValue = 0;
-
-    if( !p_intf )
-        return;
-
-    // save stuff
-    config_SaveConfigFile( p_intf );
-
-    // don't allow a double termination call. If the user has
-    // already invoked the quit then simply return this time.
-    int isTerminating = false;
+    /* don't allow a double termination call. If the user has
+     * already invoked the quit then simply return this time. */
+    static bool f_appExit = false;
+    bool isTerminating;
 
     [o_appLock lock];
-    isTerminating = (f_appExit++ > 0 ? 1 : 0);
+    isTerminating = f_appExit;
+    f_appExit = true;
     [o_appLock unlock];
 
     if (isTerminating)
         return;
 
-    msg_Dbg( p_intf, "Terminating" );
+    if (notification == nil)
+        [[NSNotificationCenter defaultCenter] postNotificationName: NSApplicationWillTerminateNotification object: nil];
 
-    /* Make sure the intf object is getting killed */
-    vlc_object_kill( p_intf );
-    p_playlist = pl_Get( p_intf );
+    playlist_t * p_playlist = pl_Get( p_intf );
+    int returnedValue = 0;
+
+    /* always exit fullscreen on quit, otherwise we get ugly artifacts on the next launch */
+    if (b_nativeFullscreenMode)
+    {
+        [o_mainwindow toggleFullScreen: self];
+        [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
+    }
+
+    /* Save some interface state in configuration, at module quit */
+    config_PutInt( p_intf, "random", var_GetBool( p_playlist, "random" ) );
+    config_PutInt( p_intf, "loop", var_GetBool( p_playlist, "loop" ) );
+    config_PutInt( p_intf, "repeat", var_GetBool( p_playlist, "repeat" ) );
+
+    msg_Dbg( p_intf, "Terminating" );
 
     /* unsubscribe from the interactive dialogues */
     dialog_Unregister( p_intf );
@@ -724,6 +760,14 @@ static VLCMain *_o_sharedMainInstance = nil;
     var_DelCallback(p_playlist, "mute", VolumeUpdated, self);
     var_DelCallback(p_playlist, "fullscreen", FullscreenChanged, self);
     var_DelCallback(p_intf->p_libvlc, "intf-toggle-fscontrol", ShowController, self);
+    var_DelCallback(p_intf->p_libvlc, "intf-show", ShowController, self);
+
+    if( p_current_input )
+    {
+        var_DelCallback( p_current_input, "intf-event", InputEvent, [VLCMain sharedInstance] );
+        vlc_object_release( p_current_input );
+        p_current_input = NULL;
+    }
 
     /* remove global observer watching for vout device changes correctly */
     [[NSNotificationCenter defaultCenter] removeObserver: self];
@@ -750,13 +794,13 @@ static VLCMain *_o_sharedMainInstance = nil;
     [o_embedded_list release];
     [o_coredialogs release];
     [o_eyetv release];
-    [o_mainwindow release];
 
     /* unsubscribe from libvlc's debug messages */
-    vlc_Unsubscribe( p_intf->p_sys->p_sub );
+    vlc_Unsubscribe( &p_intf->p_sys->sub );
 
     [o_msg_arr removeAllObjects];
     [o_msg_arr release];
+    o_msg_arr = NULL;
 
     [o_msg_lock release];
 
@@ -768,11 +812,11 @@ static VLCMain *_o_sharedMainInstance = nil;
     [o_mainmenu releaseRepresentedObjects:[NSApp mainMenu]];
     [o_mainmenu release];
 
-    /* Kill the playlist, so that it doesn't accept new request
-     * such as the play request from vlc.c (we are a blocking interface). */
-    vlc_object_kill( p_playlist );
     libvlc_Quit( p_intf->p_libvlc );
 
+    [o_mainwindow release];
+    o_mainwindow = NULL;
+
     [self setIntf:nil];
 }
 
@@ -783,7 +827,7 @@ static VLCMain *_o_sharedMainInstance = nil;
 {
     [NSApp activateIgnoringOtherApps:YES];
     [o_remote stopListening: self];
-    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_STOP );
+    [[VLCCoreInteraction sharedInstance] stop];
 }
 
 #pragma mark -
@@ -801,15 +845,15 @@ static VLCMain *_o_sharedMainInstance = nil;
         int keyRepeat = (keyFlags & 0x1);
 
         if( keyCode == NX_KEYTYPE_PLAY && keyState == 0 )
-            var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE );
+            [[VLCCoreInteraction sharedInstance] play];
 
-        if( keyCode == NX_KEYTYPE_FAST && !b_mediakeyJustJumped )
+        if( (keyCode == NX_KEYTYPE_FAST || keyCode == NX_KEYTYPE_NEXT) && !b_mediakeyJustJumped )
         {
             if( keyState == 0 && keyRepeat == 0 )
-                var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_NEXT );
+                [[VLCCoreInteraction sharedInstance] next];
             else if( keyRepeat == 1 )
             {
-                var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_SHORT );
+                [[VLCCoreInteraction sharedInstance] forwardShort];
                 b_mediakeyJustJumped = YES;
                 [self performSelector:@selector(resetMediaKeyJump)
                            withObject: NULL
@@ -817,13 +861,13 @@ static VLCMain *_o_sharedMainInstance = nil;
             }
         }
 
-        if( keyCode == NX_KEYTYPE_REWIND && !b_mediakeyJustJumped )
+        if( (keyCode == NX_KEYTYPE_REWIND || keyCode == NX_KEYTYPE_PREVIOUS) && !b_mediakeyJustJumped )
         {
             if( keyState == 0 && keyRepeat == 0 )
-                var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PREV );
+                [[VLCCoreInteraction sharedInstance] previous];
             else if( keyRepeat == 1 )
             {
-                var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_SHORT );
+                [[VLCCoreInteraction sharedInstance] backwardShort];
                 b_mediakeyJustJumped = YES;
                 [self performSelector:@selector(resetMediaKeyJump)
                            withObject: NULL
@@ -841,8 +885,8 @@ static VLCMain *_o_sharedMainInstance = nil;
 - (void)applicationDidBecomeActive:(NSNotification *)aNotification
 {
     if( !p_intf ) return;
-       if( config_GetInt( p_intf, "macosx-appleremote" ) == YES )
-               [o_remote startListening: self];
+    if( config_GetInt( p_intf, "macosx-appleremote" ) == YES )
+        [o_remote startListening: self];
 }
 - (void)applicationDidResignActive:(NSNotification *)aNotification
 {
@@ -853,16 +897,7 @@ static VLCMain *_o_sharedMainInstance = nil;
 /* Triggered when the computer goes to sleep */
 - (void)computerWillSleep: (NSNotification *)notification
 {
-    input_thread_t * p_input;
-
-    p_input = pl_CurrentInput( p_intf );
-    if( p_input )
-    {
-        int state = var_GetInteger( p_input, "state" );
-        if( state == PLAYING_S )
-            var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE );
-        vlc_object_release( p_input );
-    }
+    [[VLCCoreInteraction sharedInstance] pause];
 }
 
 #pragma mark -
@@ -875,6 +910,22 @@ static VLCMain *_o_sharedMainInstance = nil;
     if( !psz_uri )
         return( FALSE );
 
+    input_thread_t * p_input = pl_CurrentInput( VLCIntf );
+    BOOL b_returned = NO;
+
+    if (p_input)
+    {
+        b_returned = input_AddSubtitle( p_input, psz_uri, true );
+        vlc_object_release( p_input );
+        if(!b_returned)
+        {
+            free( psz_uri );
+            return YES;
+        }
+    }
+    else if( p_input )
+        vlc_object_release( p_input );
+
     NSDictionary *o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
 
     free( psz_uri );
@@ -994,7 +1045,7 @@ static VLCMain *_o_sharedMainInstance = nil;
 
     if( psz != NULL )
     {
-        o_str = [NSString stringWithCString: psz encoding:NSUTF8StringEncoding];
+        o_str = [NSString stringWithCString: _(psz) encoding:NSUTF8StringEncoding];
 
         if( o_str == NULL )
         {
@@ -1246,8 +1297,8 @@ unsigned int CocoaKeyToVLC( unichar i_key )
     unsigned int i_pressed_modifiers = 0;
     const struct hotkey *p_hotkeys;
     int i;
-    NSMutableString *tempString = [[[NSMutableString alloc] init] autorelease];
-    NSMutableString *tempStringPlus = [[[NSMutableString alloc] init] autorelease];
+    NSMutableString *tempString = [[NSMutableString alloc] init];
+    NSMutableString *tempStringPlus = [[NSMutableString alloc] init];
 
     val.i_int = 0;
     p_hotkeys = p_intf->p_libvlc->p_hotkeys;
@@ -1280,6 +1331,15 @@ unsigned int CocoaKeyToVLC( unichar i_key )
 
     key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
 
+    /* handle Lion's default key combo for fullscreen-toggle in addition to our own hotkeys */
+    if( key == 'f' && i_pressed_modifiers & NSControlKeyMask && i_pressed_modifiers & NSCommandKeyMask )
+    {
+        [[VLCCoreInteraction sharedInstance] toggleFullscreen];
+        [tempString release];
+        [tempStringPlus release];
+        return YES;
+    }
+
     switch( key )
     {
         case NSDeleteCharacter:
@@ -1292,12 +1352,16 @@ unsigned int CocoaKeyToVLC( unichar i_key )
         case NSLeftArrowFunctionKey:
         case NSEnterCharacter:
         case NSCarriageReturnCharacter:
+            [tempString release];
+            [tempStringPlus release];
             return NO;
     }
 
     if( key == 0x0020 ) // space key
     {
         [[VLCCoreInteraction sharedInstance] play];
+        [tempString release];
+        [tempStringPlus release];
         return YES;
     }
 
@@ -1306,9 +1370,13 @@ unsigned int CocoaKeyToVLC( unichar i_key )
     if( [o_usedHotkeys indexOfObject: tempString] != NSNotFound || [o_usedHotkeys indexOfObject: tempStringPlus] != NSNotFound )
     {
         var_SetInteger( p_intf->p_libvlc, "key-pressed", val.i_int );
+        [tempString release];
+        [tempStringPlus release];
         return YES;
     }
 
+    [tempString release];
+    [tempStringPlus release];
     return NO;
 }
 
@@ -1336,7 +1404,8 @@ unsigned int CocoaKeyToVLC( unichar i_key )
         }
     }
     module_config_free (p_config);
-    o_usedHotkeys = [[NSArray alloc] initWithArray: o_usedHotkeys copyItems: YES];
+    o_usedHotkeys = [[NSArray alloc] initWithArray: o_tempArray copyItems: YES];
+    [o_tempArray release];
 }
 
 #pragma mark -
@@ -1346,9 +1415,13 @@ unsigned int CocoaKeyToVLC( unichar i_key )
     playlist_t * p_playlist = pl_Get( VLCIntf );
     BOOL b_fullscreen = var_GetBool( p_playlist, "fullscreen" );
 
-    if (OSX_LION && b_nativeFullscreenMode)
+    if (b_nativeFullscreenMode)
     {
-        [o_mainwindow toggleFullScreen: self];
+        // this is called twice in certain situations, so only toogle if we really need to
+        if( (  b_fullscreen && !([NSApp currentSystemPresentationOptions] & NSApplicationPresentationFullScreen) ) || 
+            ( !b_fullscreen &&  ([NSApp currentSystemPresentationOptions] & NSApplicationPresentationFullScreen) ) )
+            [o_mainwindow toggleFullScreen: self];
+
         if(b_fullscreen)
             [NSApp setPresentationOptions:(NSApplicationPresentationFullScreen | NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
         else
@@ -1356,35 +1429,51 @@ unsigned int CocoaKeyToVLC( unichar i_key )
     }
     else
     {
-        input_thread_t * p_input = pl_CurrentInput( VLCIntf );
-
-        if( p_input != NULL && [self activeVideoPlayback])
+        if( b_fullscreen )
         {
-            if(b_fullscreen)
+            input_thread_t * p_input = pl_CurrentInput( VLCIntf );
+            if( p_input != NULL && [self activeVideoPlayback] )
+            {
                 [o_mainwindow performSelectorOnMainThread:@selector(enterFullscreen) withObject:nil waitUntilDone:NO];
-            else
-                [o_mainwindow performSelectorOnMainThread:@selector(leaveFullscreen) withObject:nil waitUntilDone:NO];
-            vlc_object_release( p_input );
+            }
+            if (p_input)
+                vlc_object_release( p_input );
+        }
+        else
+        {
+            // leaving fullscreen is always allowed
+            [o_mainwindow performSelectorOnMainThread:@selector(leaveFullscreen) withObject:nil waitUntilDone:NO];
         }
     }
 }
 
 - (void)PlaylistItemChanged
 {
-    input_thread_t * p_input;
+    if( p_current_input && ( p_current_input->b_dead || !vlc_object_alive( p_current_input ) ))
+    {
+        var_DelCallback( p_current_input, "intf-event", InputEvent, [VLCMain sharedInstance] );
+        vlc_object_release( p_current_input );
+        p_current_input = NULL;
 
-    p_input = playlist_CurrentInput( pl_Get(VLCIntf) );
-    if( p_input && !( p_input->b_dead || !vlc_object_alive(p_input) ) )
+        [o_mainmenu setRateControlsEnabled: NO];
+    }
+    else if( !p_current_input )
     {
-        var_AddCallback( p_input, "intf-event", InputEvent, [VLCMain sharedInstance] );
-        [o_mainmenu setRateControlsEnabled: YES];
-        vlc_object_release( p_input );
+        // object is hold here and released then it is dead
+        p_current_input = playlist_CurrentInput( pl_Get( VLCIntf ));
+        if( p_current_input )
+        {
+            var_AddCallback( p_current_input, "intf-event", InputEvent, [VLCMain sharedInstance] );
+            [self playbackStatusUpdated];
+            [o_mainmenu setRateControlsEnabled: YES];
+            if ( [self activeVideoPlayback] && [[o_mainwindow videoView] isHidden] )
+                [o_mainwindow performSelectorOnMainThread:@selector(togglePlaylist:) withObject: nil waitUntilDone:NO];
+        }
     }
-    else
-        [o_mainmenu setRateControlsEnabled: NO];
 
     [o_playlist updateRowSelection];
     [o_mainwindow updateWindow];
+    [self updateDelays];
     [self updateMainMenu];
 }
 
@@ -1399,9 +1488,14 @@ unsigned int CocoaKeyToVLC( unichar i_key )
     [o_mainwindow updateWindow];
 }
 
+- (void)showMainWindow
+{
+    [o_mainwindow performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:NO];
+}
+
 - (void)showFullscreenController
 {
-    [o_mainwindow showFullscreenController];
+    [o_mainwindow performSelectorOnMainThread:@selector(showFullscreenController) withObject:nil waitUntilDone:NO];
 }
 
 - (void)updateDelays
@@ -1422,7 +1516,7 @@ unsigned int CocoaKeyToVLC( unichar i_key )
     p_input = pl_CurrentInput( p_intf );
     if( p_input )
     {
-        if( var_GetInteger( p_input, "state" ) == PLAYING_S )
+        if( var_GetInteger( p_input, "state" ) == PLAYING_S && [self activeVideoPlayback] )
             UpdateSystemActivity( UsrActivity );
         vlc_object_release( p_input );
     }
@@ -1475,6 +1569,15 @@ unsigned int CocoaKeyToVLC( unichar i_key )
     }
 
     [[VLCMain sharedInstance] performSelectorOnMainThread:@selector(updateMainWindow) withObject: nil waitUntilDone: NO];
+    [self performSelectorOnMainThread:@selector(sendDistributedNotificationWithUpdatedPlaybackStatus) withObject: nil waitUntilDone: NO];
+}
+
+- (void)sendDistributedNotificationWithUpdatedPlaybackStatus
+{
+    [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"VLCPlayerStateDidChange"
+                                                                   object:nil
+                                                                 userInfo:nil
+                                                       deliverImmediately:YES];
 }
 
 - (void)playbackModeUpdated
@@ -1507,6 +1610,11 @@ unsigned int CocoaKeyToVLC( unichar i_key )
     return o_mainmenu;
 }
 
+- (id)mainWindow
+{
+    return o_mainwindow;
+}
+
 - (id)controls
 {
     if( o_controls )
@@ -1593,7 +1701,7 @@ unsigned int CocoaKeyToVLC( unichar i_key )
 
 - (id)getVideoViewAtPositionX: (int *)pi_x Y: (int *)pi_y withWidth: (unsigned int*)pi_width andHeight: (unsigned int*)pi_height
 {
-    id videoView = [o_mainwindow videoView];
+    id videoView = [o_mainwindow setupVideoView];
     NSRect videoRect = [videoView frame];
     int i_x = (int)videoRect.origin.x;
     int i_y = (int)videoRect.origin.y;
@@ -1638,14 +1746,17 @@ unsigned int CocoaKeyToVLC( unichar i_key )
 
 - (id)appleRemoteController
 {
-       return o_remote;
+    return o_remote;
 }
 
 - (void)setActiveVideoPlayback:(BOOL)b_value
 {
     b_active_videoplayback = b_value;
-    [o_mainwindow setVideoplayEnabled];
-    [o_mainwindow togglePlaylist:nil];
+    if( o_mainwindow )
+    {
+        [o_mainwindow performSelectorOnMainThread:@selector(setVideoplayEnabled) withObject:nil waitUntilDone:YES];
+        [o_mainwindow performSelectorOnMainThread:@selector(togglePlaylist:) withObject:nil waitUntilDone:NO];
+    }
 }
 
 - (BOOL)activeVideoPlayback
@@ -1795,42 +1906,55 @@ unsigned int CocoaKeyToVLC( unichar i_key )
 - (void)_removeOldPreferences
 {
     static NSString * kVLCPreferencesVersion = @"VLCPreferencesVersion";
-    static const int kCurrentPreferencesVersion = 1;
+    static const int kCurrentPreferencesVersion = 2;
     int version = [[NSUserDefaults standardUserDefaults] integerForKey:kVLCPreferencesVersion];
     if( version >= kCurrentPreferencesVersion ) return;
 
-    NSArray *libraries = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
-        NSUserDomainMask, YES);
-    if( !libraries || [libraries count] == 0) return;
-    NSString * preferences = [[libraries objectAtIndex:0] stringByAppendingPathComponent:@"Preferences"];
-
-    /* File not found, don't attempt anything */
-    if(![[NSFileManager defaultManager] fileExistsAtPath:[preferences stringByAppendingPathComponent:@"VLC"]] &&
-       ![[NSFileManager defaultManager] fileExistsAtPath:[preferences stringByAppendingPathComponent:@"org.videolan.vlc.plist"]] )
+    if( version == 1 )
     {
         [[NSUserDefaults standardUserDefaults] setInteger:kCurrentPreferencesVersion forKey:kVLCPreferencesVersion];
-        return;
-    }
+        [[NSUserDefaults standardUserDefaults] synchronize];
 
-    int res = NSRunInformationalAlertPanel(_NS("Remove old preferences?"),
-                _NS("We just found an older version of VLC's preferences files."),
-                _NS("Move To Trash and Relaunch VLC"), _NS("Ignore"), nil, nil);
-    if( res != NSOKButton )
-    {
-        [[NSUserDefaults standardUserDefaults] setInteger:kCurrentPreferencesVersion forKey:kVLCPreferencesVersion];
-        return;
+        if (![[VLCCoreInteraction sharedInstance] fixPreferences])
+            return;
+        else
+            config_SaveConfigFile( VLCIntf ); // we need to do manually, since we won't quit libvlc cleanly
     }
+    else
+    {
+        NSArray *libraries = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
+            NSUserDomainMask, YES);
+        if( !libraries || [libraries count] == 0) return;
+        NSString * preferences = [[libraries objectAtIndex:0] stringByAppendingPathComponent:@"Preferences"];
+
+        /* File not found, don't attempt anything */
+        if(![[NSFileManager defaultManager] fileExistsAtPath:[preferences stringByAppendingPathComponent:@"org.videolan.vlc"]] &&
+           ![[NSFileManager defaultManager] fileExistsAtPath:[preferences stringByAppendingPathComponent:@"org.videolan.vlc.plist"]] )
+        {
+            [[NSUserDefaults standardUserDefaults] setInteger:kCurrentPreferencesVersion forKey:kVLCPreferencesVersion];
+            return;
+        }
 
-    NSArray * ourPreferences = [NSArray arrayWithObjects:@"org.videolan.vlc.plist", @"VLC", nil];
+        int res = NSRunInformationalAlertPanel(_NS("Remove old preferences?"),
+                    _NS("We just found an older version of VLC's preferences files."),
+                    _NS("Move To Trash and Relaunch VLC"), _NS("Ignore"), nil, nil);
+        if( res != NSOKButton )
+        {
+            [[NSUserDefaults standardUserDefaults] setInteger:kCurrentPreferencesVersion forKey:kVLCPreferencesVersion];
+            return;
+        }
 
-    /* Move the file to trash so that user can find them later */
-    [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:preferences destination:nil files:ourPreferences tag:0];
+        NSArray * ourPreferences = [NSArray arrayWithObjects:@"org.videolan.vlc.plist", @"VLC", @"org.videolan.vlc", nil];
 
-    /* really reset the defaults from now on */
-    [NSUserDefaults resetStandardUserDefaults];
+        /* Move the file to trash so that user can find them later */
+        [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:preferences destination:nil files:ourPreferences tag:0];
 
-    [[NSUserDefaults standardUserDefaults] setInteger:kCurrentPreferencesVersion forKey:kVLCPreferencesVersion];
-    [[NSUserDefaults standardUserDefaults] synchronize];
+        /* really reset the defaults from now on */
+        [NSUserDefaults resetStandardUserDefaults];
+
+        [[NSUserDefaults standardUserDefaults] setInteger:kCurrentPreferencesVersion forKey:kVLCPreferencesVersion];
+        [[NSUserDefaults standardUserDefaults] synchronize];
+    }
 
     /* Relaunch now */
     const char * path = [[[NSBundle mainBundle] executablePath] UTF8String];
@@ -1846,15 +1970,9 @@ unsigned int CocoaKeyToVLC( unichar i_key )
 
 #pragma mark -
 #pragma mark Errors, warnings and messages
-- (IBAction)liveUpdateMessagesPanel:(id)sender
+- (IBAction)updateMessagesPanel:(id)sender
 {
-    if ([[NSUserDefaults standardUserDefaults] boolForKey:@"LiveUpdateTheMessagesPanel"])
-        [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"LiveUpdateTheMessagesPanel"];
-    else
-        [[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"LiveUpdateTheMessagesPanel"];
-
-    b_msg_live_update = [[NSUserDefaults standardUserDefaults] boolForKey:@"LiveUpdateTheMessagesPanel"];
-    [o_msgs_liveUpdate_ckb setState: b_msg_live_update];
+    [self windowDidBecomeKey:nil];
 }
 
 - (IBAction)showMessagesPanel:(id)sender
@@ -1864,64 +1982,67 @@ unsigned int CocoaKeyToVLC( unichar i_key )
 
 - (void)windowDidBecomeKey:(NSNotification *)o_notification
 {
-    if( [o_notification object] == o_msgs_panel )
-        [self updateMessageDisplay];
+    [o_msgs_table reloadData];
+    [o_msgs_table scrollRowToVisible: [o_msg_arr count] - 1];
 }
 
-- (void)updateMessageDisplay
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
 {
-    if( [o_msgs_panel isVisible] && (b_msg_live_update || [o_msgs_panel isKeyWindow]) && b_msg_arr_changed )
-    {
-        id o_msg;
-        NSEnumerator * o_enum;
-
-        [o_messages setString: @""];
-
-        [o_msg_lock lock];
+    if (aTableView == o_msgs_table)
+        return [o_msg_arr count];
+    return 0; 
+}
 
-        o_enum = [o_msg_arr objectEnumerator];
+- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
+{
+    NSMutableAttributedString *result = NULL;
 
-        while( ( o_msg = [o_enum nextObject] ) != NULL )
-            [o_messages insertText: o_msg];
+    [o_msg_lock lock];
+    if( rowIndex < [o_msg_arr count] )
+        result = [o_msg_arr objectAtIndex: rowIndex];
+    [o_msg_lock unlock];
 
-        b_msg_arr_changed = NO;
-        [o_msg_lock unlock];
-    }
+    if( result != NULL )
+        return result;
+    else
+        return @"";
 }
 
 - (void)processReceivedlibvlcMessage:(const msg_item_t *) item ofType: (int)i_type withStr: (char *)str
 {
-    NSColor *o_white = [NSColor whiteColor];
-    NSColor *o_red = [NSColor redColor];
-    NSColor *o_yellow = [NSColor yellowColor];
-    NSColor *o_gray = [NSColor grayColor];
-
-    NSColor * pp_color[4] = { o_white, o_red, o_yellow, o_gray };
-    static const char * ppsz_type[4] = { ": ", " error: ", " warning: ", " debug: " };
-
-    NSDictionary *o_attr;
-    NSAttributedString *o_msg_color;
+    if (o_msg_arr)
+    {
+        NSColor *o_white = [NSColor whiteColor];
+        NSColor *o_red = [NSColor redColor];
+        NSColor *o_yellow = [NSColor yellowColor];
+        NSColor *o_gray = [NSColor grayColor];
+        NSString * firstString, * secondString;
 
-    [o_msg_lock lock];
+        NSColor * pp_color[4] = { o_white, o_red, o_yellow, o_gray };
+        static const char * ppsz_type[4] = { ": ", " error: ", " warning: ", " debug: " };
 
-    if( [o_msg_arr count] + 2 > 600 )
-    {
-        [o_msg_arr removeObjectAtIndex: 0];
-        [o_msg_arr removeObjectAtIndex: 1];
-    }
+        NSDictionary *o_attr;
+        NSMutableAttributedString *o_msg_color;
 
-    o_attr = [NSDictionary dictionaryWithObject: pp_color[3] forKey: NSForegroundColorAttributeName];
-    o_msg_color = [[NSAttributedString alloc] initWithString: [NSString stringWithFormat: @"%s%s", item->psz_module, ppsz_type[i_type]] attributes: o_attr];
-    [o_msg_arr addObject: [o_msg_color autorelease]];
+        [o_msg_lock lock];
 
-    o_attr = [NSDictionary dictionaryWithObject: pp_color[i_type] forKey: NSForegroundColorAttributeName];
-    o_msg_color = [[NSAttributedString alloc] initWithString: [NSString stringWithFormat: @"%s\n", str] attributes: o_attr];
-    [o_msg_arr addObject: [o_msg_color autorelease]];
+        if( [o_msg_arr count] + 2 > 600 )
+        {
+            [o_msg_arr removeObjectAtIndex: 0];
+            [o_msg_arr removeObjectAtIndex: 1];
+        }
+        firstString = [NSString stringWithFormat:@"%s%s", item->psz_module, ppsz_type[i_type]];
+        secondString = [NSString stringWithFormat:@"%@%s\n", firstString, str];
 
-    b_msg_arr_changed = YES;
-    [o_msg_lock unlock];
+        o_attr = [NSDictionary dictionaryWithObject: pp_color[i_type]  forKey: NSForegroundColorAttributeName];
+        o_msg_color = [[NSMutableAttributedString alloc] initWithString: secondString attributes: o_attr];
+        o_attr = [NSDictionary dictionaryWithObject: pp_color[3] forKey: NSForegroundColorAttributeName];
+        [o_msg_color setAttributes: o_attr range: NSMakeRange( 0, [firstString length] )];
+        [o_msg_arr addObject: [o_msg_color autorelease]];
 
-    [self performSelectorOnMainThread:@selector(updateMessageDisplay) withObject: nil waitUntilDone:NO];
+        b_msg_arr_changed = YES;
+        [o_msg_lock unlock];
+    }
 }
 
 - (IBAction)saveDebugLog:(id)sender
@@ -1939,7 +2060,15 @@ unsigned int CocoaKeyToVLC( unichar i_key )
     BOOL b_returned;
     if( returnCode == NSOKButton )
     {
-        b_returned = [o_messages writeRTFDToFile: [[sheet URL] path] atomically: YES];
+        NSUInteger count = [o_msg_arr count];
+        NSMutableAttributedString * string = [[NSMutableAttributedString alloc] init];
+        for (NSUInteger i = 0; i < count; i++)
+        {
+            [string appendAttributedString: [o_msg_arr objectAtIndex: i]];
+        }
+        b_returned = [[string RTFDFileWrapperFromRange:NSMakeRange( 0, [string length] ) documentAttributes:[NSDictionary dictionaryWithObject: NSRTFDTextDocumentType forKey: NSDocumentTypeDocumentAttribute]] writeToFile:[[sheet URL] path] atomically:YES updateFilenames:NO];
+        [string release];
+
         if(! b_returned )
             msg_Warn( p_intf, "Error while saving the debug log" );
     }
@@ -1985,30 +2114,14 @@ unsigned int CocoaKeyToVLC( unichar i_key )
 - (void)coreChangedMediaKeySupportSetting: (NSNotification *)o_notification
 {
     b_mediaKeySupport = config_GetInt( VLCIntf, "macosx-mediakeys" );
-    if (b_mediaKeySupport) {
+    if (b_mediaKeySupport)
+    {
         if (!o_mediaKeyController)
             o_mediaKeyController = [[SPMediaKeyTap alloc] initWithDelegate:self];
         [o_mediaKeyController startWatchingMediaKeys];
     }
     else if (!b_mediaKeySupport && o_mediaKeyController)
-    {
-        int returnedValue = NSRunInformationalAlertPanel(_NS("Relaunch required"),
-                                               _NS("To make sure that VLC no longer listens to your media key events, it needs to be restarted."),
-                                               _NS("Relaunch VLC"), _NS("Ignore"), nil, nil);
-        if( returnedValue == NSOKButton )
-        {
-            /* Relaunch now */
-            const char * path = [[[NSBundle mainBundle] executablePath] UTF8String];
-
-            /* For some reason we need to fork(), not just execl(), which reports a ENOTSUP then. */
-            if(fork() != 0)
-            {
-                exit(0);
-                return;
-            }
-            execl(path, path, NULL);
-        }
-    }
+        [o_mediaKeyController stopWatchingMediaKeys];
 }
 
 @end
@@ -2021,7 +2134,7 @@ unsigned int CocoaKeyToVLC( unichar i_key )
 // when user selects the quit menu from dock it sends a terminate:
 // but we need to send a stop: to properly exits libvlc.
 // However, we are not able to change the action-method sent by this standard menu item.
-// thus we override terminat: to send a stop:
+// thus we override terminate: to send a stop:
 // see [af97f24d528acab89969d6541d83f17ce1ecd580] that introduced the removal of setjmp() and longjmp()
 - (void)terminate:(id)sender
 {