* OSX lowlevel work
authorDerk-Jan Hartman <hartman@videolan.org>
Mon, 5 Jul 2004 01:27:35 +0000 (01:27 +0000)
committerDerk-Jan Hartman <hartman@videolan.org>
Mon, 5 Jul 2004 01:27:35 +0000 (01:27 +0000)
  - The VLCApplication is now launched at the vlc.c level instead of at the module level. Allows VLC to be a more valid Mac application, also removes the vout intf dependancy (use ncurses to disp. video :).
    This wasn't done at the libvlc level, because a mozilla plugin would no longer be able to function properly.
  - Some functionality of the macosx vout may not work without the OS X GUI, and not all of this is checked yet.
  - There is a symlink in VLC.app/Contents/Mac called clivlc that will force it back to a fullblown cli app when you want, so it can still be run by a user who isn't logged in via GUI.
  - there are some autorelease leaks which need to be tackled.
  - moved a lot of the VLCApplication func. to the VLCMain class.
  - VLCMain is a +sharedInstance now.
  - the complete OS X interface is still badly broken because of the many API changes lately. any volunteers?

Examples:
VLC.app/Contents/MacOS/VLC [-I macosx]
launches VLC as before (requires you to be logged in via GUI)

VLC.app/Contents/MacOS/VLC -I ncurses
launch vlc with a ncurses intf and display video on your mac
(requires you to be logged in via GUI)

VLC.app/Contents/MacOS/clivlc -I telnet -d
launch vlm remotely trough ssh in daemon mode, on a GUI'less server for instance, and stream your vids

Now how is that for combining GUI and cli in one application on the mac?!!? :)
jlj? I finally understand now how the OS X interface works !

18 files changed:
Makefile.am
TODO
configure.ac
extras/MacOSX/Resources/English.lproj/MainMenu.nib/info.nib
extras/MacOSX/Resources/English.lproj/MainMenu.nib/objects.nib
modules/gui/macosx/applescript.m
modules/gui/macosx/controls.m
modules/gui/macosx/intf.h
modules/gui/macosx/intf.m
modules/gui/macosx/misc.m
modules/gui/macosx/open.m
modules/gui/macosx/output.m
modules/gui/macosx/playlist.m
modules/gui/macosx/playlistinfo.m
modules/gui/macosx/prefs.m
modules/gui/macosx/vout.m
src/interface/interface.c
src/vlc.c

index b138d67..79d2a61 100644 (file)
@@ -492,6 +492,7 @@ VLC.app: vlc
        $(INSTALL) -d $(top_builddir)/VLC.app/Contents/MacOS
        $(INSTALL) $(top_builddir)/vlc \
                   $(top_builddir)/VLC.app/Contents/MacOS/VLC
+       ln -sf ./VLC $(top_builddir)/VLC.app/Contents/MacOS/clivlc
        $(INSTALL) -d $(top_builddir)/VLC.app/Contents/MacOS/modules
        for i in "" `$(VLC_CONFIG) --target plugin` ; do \
          if test -n "$$i" ; \
diff --git a/TODO b/TODO
index a68e63f..1db3c5f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -183,6 +183,13 @@ Description: DVB info in NIT
 We need to get the information of a DVB stream that are in the NIT (current program, next program, ...)
 Status: Todo
 
+Task
+Difficulty: Medium
+Urgency: Wishlist
+Platform: any
+Description: IceCast/ShoutCast serving
+This would be a nice thing for the sake of completeness of VLC's streaming capabilities.
+Status: Todo
 
 Task
 Difficulty: Hard
index 57f2028..d3f2901 100644 (file)
@@ -120,6 +120,7 @@ case "${target_os}" in
     OBJCFLAGS_save="${OBJCFLAGS_save} -no-cpp-precomp -D_INTL_REDIRECT_MACROS"; OBJCFLAGS="${OBJCFLAGS_save}"
     VLC_ADD_LDFLAGS([vlc ffmpeg],[-all_load])
     VLC_ADD_LDFLAGS([mp4], [-framework IOKit -framework CoreFoundation])
+    VLC_ADD_CFLAGS([vlc],[-x objective-c])
     VLC_ADD_LDFLAGS([vlc],[-Wl,-multiply_defined,suppress])
     ;;
   *mingw32* | *cygwin*)
@@ -1237,7 +1238,6 @@ then
         ],[
           if test -n "${enable_dvdread}"
           then
-            AC_MSG_WARN([Please get libdvdread from http://www.dtek.chalmers.se/groups/dvd/downloads.shtml])
             AC_MSG_ERROR([cannot find libdvdread headers])
           fi
         ])
index c3a0574..d281f30 100644 (file)
        </array>
        <key>IBOpenObjects</key>
        <array>
-               <integer>29</integer>
-               <integer>1617</integer>
                <integer>21</integer>
+               <integer>1617</integer>
                <integer>1647</integer>
+               <integer>29</integer>
        </array>
        <key>IBSystem Version</key>
-       <string>7F44</string>
+       <string>7H63</string>
 </dict>
 </plist>
index f19413d..fda4eaf 100644 (file)
Binary files a/extras/MacOSX/Resources/English.lproj/MainMenu.nib/objects.nib and b/extras/MacOSX/Resources/English.lproj/MainMenu.nib/objects.nib differ
index 5cade7a..af3fbba 100644 (file)
@@ -41,7 +41,7 @@
 
     if ( [o_command isEqualToString:@"GetURL"] || [o_command isEqualToString:@"OpenURL"] )
     {
-        intf_thread_t * p_intf = [NSApp getIntf];
+        intf_thread_t * p_intf = VLCIntf;
         playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                         FIND_ANYWHERE );
         if( p_playlist == NULL )
@@ -84,7 +84,7 @@
 - (id)performDefaultImplementation {
     NSString *o_command = [[self commandDescription] commandName];
 
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                     FIND_ANYWHERE );
     if( p_playlist == NULL )
index b355a43..fa0e67b 100644 (file)
@@ -45,7 +45,7 @@
 {
     vlc_value_t val;
     playlist_t * p_playlist;
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                        FIND_ANYWHERE );
 
@@ -87,7 +87,7 @@
 
 - (IBAction)stop:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
     if( p_playlist != NULL )
 
 - (IBAction)faster:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                        FIND_ANYWHERE );
     if( p_input != NULL )
 
 - (IBAction)slower:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                        FIND_ANYWHERE );
     if( p_input != NULL )
 
 - (IBAction)prev:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
     if( p_playlist )
 
 - (IBAction)next:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
     if( p_playlist )
 
 - (IBAction)random:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     vlc_value_t val;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
 - (IBAction)repeat:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     vlc_value_t val;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
 - (IBAction)loop:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     vlc_value_t val;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
 - (IBAction)forward:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                        FIND_ANYWHERE );
     if( p_input != NULL )
 
 - (IBAction)backward:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                        FIND_ANYWHERE );
     if( p_input != NULL )
 
 - (IBAction)volumeUp:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
 
     if( p_intf->p_sys->b_mute )
     {
 
 - (IBAction)volumeDown:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
 
     if( p_intf->p_sys->b_mute )
     {
 
 - (IBAction)mute:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     audio_volume_t i_volume;
 
     aout_VolumeMute( p_intf, &i_volume );
 
 - (IBAction)volumeSliderUpdated:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     audio_volume_t i_volume = (audio_volume_t)[sender intValue];
 
     aout_VolumeSet( p_intf, i_volume * AOUT_VOLUME_STEP );
 
 - (void)updateVolumeSlider
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     audio_volume_t i_volume;
 
     aout_VolumeGet( p_intf, &i_volume );
     NSString *o_title = [sender title];
     NSArray *o_windows = [NSApp orderedWindows];
     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
-    vout_thread_t   *p_vout = vlc_object_find( [NSApp getIntf], VLC_OBJECT_VOUT,
+    vout_thread_t   *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT,
                                               FIND_ANYWHERE );
 
     if( p_vout != NULL )
     
     /* Get the descriptive name of the variable */
     var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
-    [o_mi setTitle: [NSApp localizedString: text.psz_string ?
+    [o_mi setTitle: [[VLCMain sharedInstance] localizedString: text.psz_string ?
                                         text.psz_string : strdup( psz_variable ) ]];
 
     var_Get( p_object, psz_variable, &val );
             another_val.psz_string =
                 strdup(val_list.p_list->p_values[i].psz_string);
 
-            o_title = [NSApp localizedString: text_list.p_list->p_values[i].psz_string ?
+            o_title = [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string ?
                 text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
 
             o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
         case VLC_VAR_INTEGER:
 
              o_title = text_list.p_list->p_values[i].psz_string ?
-                                 [NSApp localizedString: strdup( text_list.p_list->p_values[i].psz_string )] :
+                                 [[VLCMain sharedInstance] localizedString: strdup( text_list.p_list->p_values[i].psz_string )] :
                                  [NSString stringWithFormat: @"%d",
                                  val_list.p_list->p_values[i].i_int];
 
     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
     VLCMenuExt *o_data = (VLCMenuExt *)_o_data;
 
-    vlc_thread_set_priority( [NSApp getIntf] , VLC_THREAD_PRIORITY_LOW );
+    vlc_thread_set_priority( VLCIntf , VLC_THREAD_PRIORITY_LOW );
 
-    p_object = (vlc_object_t *)vlc_object_get( [NSApp getIntf],
+    p_object = (vlc_object_t *)vlc_object_get( VLCIntf,
                                     [o_data objectID] );
 
     if( p_object != NULL )
 {
     BOOL bEnabled = TRUE;
     vlc_value_t val;
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
index c57ef76..f5890b4 100644 (file)
 #include <Cocoa/Cocoa.h>
 
 /*****************************************************************************
- * VLCApplication interface
+ * Local prototypes.
  *****************************************************************************/
-@interface VLCApplication : NSApplication
-{
-    intf_thread_t *p_intf;
-}
-
-- (NSString *)localizedString:(char *)psz;
-- (char *)delocalizeString:(NSString *)psz;
-- (NSString *)wrapString: (NSString *)o_in_string toWidth: (int)i_width;
-
-- (void)setIntf:(intf_thread_t *)p_intf;
-- (intf_thread_t *)getIntf;
-- (BOOL)hasDefinedShortcutKey:(NSEvent *)o_event;
+int ExecuteOnMainThread( id target, SEL sel, void * p_arg );
+unsigned int CocoaKeyToVLC( unichar i_key );
 
-@end
+#define VLCIntf [[VLCMain sharedInstance] getIntf]
 
-#define _NS(s) [NSApp localizedString: _(s)]
+#define _NS(s) [[VLCMain sharedInstance] localizedString: _(s)]
 /* Get an alternate version of the string.
  * This string is stored as '1:string' but when displayed it only displays
  * the translated string. the translation should be '1:translatedstring' though */
-#define _ANS(s) [[NSApp localizedString: _(s)] substringFromIndex:2]
-
-int ExecuteOnMainThread( id target, SEL sel, void * p_arg );
-int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
-                     vlc_value_t old_val, vlc_value_t new_val, void *param );
-unsigned int CocoaKeyToVLC( unichar i_key );
+#define _ANS(s) [[[VLCMain sharedInstance] localizedString: _(s)] substringFromIndex:2]
 
 /*****************************************************************************
  * intf_sys_t: description and status of the interface
@@ -92,6 +77,7 @@ struct intf_sys_t
  *****************************************************************************/
 @interface VLCMain : NSObject
 {
+    intf_thread_t *p_intf;      /* The main intf object */
     id o_prefs;                 /* VLCPrefs       */
 
     IBOutlet id o_window;       /* main window    */
@@ -238,10 +224,19 @@ struct intf_sys_t
     IBOutlet id o_dmi_mute;
 }
 
++ (VLCMain *)sharedInstance;
+
+- (intf_thread_t *)getIntf;
+- (void)setIntf:(intf_thread_t *)p_mainintf;
+
 - (id)getControls;
 - (id)getPlaylist;
 - (id)getInfo;
 - (void)terminate;
+- (NSString *)localizedString:(char *)psz;
+- (char *)delocalizeString:(NSString *)psz;
+- (NSString *)wrapString: (NSString *)o_in_string toWidth: (int)i_width;
+- (BOOL)hasDefinedShortcutKey:(NSEvent *)o_event;
 
 - (void)initStrings;
 
index 8a1f567..377d5f8 100644 (file)
@@ -70,10 +70,7 @@ int E_(OpenIntf) ( vlc_object_t *p_this )
     p_intf->b_play = VLC_TRUE;
     p_intf->pf_run = Run;
     
-    [VLCApplication sharedApplication];
-    [NSApp setIntf: p_intf];
-
-    [NSBundle loadNibNamed: @"MainMenu" owner: NSApp];
+    [[VLCMain sharedInstance] setIntf: p_intf];
 
     return( 0 );
 }
@@ -102,162 +99,9 @@ static void Run( intf_thread_t *p_intf )
      * fails to go to real-time priority with the first launched thread
      * (???) --Meuuh */
     vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
-
-    [NSApp run];
-}
-
-/*****************************************************************************
- * VLCApplication implementation 
- *****************************************************************************/
-@implementation VLCApplication
-
-- (NSString *)localizedString:(char *)psz
-{
-    NSString * o_str = nil;
-
-    if( psz != NULL )
-    {
-        o_str = [[[NSString alloc] initWithUTF8String: psz] autorelease];
-    }
-    if ( o_str == NULL )
-    {
-        msg_Err( p_intf, "could not translate: %s", psz );
-    }
-
-    return( o_str );
-}
-
-- (char *)delocalizeString:(NSString *)id
-{
-    NSData * o_data = [id dataUsingEncoding: NSUTF8StringEncoding
-                          allowLossyConversion: NO];
-    char * psz_string;
-
-    if ( o_data == nil )
-    {
-        o_data = [id dataUsingEncoding: NSUTF8StringEncoding
-                     allowLossyConversion: YES];
-        psz_string = malloc( [o_data length] + 1 ); 
-        [o_data getBytes: psz_string];
-        psz_string[ [o_data length] ] = '\0';
-        msg_Err( p_intf, "cannot convert to wanted encoding: %s",
-                 psz_string );
-    }
-    else
-    {
-        psz_string = malloc( [o_data length] + 1 ); 
-        [o_data getBytes: psz_string];
-        psz_string[ [o_data length] ] = '\0';
-    }
-
-    return psz_string;
-}
-
-/* i_width is in pixels */
-- (NSString *)wrapString: (NSString *)o_in_string toWidth: (int) i_width
-{
-    NSMutableString *o_wrapped;
-    NSString *o_out_string;
-    NSRange glyphRange, effectiveRange, charRange;
-    NSRect lineFragmentRect;
-    unsigned glyphIndex, breaksInserted = 0;
-
-    NSTextStorage *o_storage = [[NSTextStorage alloc] initWithString: o_in_string
-        attributes: [NSDictionary dictionaryWithObjectsAndKeys:
-        [NSFont labelFontOfSize: 0.0], NSFontAttributeName, nil]];
-    NSLayoutManager *o_layout_manager = [[NSLayoutManager alloc] init];
-    NSTextContainer *o_container = [[NSTextContainer alloc]
-        initWithContainerSize: NSMakeSize(i_width, 2000)];
-    
-    [o_layout_manager addTextContainer: o_container];
-    [o_container release];
-    [o_storage addLayoutManager: o_layout_manager];
-    [o_layout_manager release];
-        
-    o_wrapped = [o_in_string mutableCopy];
-    glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
-    
-    for( glyphIndex = glyphRange.location ; glyphIndex < NSMaxRange(glyphRange) ;
-            glyphIndex += effectiveRange.length) {
-        lineFragmentRect = [o_layout_manager lineFragmentRectForGlyphAtIndex: glyphIndex
-                                            effectiveRange: &effectiveRange];
-        charRange = [o_layout_manager characterRangeForGlyphRange: effectiveRange
-                                    actualGlyphRange: &effectiveRange];
-        if ([o_wrapped lineRangeForRange:
-                NSMakeRange(charRange.location + breaksInserted, charRange.length)].length > charRange.length) {
-            [o_wrapped insertString: @"\n" atIndex: NSMaxRange(charRange) + breaksInserted];
-            breaksInserted++;
-        }
-    }
-    o_out_string = [NSString stringWithString: o_wrapped];
-    [o_wrapped release];
-    [o_storage release];
-    
-    return o_out_string;
-}
-
-- (void)setIntf:(intf_thread_t *)_p_intf
-{
-    p_intf = _p_intf;
-}
-
-- (intf_thread_t *)getIntf
-{
-    return( p_intf );
-}
-
-- (void)terminate:(id)sender
-{
-    p_intf->p_vlc->b_die = VLC_TRUE;
-    [super terminate:sender];
-}
-
-
-/*****************************************************************************
- * hasDefinedShortcutKey: Check to see if the key press is a defined VLC
- * shortcut key.  If it is, pass it off to VLC for handling and return YES,
- * otherwise ignore it and return NO (where it will get handled by Cocoa).
- *****************************************************************************/
-- (BOOL)hasDefinedShortcutKey:(NSEvent *)o_event
-{
-    unichar key = 0;
-    vlc_value_t val;
-    unsigned int i_pressed_modifiers = 0;
-    struct hotkey *p_hotkeys;
-    int i;
-
-    val.i_int = 0;
-    p_hotkeys = p_intf->p_vlc->p_hotkeys;
-
-    i_pressed_modifiers = [o_event modifierFlags];
-
-    if( i_pressed_modifiers & NSShiftKeyMask )
-        val.i_int |= KEY_MODIFIER_SHIFT;
-    if( i_pressed_modifiers & NSControlKeyMask )
-        val.i_int |= KEY_MODIFIER_CTRL;
-    if( i_pressed_modifiers & NSAlternateKeyMask )
-        val.i_int |= KEY_MODIFIER_ALT;
-    if( i_pressed_modifiers & NSCommandKeyMask )
-        val.i_int |= KEY_MODIFIER_COMMAND;
-
-    key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
-
-    val.i_int |= CocoaKeyToVLC( key );
-
-    for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
-    {
-        if( p_hotkeys[i].i_key == val.i_int )
-        {
-            var_Set( p_intf->p_vlc, "key-pressed", val );
-            return YES;
-        }
-    }
-
-    return NO;
+    [NSBundle loadNibNamed: @"MainMenu" owner: NSApp];
 }
 
-@end
-
 int ExecuteOnMainThread( id target, SEL sel, void * p_arg )
 {
     int i_ret = 0;
@@ -271,7 +115,7 @@ int ExecuteOnMainThread( id target, SEL sel, void * p_arg )
                 withObject: [NSValue valueWithPointer: p_arg]
                 waitUntilDone: YES];
     }
-    else if( NSApp != nil && [NSApp respondsToSelector: @selector(getIntf)] ) 
+    else if( NSApp != nil && [[VLCMain sharedInstance] respondsToSelector: @selector(getIntf)] ) 
     {
         NSValue * o_v1;
         NSValue * o_v2;
@@ -285,7 +129,7 @@ int ExecuteOnMainThread( id target, SEL sel, void * p_arg )
 
         id * val[] = { &o_lock, &o_v2 };
 
-        p_intf = (intf_thread_t *)[NSApp getIntf];
+        p_intf = (intf_thread_t *)VLCIntf;
 
         o_recv_port = [[NSPort port] retain];
         o_v1 = [NSValue valueWithPointer: val]; 
@@ -329,7 +173,7 @@ int ExecuteOnMainThread( id target, SEL sel, void * p_arg )
 int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
                      vlc_value_t old_val, vlc_value_t new_val, void *param )
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     p_intf->p_sys->b_playlist_update = TRUE;
     p_intf->p_sys->b_intf_update = TRUE;
     return VLC_SUCCESS;
@@ -417,10 +261,36 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
  *****************************************************************************/
 @implementation VLCMain
 
+static VLCMain *_o_sharedMainInstance = nil;
+
++ (VLCMain *)sharedInstance
+{
+    return _o_sharedMainInstance ? _o_sharedMainInstance : [[self alloc] init];
+}
+
+- (id)init 
+{
+    if (_o_sharedMainInstance) {
+        [self dealloc];
+    } else {
+        _o_sharedMainInstance = [super init];
+    }
+    
+    return _o_sharedMainInstance;
+}
+
+- (void)setIntf: (intf_thread_t *)p_mainintf {
+    p_intf = p_mainintf;
+}
+
+- (intf_thread_t *)getIntf {
+    return p_intf;
+}
+
 - (void)awakeFromNib
 {
     unsigned int i_key = 0;
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t *p_playlist;
     vlc_value_t val;
 
@@ -632,8 +502,6 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
 
 - (void)applicationWillFinishLaunching:(NSNotification *)o_notification
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
-
     o_msg_lock = [[NSLock alloc] init];
     o_msg_arr = [[NSMutableArray arrayWithCapacity: 200] retain];
 
@@ -659,7 +527,7 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
 
     vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
 }
-
+/*
 - (BOOL)application:(NSApplication *)o_app openFile:(NSString *)o_filename
 {
     NSDictionary *o_dic = [NSDictionary dictionaryWithObjectsAndKeys: o_filename, @"ITEM_URL", nil];
@@ -668,6 +536,135 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
             
     return( TRUE );
 }
+*/
+- (NSString *)localizedString:(char *)psz
+{
+    NSString * o_str = nil;
+
+    if( psz != NULL )
+    {
+        o_str = [[[NSString alloc] initWithUTF8String: psz] autorelease];
+    }
+    if ( o_str == NULL )
+    {
+        msg_Err( VLCIntf, "could not translate: %s", psz );
+    }
+
+    return( o_str );
+}
+
+- (char *)delocalizeString:(NSString *)id
+{
+    NSData * o_data = [id dataUsingEncoding: NSUTF8StringEncoding
+                          allowLossyConversion: NO];
+    char * psz_string;
+
+    if ( o_data == nil )
+    {
+        o_data = [id dataUsingEncoding: NSUTF8StringEncoding
+                     allowLossyConversion: YES];
+        psz_string = malloc( [o_data length] + 1 ); 
+        [o_data getBytes: psz_string];
+        psz_string[ [o_data length] ] = '\0';
+        msg_Err( VLCIntf, "cannot convert to wanted encoding: %s",
+                 psz_string );
+    }
+    else
+    {
+        psz_string = malloc( [o_data length] + 1 ); 
+        [o_data getBytes: psz_string];
+        psz_string[ [o_data length] ] = '\0';
+    }
+
+    return psz_string;
+}
+
+/* i_width is in pixels */
+- (NSString *)wrapString: (NSString *)o_in_string toWidth: (int) i_width
+{
+    NSMutableString *o_wrapped;
+    NSString *o_out_string;
+    NSRange glyphRange, effectiveRange, charRange;
+    NSRect lineFragmentRect;
+    unsigned glyphIndex, breaksInserted = 0;
+
+    NSTextStorage *o_storage = [[NSTextStorage alloc] initWithString: o_in_string
+        attributes: [NSDictionary dictionaryWithObjectsAndKeys:
+        [NSFont labelFontOfSize: 0.0], NSFontAttributeName, nil]];
+    NSLayoutManager *o_layout_manager = [[NSLayoutManager alloc] init];
+    NSTextContainer *o_container = [[NSTextContainer alloc]
+        initWithContainerSize: NSMakeSize(i_width, 2000)];
+    
+    [o_layout_manager addTextContainer: o_container];
+    [o_container release];
+    [o_storage addLayoutManager: o_layout_manager];
+    [o_layout_manager release];
+        
+    o_wrapped = [o_in_string mutableCopy];
+    glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
+    
+    for( glyphIndex = glyphRange.location ; glyphIndex < NSMaxRange(glyphRange) ;
+            glyphIndex += effectiveRange.length) {
+        lineFragmentRect = [o_layout_manager lineFragmentRectForGlyphAtIndex: glyphIndex
+                                            effectiveRange: &effectiveRange];
+        charRange = [o_layout_manager characterRangeForGlyphRange: effectiveRange
+                                    actualGlyphRange: &effectiveRange];
+        if ([o_wrapped lineRangeForRange:
+                NSMakeRange(charRange.location + breaksInserted, charRange.length)].length > charRange.length) {
+            [o_wrapped insertString: @"\n" atIndex: NSMaxRange(charRange) + breaksInserted];
+            breaksInserted++;
+        }
+    }
+    o_out_string = [NSString stringWithString: o_wrapped];
+    [o_wrapped release];
+    [o_storage release];
+    
+    return o_out_string;
+}
+
+
+/*****************************************************************************
+ * hasDefinedShortcutKey: Check to see if the key press is a defined VLC
+ * shortcut key.  If it is, pass it off to VLC for handling and return YES,
+ * otherwise ignore it and return NO (where it will get handled by Cocoa).
+ *****************************************************************************/
+- (BOOL)hasDefinedShortcutKey:(NSEvent *)o_event
+{
+    unichar key = 0;
+    vlc_value_t val;
+    unsigned int i_pressed_modifiers = 0;
+    struct hotkey *p_hotkeys;
+    int i;
+
+    val.i_int = 0;
+    p_hotkeys = VLCIntf->p_vlc->p_hotkeys;
+
+    i_pressed_modifiers = [o_event modifierFlags];
+
+    if( i_pressed_modifiers & NSShiftKeyMask )
+        val.i_int |= KEY_MODIFIER_SHIFT;
+    if( i_pressed_modifiers & NSControlKeyMask )
+        val.i_int |= KEY_MODIFIER_CTRL;
+    if( i_pressed_modifiers & NSAlternateKeyMask )
+        val.i_int |= KEY_MODIFIER_ALT;
+    if( i_pressed_modifiers & NSCommandKeyMask )
+        val.i_int |= KEY_MODIFIER_COMMAND;
+
+    key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
+
+    val.i_int |= CocoaKeyToVLC( key );
+
+    for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
+    {
+        if( p_hotkeys[i].i_key == val.i_int )
+        {
+            var_Set( VLCIntf->p_vlc, "key-pressed", val );
+            return YES;
+        }
+    }
+
+    return NO;
+}
 
 - (id)getControls
 {
@@ -699,7 +696,6 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
 - (void)manage
 {
     NSDate * o_sleep_date;
-    intf_thread_t * p_intf = [NSApp getIntf];
     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
 
     vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
@@ -769,8 +765,6 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
 
 - (void)manageIntf:(NSTimer *)o_timer
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
-
     if( p_intf->p_vlc->b_die == VLC_TRUE )
     {
         [o_timer invalidate];
@@ -950,7 +944,6 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
 
 - (void)setupMenus
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
     playlist_t *p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, 
                                                 FIND_ANYWHERE );
     
@@ -1013,7 +1006,6 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
 - (void)updateMessageArray
 {
     int i_start, i_stop;
-    intf_thread_t * p_intf = [NSApp getIntf];
     vlc_value_t quiet;
 
     vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
@@ -1131,7 +1123,6 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
 - (void)manageVolumeSlider
 {
     audio_volume_t i_volume;
-    intf_thread_t * p_intf = [NSApp getIntf];
 
     aout_VolumeGet( p_intf, &i_volume );
 
@@ -1159,7 +1150,6 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
             return;
     }
 
-    p_intf = [NSApp getIntf];
     p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                             FIND_ANYWHERE );
 
@@ -1194,10 +1184,8 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
 
 - (void)terminate
 {
-    NSEvent * o_event;
     playlist_t * p_playlist;
     vout_thread_t * p_vout;
-    intf_thread_t * p_intf = [NSApp getIntf];
 
     /* Stop playback */
     if( ( p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
@@ -1257,19 +1245,11 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
         o_msg_lock = nil;
     }
 
-    [NSApp stop: nil];
-    [NSApp terminate: nil];
-
     /* write cached user defaults to disk */
     [[NSUserDefaults standardUserDefaults] synchronize];
-
-    /* send a dummy event to break out of the event loop */
-    o_event = [NSEvent mouseEventWithType: NSLeftMouseDown
-                location: NSMakePoint( 1, 1 ) modifierFlags: 0
-                timestamp: 1 windowNumber: [[NSApp mainWindow] windowNumber]
-                context: [NSGraphicsContext currentContext] eventNumber: 1
-                clickCount: 1 pressure: 0.0];
-    [NSApp postEvent: o_event atStart: YES];
+    
+    p_intf->b_die = VLC_TRUE;
+    [NSApp stop:NULL];
 }
 
 - (IBAction)clearRecentItems:(id)sender
@@ -1291,8 +1271,7 @@ unsigned int VLCModifiersToCocoa( unsigned int i_key )
 - (IBAction)closeError:(id)sender
 {
     vlc_value_t val;
-    intf_thread_t * p_intf = [NSApp getIntf];
-    
+
     if( [o_err_ckbk_surpress state] == NSOnState )
     {
         val.i_int = -1;
index 276370d..7bcfbc4 100644 (file)
@@ -44,8 +44,7 @@
 
 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
 {
-    return [( (VLCApplication *) [VLCApplication sharedApplication] )
-            hasDefinedShortcutKey:o_event];
+    return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event];
 }
 
 @end
                 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
                 o_array = [o_array arrayByAddingObject: o_dic];
             }
-            [(VLCPlaylist *)[[NSApp delegate] getPlaylist] appendArray: o_array atPos: -1 enqueue:NO];
+            [(VLCPlaylist *)[[VLCMain sharedInstance] getPlaylist] appendArray: o_array atPos: -1 enqueue:NO];
             return YES;
         }
     }
                 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
                 o_array = [o_array arrayByAddingObject: o_dic];
             }
-            [(VLCPlaylist *)[[NSApp delegate] getPlaylist] appendArray: o_array atPos: -1 enqueue:NO];
+            [[[VLCMain sharedInstance] getPlaylist] appendArray: o_array atPos: -1 enqueue:NO];
             return YES;
         }
     }
index 0f39319..69faebb 100644 (file)
@@ -130,7 +130,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class )
 
 - (void)awakeFromNib
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
 
     [o_panel setTitle: _NS("Open Source")];
     [o_mrl_lbl setTitle: _NS("Media Resource Locator (MRL)")];
@@ -573,7 +573,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class )
 {
     NSString *o_mode;
     NSString *o_mrl_string = [NSString string];
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
 
     o_mode = [[o_net_mode selectedCell] title];
 
index 0aa917e..c3214de 100644 (file)
 
 - (void)TTLChanged:(NSNotification *)o_notification
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     config_PutInt( p_intf, "ttl", [o_stream_ttl intValue] );
 }
 
index fb73965..984b187 100644 (file)
@@ -56,7 +56,7 @@
     NSNumber *o_number;
 
     playlist_t * p_playlist;
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
 
     if( [[o_event characters] length] )
     {
@@ -191,7 +191,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 - (void) tableView:(NSTableView*)o_tv
                   didClickTableColumn:(NSTableColumn *)o_tc
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t *p_playlist =
         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                        FIND_ANYWHERE );
@@ -264,7 +264,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 
 - (NSMenu *)menuForEvent:(NSEvent *)o_event
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                             FIND_ANYWHERE );
 
@@ -316,7 +316,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 
 - (IBAction)savePlaylist:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
@@ -335,7 +335,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 
 - (IBAction)playItem:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
@@ -352,7 +352,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
     NSMutableArray *o_to_delete;
     NSNumber *o_number;
 
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
@@ -392,7 +392,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
     NSMutableArray *o_selected;
     NSNumber *o_number;
 
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
@@ -434,7 +434,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 
 - (IBAction)enableGroup:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
@@ -448,7 +448,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 
 - (IBAction)disableGroup:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
@@ -472,7 +472,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
     NSString *o_current_name;
     NSString *o_current_author;
 
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                FIND_ANYWHERE );
 
@@ -528,7 +528,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 - (IBAction)handlePopUp:(id)sender
 
 {
-             intf_thread_t * p_intf = [NSApp getIntf];
+             intf_thread_t * p_intf = VLCIntf;
              vlc_value_t val1,val2;
              playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                         FIND_ANYWHERE );
@@ -576,7 +576,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 - (void)appendArray:(NSArray*)o_array atPos:(int)i_position enqueue:(BOOL)b_enqueue
 {
     int i_item;
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
@@ -667,7 +667,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 - (void)playlistUpdated
 {
     vlc_value_t val1, val2;
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
     if( p_playlist != NULL )
@@ -698,7 +698,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 {
     int i_row;
 
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
@@ -728,7 +728,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 
 - (void)deleteGroup:(int)i_id
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
     int i;
@@ -833,7 +833,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
 - (int)numberOfRowsInTableView:(NSTableView *)o_tv
 {
     int i_count = 0;
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                        FIND_ANYWHERE );
 
@@ -853,7 +853,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
                 row:(int)i_row
 {
     id o_value = nil;
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                FIND_ANYWHERE );
 
@@ -922,7 +922,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
                 forTableColumn:(NSTableColumn *)o_tc
                 row:(int)i_rows
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                FIND_ANYWHERE );
     if (p_playlist)
@@ -998,7 +998,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
     {
         if (i_moveRow != -1 && i_proposed_row != -1)
         {
-            intf_thread_t * p_intf = [NSApp getIntf];
+            intf_thread_t * p_intf = VLCIntf;
             playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                                             FIND_ANYWHERE );
 
index 86f0c03..04b6b21 100644 (file)
@@ -76,8 +76,8 @@
     }
     else
     {
-        i_item = [[[NSApp delegate] getPlaylist] selectedPlaylistItem];
-        o_selected = [[[NSApp delegate] getPlaylist] selectedPlaylistItemsList];
+        i_item = [[[VLCMain sharedInstance] getPlaylist] selectedPlaylistItem];
+        o_selected = [[[VLCMain sharedInstance] getPlaylist] selectedPlaylistItemsList];
         [o_selected retain];
         [self initPanel:sender];
     }
@@ -91,7 +91,7 @@
     }
     else
     {
-        intf_thread_t * p_intf = [NSApp getIntf];
+        intf_thread_t * p_intf = VLCIntf;
         playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
 
 
 - (void)initPanel:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist;
 
     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
 - (IBAction)infoOk:(id)sender
 {
     int i,i_row,c;
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
     vlc_value_t val;
 
 - (IBAction)handleGroup:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
 
         if ([[o_group_cbx stringValue] isEqual:
                     [o_group_cbx objectValueOfSelectedItem]])
         {
-            [o_group_color setBackgroundColor:[[[NSApp delegate] getPlaylist]
+            [o_group_color setBackgroundColor:[[[VLCMain sharedInstance] getPlaylist]
                 getColor: p_playlist->pp_groups[
                 [o_group_cbx indexOfSelectedItem]]->i_id]];
         }
         else
         {
-            [o_group_color setBackgroundColor:[[[NSApp delegate] getPlaylist]
+            [o_group_color setBackgroundColor:[[[VLCMain sharedInstance] getPlaylist]
                 getColor:p_playlist->pp_groups[
                 [o_group_cbx numberOfItems] - 1]->i_id + 1]];
         }
 
 - (IBAction)deleteOutlineGroup:(id)sender
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
 
         if ([[o_group_cbx stringValue] isEqual:
                     [o_group_cbx objectValueOfSelectedItem]])
         {
-            [[[NSApp delegate] getPlaylist] deleteGroup:p_playlist->pp_groups[
+            [[[VLCMain sharedInstance] getPlaylist] deleteGroup:p_playlist->pp_groups[
                     [o_group_cbx indexOfSelectedItem]]->i_id];
             [self createComboBox];
             [self handleGroup:self];
 
 - (IBAction)createOutlineGroup:(id)sender;
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
     if(p_playlist)
                     strdup([[o_group_cbx stringValue] cString]));
         [self createComboBox];
         [o_group_cbx reloadData];
-        [[[NSApp delegate] getPlaylist] playlistUpdated];
+        [[[VLCMain sharedInstance] getPlaylist] playlistUpdated];
         vlc_object_release(p_playlist);
     }
 }
 
 -(void)createComboBox
 {
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
     int i;
 {
     BOOL bEnabled = TRUE;
 
-    intf_thread_t * p_intf = [NSApp getIntf];
+    intf_thread_t * p_intf = VLCIntf;
     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                        FIND_ANYWHERE );
 
@@ -387,7 +387,7 @@ static VLCInfoTreeItem *o_root_item = nil;
         o_value = [o_item_value copy];
         i_object_id = i_id;
         o_parent = o_parent_item;
-        i_item = [[[NSApp delegate] getInfo] getItem];
+        i_item = [[[VLCMain sharedInstance] getInfo] getItem];
     }
     return( self );
 }
@@ -410,7 +410,7 @@ static VLCInfoTreeItem *o_root_item = nil;
 {
     if (o_children == NULL)
     {
-        intf_thread_t * p_intf = [NSApp getIntf];
+        intf_thread_t * p_intf = VLCIntf;
         playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );
         int i;
@@ -491,7 +491,7 @@ static VLCInfoTreeItem *o_root_item = nil;
 */
 - (void)refresh
 {
-    i_item = [[[NSApp delegate] getInfo] getItem];
+    i_item = [[[VLCMain sharedInstance] getInfo] getItem];
     if (o_children != NULL)
     {
         [o_children release];
index a6c53b1..34b46c6 100644 (file)
@@ -60,7 +60,7 @@
 
 - (void)awakeFromNib
 {
-    p_intf = [NSApp getIntf];
+    p_intf = VLCIntf;
     b_advanced = config_GetInt( p_intf, "advanced" );
 
     [self initStrings];
         if ( label ) \
         { \
             [o_text_field setStringValue: \
-                [NSApp localizedString: label]]; \
+                [[VLCMain sharedInstance] localizedString: label]]; \
         } \
         [o_text_field sizeToFit]; \
         [o_view addSubview: [o_text_field autorelease]]; \
         [o_text_field msg: param]; \
         if ( psz_duptip != NULL ) \
         { \
-            [o_text_field setToolTip: [NSApp wrapString: [NSApp localizedString: \
+            [o_text_field setToolTip: [[VLCMain sharedInstance] wrapString: [[VLCMain sharedInstance] localizedString: \
                                        psz_duptip] toWidth: PREFS_WRAP ]]; \
             free(psz_duptip);\
         } \
         if( p_item->i_type == CONFIG_HINT_CATEGORY )
         {
             if( !strcmp( p_parser->psz_object_name, "main" ) &&
-                [o_item_name isEqualToString: [NSApp localizedString: p_item->psz_text]] )
+                [o_item_name isEqualToString: [[VLCMain sharedInstance] localizedString: p_item->psz_text]] )
             {
                 b_right_cat = TRUE;
             } else if( strcmp( p_parser->psz_object_name, "main" ) )
                 
                 if ( psz_duptip != NULL )
                 {
-                    [o_modules setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
+                    [o_modules setToolTip: [[VLCMain sharedInstance] wrapString: [[VLCMain sharedInstance] localizedString: psz_duptip] toWidth: PREFS_WRAP]];
                     free( psz_duptip );
                 }
                 [o_view addSubview: [o_modules autorelease]];
                         if( !strcmp( p_a_module->psz_capability,
                                     p_item->psz_type ) )
                         {
-                            NSString *o_description = [NSApp
+                            NSString *o_description = [[VLCMain sharedInstance]
                                 localizedString: p_a_module->psz_longname];
                             [o_modules addItemWithTitle: o_description];
                             [[o_modules lastItem] setTag: p_a_module->i_object_id];
                 o_text_field = [[VLCTextField alloc] initWithFrame: s_rc];
                 CONTROL_CONFIG( o_text_field, o_module_name, CONFIG_ITEM_STRING , p_item->psz_name );
 
-                [o_text_field setStringValue: [NSApp localizedString: psz_value]];
+                [o_text_field setStringValue: [[VLCMain sharedInstance] localizedString: psz_value]];
                 if ( psz_duptip != NULL )
                 {
-                    [o_text_field setToolTip: [NSApp wrapString: [NSApp localizedString:
+                    [o_text_field setToolTip: [[VLCMain sharedInstance] wrapString: [[VLCMain sharedInstance] localizedString:
                                             psz_duptip] toWidth: PREFS_WRAP ]];
                     free(psz_duptip);
                 }
                                     p_item->psz_value : "";
     
                     INPUT_FIELD_STRING( p_item->psz_name, p_item->psz_text, 200,
-                                        [NSApp localizedString: psz_value],
+                                        [[VLCMain sharedInstance] localizedString: psz_value],
                                         p_item->psz_longtext );
                 }
                 else
 
                     if ( psz_duptip != NULL )
                     {
-                        [o_combo_box setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
+                        [o_combo_box setToolTip: [[VLCMain sharedInstance] wrapString: [[VLCMain sharedInstance] localizedString: psz_duptip] toWidth: PREFS_WRAP]];
                         free( psz_duptip );
                     }
                     [o_view addSubview: [o_combo_box autorelease]];
                     for( i=0; p_item->ppsz_list[i]; i++ )
                     {
                         [o_combo_box addItemWithObjectValue:
-                            [NSApp localizedString: p_item->ppsz_list[i]]];
+                            [[VLCMain sharedInstance] localizedString: p_item->ppsz_list[i]]];
                     }
-                    [o_combo_box setStringValue: [NSApp localizedString: 
+                    [o_combo_box setStringValue: [[VLCMain sharedInstance] localizedString: 
                         p_item->psz_value ? p_item->psz_value : ""]];
     
                     CONTROL_LABEL( p_item->psz_text );
 
                     if ( psz_duptip != NULL )
                     {
-                        [o_slider setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
+                        [o_slider setToolTip: [[VLCMain sharedInstance] wrapString: [[VLCMain sharedInstance] localizedString: psz_duptip] toWidth: PREFS_WRAP]];
                         free( psz_duptip );
                     }
                     [o_slider setTarget: self];
 
                     if ( psz_duptip != NULL )
                     {
-                        [o_slider setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
+                        [o_slider setToolTip: [[VLCMain sharedInstance] wrapString: [[VLCMain sharedInstance] localizedString: psz_duptip] toWidth: PREFS_WRAP]];
                         free( psz_duptip );
                     }
                     [o_slider setTarget: self];
                 o_btn_bool = [[VLCButton alloc] initWithFrame: s_rc];
                 [o_btn_bool setButtonType: NSSwitchButton];
                 [o_btn_bool setIntValue: p_item->i_value];
-                [o_btn_bool setTitle: [NSApp localizedString: p_item->psz_text]];
+                [o_btn_bool setTitle: [[VLCMain sharedInstance] localizedString: p_item->psz_text]];
                 if ( psz_duptip != NULL )
                 {
-                    [o_btn_bool setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
+                    [o_btn_bool setToolTip: [[VLCMain sharedInstance] wrapString: [[VLCMain sharedInstance] localizedString: psz_duptip] toWidth: PREFS_WRAP]];
                     free( psz_duptip );
                 }
                 [o_btn_bool setTarget: self];
                     [o_current_cell setControlSize: NSSmallControlSize];
                     if( psz_duptip != NULL )
                     {
-                        [o_matrix setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP] forCell: o_current_cell];
+                        [o_matrix setToolTip: [[VLCMain sharedInstance] wrapString: [[VLCMain sharedInstance] localizedString: psz_duptip] toWidth: PREFS_WRAP] forCell: o_current_cell];
                     }
                     switch( i )
                     {
 
                 if ( psz_duptip != NULL )
                 {
-                    [o_combo_box setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
+                    [o_combo_box setToolTip: [[VLCMain sharedInstance] wrapString: [[VLCMain sharedInstance] localizedString: psz_duptip] toWidth: PREFS_WRAP]];
                 }
                 [o_view addSubview: [o_combo_box autorelease]];
                 
                 {
                     
                     if( vlc_keys[i].psz_key_string && *vlc_keys[i].psz_key_string )
-                    [o_combo_box addItemWithObjectValue: [NSApp localizedString:vlc_keys[i].psz_key_string]];
+                    [o_combo_box addItemWithObjectValue: [[VLCMain sharedInstance] localizedString:vlc_keys[i].psz_key_string]];
                 }
                 
-                [o_combo_box setStringValue: [NSApp localizedString:KeyToString(( ((unsigned int)p_item->i_value) & ~KEY_MODIFIER ))]];
+                [o_combo_box setStringValue: [[VLCMain sharedInstance] localizedString:KeyToString(( ((unsigned int)p_item->i_value) & ~KEY_MODIFIER ))]];
                 
                 s_rc.origin.y += s_rc.size.height;
                 s_rc.origin.x = X_ORIGIN;
@@ -886,7 +886,7 @@ static VLCTreeItem *o_root_item = nil;
  * Loads children incrementally */
 - (NSArray *)children {
     if (o_children == NULL) {
-        intf_thread_t *p_intf = [NSApp getIntf];
+        intf_thread_t *p_intf = VLCIntf;
         vlc_list_t      *p_list;
         module_t        *p_module = NULL;
         module_config_t *p_item;
@@ -928,7 +928,7 @@ static VLCTreeItem *o_root_item = nil;
                     switch( p_item->i_type )
                     {
                     case CONFIG_HINT_CATEGORY:
-                        o_child_name = [NSApp localizedString: p_item->psz_text];
+                        o_child_name = [[VLCMain sharedInstance] localizedString: p_item->psz_text];
                         [o_children addObject:[[VLCTreeItem alloc] initWithName: o_child_name
                             ID: p_module->i_object_id parent:self]];
                         break;
@@ -970,7 +970,7 @@ static VLCTreeItem *o_root_item = nil;
         
                 /* Create the capability tree if it doesn't already exist */
                 NSString *o_capability;
-                o_capability = [NSApp localizedString: p_module->psz_capability];
+                o_capability = [[VLCMain sharedInstance] localizedString: p_module->psz_capability];
                 if( !p_module->psz_capability || !*p_module->psz_capability )
                 {
                     /* Empty capability ? Let's look at the submodules */
@@ -980,7 +980,7 @@ static VLCTreeItem *o_root_item = nil;
                         p_submodule = (module_t*)p_module->pp_children[ j ];
                         if( p_submodule->psz_capability && *p_submodule->psz_capability )
                         {
-                            o_capability = [NSApp localizedString: p_submodule->psz_capability];
+                            o_capability = [[VLCMain sharedInstance] localizedString: p_submodule->psz_capability];
                             BOOL b_found = FALSE;
                             for( j = 0; j < (int)[o_children count]; j++ )
                             {
@@ -1040,7 +1040,7 @@ static VLCTreeItem *o_root_item = nil;
         
                 /* Check the capability */
                 NSString *o_capability;
-                o_capability = [NSApp localizedString: p_module->psz_capability];
+                o_capability = [[VLCMain sharedInstance] localizedString: p_module->psz_capability];
                 if( !p_module->psz_capability || !*p_module->psz_capability )
                 {
                     /* Empty capability ? Let's look at the submodules */
@@ -1050,11 +1050,11 @@ static VLCTreeItem *o_root_item = nil;
                         p_submodule = (module_t*)p_module->pp_children[ j ];
                         if( p_submodule->psz_capability && *p_submodule->psz_capability )
                         {
-                            o_capability = [NSApp localizedString: p_submodule->psz_capability];
+                            o_capability = [[VLCMain sharedInstance] localizedString: p_submodule->psz_capability];
                             if( [o_capability isEqualToString: [self getName]] )
                             {
                             [o_children addObject:[[VLCTreeItem alloc] initWithName:
-                                [NSApp localizedString: p_module->psz_object_name ]
+                                [[VLCMain sharedInstance] localizedString: p_module->psz_object_name ]
                                 ID: p_module->i_object_id parent:self]];
                             }
                         }
@@ -1063,7 +1063,7 @@ static VLCTreeItem *o_root_item = nil;
                 else if( [o_capability isEqualToString: [self getName]] )
                 {
                     [o_children addObject:[[VLCTreeItem alloc] initWithName:
-                        [NSApp localizedString: p_module->psz_object_name ]
+                        [[VLCMain sharedInstance] localizedString: p_module->psz_object_name ]
                         ID: p_module->i_object_id parent:self]];
                 }
             }
@@ -1092,13 +1092,14 @@ static VLCTreeItem *o_root_item = nil;
 }
 
 - (int)numberOfChildren {
+    return 0;
     id i_tmp = [self children];
     return (i_tmp == IsALeafNode) ? (-1) : (int)[i_tmp count];
 }
 
 - (BOOL)hasPrefs:(NSString *)o_module_name
 {
-    intf_thread_t *p_intf = [NSApp getIntf];
+    intf_thread_t *p_intf = VLCIntf;
     module_t *p_parser;
     vlc_list_t *p_list;
     char *psz_module_name;
index e879596..eb787c6 100644 (file)
@@ -119,26 +119,6 @@ int E_(OpenVideo) ( vlc_object_t *p_this )
         return( 1 );
     }
 
-    if( [NSApp respondsToSelector: @selector(getIntf)] )
-    {
-        intf_thread_t * p_intf;
-
-        for( i_timeout = 10 ; i_timeout-- ; )
-        {
-            if( ( p_intf = [NSApp getIntf] ) == NULL )
-            {
-                msleep( INTF_IDLE_SLEEP );
-            }
-        }
-
-        if( p_intf == NULL )
-        {
-            msg_Err( p_vout, "MacOS X intf has getIntf, but is NULL" );
-            free( p_vout->p_sys );
-            return( 1 );
-        }
-    }
-
     p_vout->p_sys->b_mouse_moved = VLC_TRUE;
     p_vout->p_sys->i_time_mouse_last_moved = mdate();
 
@@ -613,12 +593,12 @@ static int CoSendRequest( vout_thread_t *p_vout, SEL sel )
     interface. We do not check if this interface exists, since it has 
     already been done before.*/
 
-    p_intf = [NSApp getIntf];
+    /*p_intf = VLCIntf;
 
     val.b_bool = VLC_TRUE;
     var_Create(p_intf,"intf-change",VLC_VAR_BOOL);
     var_Set(p_intf, "intf-change",val);
-
+*/
     return( i_ret );
 }
 
@@ -1036,8 +1016,7 @@ static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
 
 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
 {
-    return [(VLCApplication *) [VLCApplication sharedApplication]
-            hasDefinedShortcutKey:o_event];
+    return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event];
 }
 
 - (void)keyDown:(NSEvent *)o_event
index 458431d..f729444 100644 (file)
 #include "audio_output.h"
 
 #include "vlc_interface.h"
-
 #include "vlc_video.h"
 #include "video_output.h"
 
+#ifdef SYS_DARWIN
+#    include "Cocoa/Cocoa.h"
+#endif /* SYS_DARWIN */
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -127,8 +130,10 @@ intf_thread_t* __intf_Create( vlc_object_t *p_this, const char *psz_module )
  */
 int intf_RunThread( intf_thread_t *p_intf )
 {
+#ifdef SYS_DARWIN
     if( p_intf->b_block )
     {
+        /* This is the primary intf */
         /* Run a manager thread, launch the interface, kill the manager */
         if( vlc_thread_create( p_intf, "manager", Manager,
                                VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
@@ -136,15 +141,49 @@ int intf_RunThread( intf_thread_t *p_intf )
             msg_Err( p_intf, "cannot spawn manager thread" );
             return VLC_EGENERIC;
         }
+    }
 
-        RunInterface( p_intf );
+    if( p_intf->b_block && !strncmp( p_intf->p_module->psz_shortname, "macosx" , 6 ) )
+    {
+       /* this is OSX, we are cheating :)
+           This is NOT I REPEAT NOT blocking since [NSApp run] is */
+       p_intf->b_block = VLC_FALSE;
 
+        RunInterface( p_intf );
+       p_intf->b_block = VLC_TRUE;
+    }
+    else if( p_intf->b_block && !strncmp( p_intf->p_vlc->psz_object_name, "clivlc", 6 ) )
+    {
+        /* VLC OS X in cli mode ( no blocking [NSApp run] )
+           this is equal to running in normal non-OSX primary intf mode */
+        RunInterface( p_intf );
         p_intf->b_die = VLC_TRUE;
+    }
+    else
+    {
+        /* If anything else is the primary intf and we are not in cli mode,
+           then don't make it blocking ([NSApp run] will be blocking) 
+           but run it in a seperate thread. */
+        p_intf->b_block = VLC_FALSE;
+#else
+    if( p_intf->b_block )
+    {
+        /* Run a manager thread, launch the interface, kill the manager */
+        if( vlc_thread_create( p_intf, "manager", Manager,
+                               VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
+        {
+            msg_Err( p_intf, "cannot spawn manager thread" );
+            return VLC_EGENERIC;
+        }
+
+        RunInterface( p_intf );
 
+        p_intf->b_die = VLC_TRUE;
         /* Do not join the thread... intf_StopThread will do it for us */
     }
     else
     {
+#endif
         /* Run the interface in a separate thread */
         if( vlc_thread_create( p_intf, "interface", RunInterface,
                                VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
@@ -228,6 +267,12 @@ static void Manager( intf_thread_t *p_intf )
         if( p_intf->p_vlc->b_die )
         {
             p_intf->b_die = VLC_TRUE;
+#ifdef SYS_DARWIN
+    if( strncmp( p_intf->p_vlc->psz_object_name, "clivlc", 6 ) )
+    {
+        [NSApp stop: NULL];
+    }
+#endif
             return;
         }
     }
index 6aedd11..36cf1f3 100644 (file)
--- a/src/vlc.c
+++ b/src/vlc.c
@@ -7,6 +7,7 @@
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
  *          Gildas Bazin <gbazin@netcourrier.com>
+ *          Derk-Jan Hartman <hartman at videolan dot org>
  *          Lots of other people, see the libvlc AUTHORS file
  *
  * This program is free software; you can redistribute it and/or modify
 #ifdef HAVE_TIME_H
 #   include <time.h>                                               /* time() */
 #endif
+#ifdef HAVE_STRINGS_H
+#   include <strings.h>                                         /* strncmp() */
+#endif
 
 #include <vlc/vlc.h>
 
+#ifdef SYS_DARWIN
+#include <Cocoa/Cocoa.h>
+#endif
+
 /*****************************************************************************
  * Local prototypes.
  *****************************************************************************/
 static void SigHandler  ( int i_signal );
 #endif
 
+#ifdef SYS_DARWIN
+/*****************************************************************************
+ * VLCApplication interface
+ *****************************************************************************/
+@interface VLCApplication : NSApplication
+{
+}
+
+@end
+
+/*****************************************************************************
+ * VLCApplication implementation 
+ *****************************************************************************/
+@implementation VLCApplication 
+
+- (void)stop: (id)sender
+{
+    NSEvent *o_event;
+    [super stop:sender];
+
+    /* send a dummy event to break out of the event loop */
+    o_event = [NSEvent mouseEventWithType: NSLeftMouseDown
+                location: NSMakePoint( 1, 1 ) modifierFlags: 0
+                timestamp: 1 windowNumber: [[NSApp mainWindow] windowNumber]
+                context: [NSGraphicsContext currentContext] eventNumber: 1
+                clickCount: 1 pressure: 0.0];
+    [NSApp postEvent: o_event atStart: YES];
+}
+
+- (void)terminate: (id)sender
+{
+    if( [NSApp isRunning] )
+        [NSApp stop:sender];
+    [super terminate: sender];
+}
+
+@end
+
+#endif /* SYS_DARWIN */
+
 /*****************************************************************************
- * main: parse command line, start interface and spawn threads
+ * main: parse command line, start interface and spawn threads.
  *****************************************************************************/
 int main( int i_argc, char *ppsz_argv[] )
 {
     int i_ret;
+    int b_cli = VLC_FALSE ;
 
+#ifndef SYS_DARWIN
+    /* This clutters OSX GUI error logs */
     fprintf( stderr, "VLC media player %s\n", VLC_Version() );
+#endif
 
 #ifdef HAVE_PUTENV
 #   ifdef DEBUG
@@ -98,8 +150,39 @@ int main( int i_argc, char *ppsz_argv[] )
         return i_ret;
     }
 
-    /* Add a blocking interface, start playing, and keep the return value */
+#ifdef HAVE_STRINGS_H
+    /* if first 3 chars of argv[0] are cli, then this is clivlc
+     * We detect this specifically for Mac OS X, so you can launch vlc
+     * from the commandline even if you are not logged in on the GUI */
+    if( i_argc > 0 )
+    {
+        char *psz_temp;
+        char *psz_program = psz_temp = ppsz_argv[0];
+        while( *psz_temp )
+        {
+            if( *psz_temp == '/' ) psz_program = ++psz_temp;
+            else ++psz_temp;
+        }
+        b_cli = !strncmp( psz_program, "cli", 3 );
+    }
+#endif
+
+#ifdef SYS_DARWIN
+    if( !b_cli )
+    {
+        [VLCApplication sharedApplication];
+    }
+
+    i_ret = VLC_AddIntf( 0, NULL, VLC_TRUE, VLC_TRUE );
+    
+    if( !b_cli )
+    {
+        /* This is a blocking call */
+        [NSApp run];
+    }
+#else
     i_ret = VLC_AddIntf( 0, NULL, VLC_TRUE, VLC_TRUE );
+#endif /* SYS_DARWIN */
 
     /* Finish the threads */
     VLC_CleanUp( 0 );
@@ -107,6 +190,13 @@ int main( int i_argc, char *ppsz_argv[] )
     /* Destroy the libvlc structure */
     VLC_Destroy( 0 );
 
+#ifdef SYS_DARWIN
+    if( !b_cli )
+    {
+        [NSApp terminate:NULL];
+    }
+#endif /* SYS_DARWIN */
+
     return i_ret;
 }