intf.m
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:48k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * intf.m: MacOS X interface module
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2004 VideoLAN
  5.  * $Id: intf.m 8948 2004-10-07 21:33:38Z bigben $
  6.  *
  7.  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
  8.  *          Christophe Massiot <massiot@via.ecp.fr>
  9.  *          Derk-Jan Hartman <hartman at videolan.org>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include <stdlib.h>                                      /* malloc(), free() */
  29. #include <sys/param.h>                                    /* for MAXPATHLEN */
  30. #include <string.h>
  31. #include <vlc_keys.h>
  32. #include "intf.h"
  33. #include "vout.h"
  34. #include "prefs.h"
  35. #include "playlist.h"
  36. #include "controls.h"
  37. /*****************************************************************************
  38.  * Local prototypes.
  39.  *****************************************************************************/
  40. static void Run ( intf_thread_t *p_intf );
  41. /*****************************************************************************
  42.  * OpenIntf: initialize interface
  43.  *****************************************************************************/
  44. int E_(OpenIntf) ( vlc_object_t *p_this )
  45. {
  46.     intf_thread_t *p_intf = (intf_thread_t*) p_this;
  47.     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
  48.     if( p_intf->p_sys == NULL )
  49.     {
  50.         return( 1 );
  51.     }
  52.     memset( p_intf->p_sys, 0, sizeof( *p_intf->p_sys ) );
  53.     p_intf->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
  54.     /* Put Cocoa into multithread mode as soon as possible.
  55.      * http://developer.apple.com/techpubs/macosx/Cocoa/
  56.      * TasksAndConcepts/ProgrammingTopics/Multithreading/index.html
  57.      * This thread does absolutely nothing at all. */
  58.     [NSThread detachNewThreadSelector:@selector(self) toTarget:[NSString string] withObject:nil];
  59.     p_intf->p_sys->o_sendport = [[NSPort port] retain];
  60.     p_intf->p_sys->p_sub = msg_Subscribe( p_intf );
  61.     p_intf->b_play = VLC_TRUE;
  62.     p_intf->pf_run = Run;
  63.     return( 0 );
  64. }
  65. /*****************************************************************************
  66.  * CloseIntf: destroy interface
  67.  *****************************************************************************/
  68. void E_(CloseIntf) ( vlc_object_t *p_this )
  69. {
  70.     intf_thread_t *p_intf = (intf_thread_t*) p_this;
  71.     msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
  72.     [p_intf->p_sys->o_sendport release];
  73.     [p_intf->p_sys->o_pool release];
  74.     free( p_intf->p_sys );
  75. }
  76. /*****************************************************************************
  77.  * Run: main loop
  78.  *****************************************************************************/
  79. static void Run( intf_thread_t *p_intf )
  80. {
  81.     /* Do it again - for some unknown reason, vlc_thread_create() often
  82.      * fails to go to real-time priority with the first launched thread
  83.      * (???) --Meuuh */
  84.     vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
  85.     [[VLCMain sharedInstance] setIntf: p_intf];
  86.     [NSBundle loadNibNamed: @"MainMenu" owner: NSApp];
  87.     [NSApp run];
  88.     [[VLCMain sharedInstance] terminate];
  89. }
  90. int ExecuteOnMainThread( id target, SEL sel, void * p_arg )
  91. {
  92.     int i_ret = 0;
  93.     //NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
  94.     if( [target respondsToSelector: @selector(performSelectorOnMainThread:
  95.                                              withObject:waitUntilDone:)] )
  96.     {
  97.         [target performSelectorOnMainThread: sel
  98.                 withObject: [NSValue valueWithPointer: p_arg]
  99.                 waitUntilDone: NO];
  100.     }
  101.     else if( NSApp != nil && [[VLCMain sharedInstance] respondsToSelector: @selector(getIntf)] )
  102.     {
  103.         NSValue * o_v1;
  104.         NSValue * o_v2;
  105.         NSArray * o_array;
  106.         NSPort * o_recv_port;
  107.         NSInvocation * o_inv;
  108.         NSPortMessage * o_msg;
  109.         intf_thread_t * p_intf;
  110.         NSConditionLock * o_lock;
  111.         NSMethodSignature * o_sig;
  112.         id * val[] = { &o_lock, &o_v2 };
  113.         p_intf = (intf_thread_t *)VLCIntf;
  114.         o_recv_port = [[NSPort port] retain];
  115.         o_v1 = [NSValue valueWithPointer: val];
  116.         o_v2 = [NSValue valueWithPointer: p_arg];
  117.         o_sig = [target methodSignatureForSelector: sel];
  118.         o_inv = [NSInvocation invocationWithMethodSignature: o_sig];
  119.         [o_inv setArgument: &o_v1 atIndex: 2];
  120.         [o_inv setTarget: target];
  121.         [o_inv setSelector: sel];
  122.         o_array = [NSArray arrayWithObject:
  123.             [NSData dataWithBytes: &o_inv length: sizeof(o_inv)]];
  124.         o_msg = [[NSPortMessage alloc]
  125.             initWithSendPort: p_intf->p_sys->o_sendport
  126.             receivePort: o_recv_port components: o_array];
  127.         o_lock = [[NSConditionLock alloc] initWithCondition: 0];
  128.         [o_msg sendBeforeDate: [NSDate distantPast]];
  129.         [o_lock lockWhenCondition: 1];
  130.         [o_lock unlock];
  131.         [o_lock release];
  132.         [o_msg release];
  133.         [o_recv_port release];
  134.     }
  135.     else
  136.     {
  137.         i_ret = 1;
  138.     }
  139.     //[o_pool release];
  140.     return( i_ret );
  141. }
  142. /*****************************************************************************
  143.  * playlistChanged: Callback triggered by the intf-change playlist
  144.  * variable, to let the intf update the playlist.
  145.  *****************************************************************************/
  146. int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
  147.                      vlc_value_t old_val, vlc_value_t new_val, void *param )
  148. {
  149.     intf_thread_t * p_intf = VLCIntf;
  150.     p_intf->p_sys->b_playlist_update = TRUE;
  151.     p_intf->p_sys->b_intf_update = TRUE;
  152.     return VLC_SUCCESS;
  153. }
  154. /*****************************************************************************
  155.  * FullscreenChanged: Callback triggered by the fullscreen-change playlist
  156.  * variable, to let the intf update the controller.
  157.  *****************************************************************************/
  158. int FullscreenChanged( vlc_object_t *p_this, const char *psz_variable,
  159.                      vlc_value_t old_val, vlc_value_t new_val, void *param )
  160. {
  161.     intf_thread_t * p_intf = VLCIntf;
  162.     p_intf->p_sys->b_fullscreen_update = TRUE;
  163.     return VLC_SUCCESS;
  164. }
  165. static struct
  166. {
  167.     unichar i_nskey;
  168.     unsigned int i_vlckey;
  169. } nskeys_to_vlckeys[] =
  170. {
  171.     { NSUpArrowFunctionKey, KEY_UP },
  172.     { NSDownArrowFunctionKey, KEY_DOWN },
  173.     { NSLeftArrowFunctionKey, KEY_LEFT },
  174.     { NSRightArrowFunctionKey, KEY_RIGHT },
  175.     { NSF1FunctionKey, KEY_F1 },
  176.     { NSF2FunctionKey, KEY_F2 },
  177.     { NSF3FunctionKey, KEY_F3 },
  178.     { NSF4FunctionKey, KEY_F4 },
  179.     { NSF5FunctionKey, KEY_F5 },
  180.     { NSF6FunctionKey, KEY_F6 },
  181.     { NSF7FunctionKey, KEY_F7 },
  182.     { NSF8FunctionKey, KEY_F8 },
  183.     { NSF9FunctionKey, KEY_F9 },
  184.     { NSF10FunctionKey, KEY_F10 },
  185.     { NSF11FunctionKey, KEY_F11 },
  186.     { NSF12FunctionKey, KEY_F12 },
  187.     { NSHomeFunctionKey, KEY_HOME },
  188.     { NSEndFunctionKey, KEY_END },
  189.     { NSPageUpFunctionKey, KEY_PAGEUP },
  190.     { NSPageDownFunctionKey, KEY_PAGEDOWN },
  191.     { NSTabCharacter, KEY_TAB },
  192.     { NSCarriageReturnCharacter, KEY_ENTER },
  193.     { NSEnterCharacter, KEY_ENTER },
  194.     { NSBackspaceCharacter, KEY_BACKSPACE },
  195.     { (unichar) ' ', KEY_SPACE },
  196.     { (unichar) 0x1b, KEY_ESC },
  197.     {0,0}
  198. };
  199. unichar VLCKeyToCocoa( unsigned int i_key )
  200. {
  201.     unsigned int i;
  202.     for( i = 0; nskeys_to_vlckeys[i].i_vlckey != 0; i++ )
  203.     {
  204.         if( nskeys_to_vlckeys[i].i_vlckey == (i_key & ~KEY_MODIFIER) )
  205.         {
  206.             return nskeys_to_vlckeys[i].i_nskey;
  207.         }
  208.     }
  209.     return (unichar)(i_key & ~KEY_MODIFIER);
  210. }
  211. unsigned int CocoaKeyToVLC( unichar i_key )
  212. {
  213.     unsigned int i;
  214.     for( i = 0; nskeys_to_vlckeys[i].i_nskey != 0; i++ )
  215.     {
  216.         if( nskeys_to_vlckeys[i].i_nskey == i_key )
  217.         {
  218.             return nskeys_to_vlckeys[i].i_vlckey;
  219.         }
  220.     }
  221.     return (unsigned int)i_key;
  222. }
  223. unsigned int VLCModifiersToCocoa( unsigned int i_key )
  224. {
  225.     unsigned int new = 0;
  226.     if( i_key & KEY_MODIFIER_COMMAND )
  227.         new |= NSCommandKeyMask;
  228.     if( i_key & KEY_MODIFIER_ALT )
  229.         new |= NSAlternateKeyMask;
  230.     if( i_key & KEY_MODIFIER_SHIFT )
  231.         new |= NSShiftKeyMask;
  232.     if( i_key & KEY_MODIFIER_CTRL )
  233.         new |= NSControlKeyMask;
  234.     return new;
  235. }
  236. /*****************************************************************************
  237.  * VLCMain implementation
  238.  *****************************************************************************/
  239. @implementation VLCMain
  240. static VLCMain *_o_sharedMainInstance = nil;
  241. + (VLCMain *)sharedInstance
  242. {
  243.     return _o_sharedMainInstance ? _o_sharedMainInstance : [[self alloc] init];
  244. }
  245. - (id)init
  246. {
  247.     if( _o_sharedMainInstance) {
  248.         [self dealloc];
  249.     } else {
  250.         _o_sharedMainInstance = [super init];
  251.     }
  252.     return _o_sharedMainInstance;
  253. }
  254. - (void)setIntf: (intf_thread_t *)p_mainintf {
  255.     p_intf = p_mainintf;
  256. }
  257. - (intf_thread_t *)getIntf {
  258.     return p_intf;
  259. }
  260. - (void)awakeFromNib
  261. {
  262.     unsigned int i_key = 0;
  263.     playlist_t *p_playlist;
  264.     vlc_value_t val;
  265.     [self initStrings];
  266.     [o_window setExcludedFromWindowsMenu: TRUE];
  267.     [o_msgs_panel setExcludedFromWindowsMenu: TRUE];
  268.     [o_msgs_panel setDelegate: self];
  269.     i_key = config_GetInt( p_intf, "key-quit" );
  270.     [o_mi_quit setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  271.     [o_mi_quit setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  272.     i_key = config_GetInt( p_intf, "key-play-pause" );
  273.     [o_mi_play setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  274.     [o_mi_play setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  275.     i_key = config_GetInt( p_intf, "key-stop" );
  276.     [o_mi_stop setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  277.     [o_mi_stop setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  278.     i_key = config_GetInt( p_intf, "key-faster" );
  279.     [o_mi_faster setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  280.     [o_mi_faster setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  281.     i_key = config_GetInt( p_intf, "key-slower" );
  282.     [o_mi_slower setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  283.     [o_mi_slower setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  284.     i_key = config_GetInt( p_intf, "key-prev" );
  285.     [o_mi_previous setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  286.     [o_mi_previous setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  287.     i_key = config_GetInt( p_intf, "key-next" );
  288.     [o_mi_next setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  289.     [o_mi_next setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  290.     i_key = config_GetInt( p_intf, "key-jump+10sec" );
  291.     [o_mi_fwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  292.     [o_mi_fwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  293.     i_key = config_GetInt( p_intf, "key-jump-10sec" );
  294.     [o_mi_bwd setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  295.     [o_mi_bwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  296.     i_key = config_GetInt( p_intf, "key-jump+1min" );
  297.     [o_mi_fwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  298.     [o_mi_fwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  299.     i_key = config_GetInt( p_intf, "key-jump-1min" );
  300.     [o_mi_bwd1m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  301.     [o_mi_bwd1m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  302.     i_key = config_GetInt( p_intf, "key-jump+5min" );
  303.     [o_mi_fwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  304.     [o_mi_fwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  305.     i_key = config_GetInt( p_intf, "key-jump-5min" );
  306.     [o_mi_bwd5m setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  307.     [o_mi_bwd5m setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  308.     i_key = config_GetInt( p_intf, "key-vol-up" );
  309.     [o_mi_vol_up setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  310.     [o_mi_vol_up setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  311.     i_key = config_GetInt( p_intf, "key-vol-down" );
  312.     [o_mi_vol_down setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  313.     [o_mi_vol_down setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  314.     i_key = config_GetInt( p_intf, "key-vol-mute" );
  315.     [o_mi_mute setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  316.     [o_mi_mute setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  317.     i_key = config_GetInt( p_intf, "key-fullscreen" );
  318.     [o_mi_fullscreen setKeyEquivalent: [NSString stringWithFormat:@"%C", VLCKeyToCocoa( i_key )]];
  319.     [o_mi_fullscreen setKeyEquivalentModifierMask: VLCModifiersToCocoa(i_key)];
  320.     var_Create( p_intf, "intf-change", VLC_VAR_BOOL );
  321.     [self setSubmenusEnabled: FALSE];
  322.     [self manageVolumeSlider];
  323.     p_playlist = (playlist_t *) vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
  324.     if( p_playlist )
  325.     {
  326.         /* Check if we need to start playing */
  327.         if( p_intf->b_play )
  328.         {
  329.             playlist_Play( p_playlist );
  330.         }
  331.         var_Create( p_playlist, "fullscreen", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
  332.         val.b_bool = VLC_FALSE;
  333.         var_AddCallback( p_playlist, "fullscreen", FullscreenChanged, self);
  334.         [o_btn_fullscreen setState: ( var_Get( p_playlist, "fullscreen", &val )>=0 && val.b_bool )];
  335.         vlc_object_release( p_playlist );
  336.     }
  337. }
  338. - (void)initStrings
  339. {
  340.     [o_window setTitle: _NS("VLC - Controller")];
  341.     [o_scrollfield setStringValue: _NS("VLC media player")];
  342.     /* button controls */
  343.     [o_btn_prev setToolTip: _NS("Previous")];
  344.     [o_btn_rewind setToolTip: _NS("Rewind")];
  345.     [o_btn_play setToolTip: _NS("Play")];
  346.     [o_btn_stop setToolTip: _NS("Stop")];
  347.     [o_btn_ff setToolTip: _NS("Fast Forward")];
  348.     [o_btn_next setToolTip: _NS("Next")];
  349.     [o_btn_fullscreen setToolTip: _NS("Fullscreen")];
  350.     [o_volumeslider setToolTip: _NS("Volume")];
  351.     [o_timeslider setToolTip: _NS("Position")];
  352.     /* messages panel */
  353.     [o_msgs_panel setTitle: _NS("Messages")];
  354.     [o_msgs_btn_crashlog setTitle: _NS("Open CrashLog")];
  355.     /* main menu */
  356.     [o_mi_about setTitle: _NS("About VLC media player")];
  357.     [o_mi_prefs setTitle: _NS("Preferences...")];
  358.     [o_mi_add_intf setTitle: _NS("Add Interface")];
  359.     [o_mu_add_intf setTitle: _NS("Add Interface")];
  360.     [o_mi_services setTitle: _NS("Services")];
  361.     [o_mi_hide setTitle: _NS("Hide VLC")];
  362.     [o_mi_hide_others setTitle: _NS("Hide Others")];
  363.     [o_mi_show_all setTitle: _NS("Show All")];
  364.     [o_mi_quit setTitle: _NS("Quit VLC")];
  365.     [o_mu_file setTitle: _ANS("1:File")];
  366.     [o_mi_open_generic setTitle: _NS("Open File...")];
  367.     [o_mi_open_file setTitle: _NS("Quick Open File...")];
  368.     [o_mi_open_disc setTitle: _NS("Open Disc...")];
  369.     [o_mi_open_net setTitle: _NS("Open Network...")];
  370.     [o_mi_open_recent setTitle: _NS("Open Recent")];
  371.     [o_mi_open_recent_cm setTitle: _NS("Clear Menu")];
  372.     [o_mu_edit setTitle: _NS("Edit")];
  373.     [o_mi_cut setTitle: _NS("Cut")];
  374.     [o_mi_copy setTitle: _NS("Copy")];
  375.     [o_mi_paste setTitle: _NS("Paste")];
  376.     [o_mi_clear setTitle: _NS("Clear")];
  377.     [o_mi_select_all setTitle: _NS("Select All")];
  378.     [o_mu_controls setTitle: _NS("Controls")];
  379.     [o_mi_play setTitle: _NS("Play")];
  380.     [o_mi_stop setTitle: _NS("Stop")];
  381.     [o_mi_faster setTitle: _NS("Faster")];
  382.     [o_mi_slower setTitle: _NS("Slower")];
  383.     [o_mi_previous setTitle: _NS("Previous")];
  384.     [o_mi_next setTitle: _NS("Next")];
  385.     [o_mi_random setTitle: _NS("Random")];
  386.     [o_mi_repeat setTitle: _NS("Repeat One")];
  387.     [o_mi_loop setTitle: _NS("Repeat All")];
  388.     [o_mi_fwd setTitle: _NS("Step Forward")];
  389.     [o_mi_bwd setTitle: _NS("Step Backward")];
  390.     [o_mi_program setTitle: _NS("Program")];
  391.     [o_mu_program setTitle: _NS("Program")];
  392.     [o_mi_title setTitle: _NS("Title")];
  393.     [o_mu_title setTitle: _NS("Title")];
  394.     [o_mi_chapter setTitle: _NS("Chapter")];
  395.     [o_mu_chapter setTitle: _NS("Chapter")];
  396.     [o_mu_audio setTitle: _NS("Audio")];
  397.     [o_mi_vol_up setTitle: _NS("Volume Up")];
  398.     [o_mi_vol_down setTitle: _NS("Volume Down")];
  399.     [o_mi_mute setTitle: _NS("Mute")];
  400.     [o_mi_audiotrack setTitle: _NS("Audio Track")];
  401.     [o_mu_audiotrack setTitle: _NS("Audio Track")];
  402.     [o_mi_channels setTitle: _NS("Audio Channels")];
  403.     [o_mu_channels setTitle: _NS("Audio Channels")];
  404.     [o_mi_device setTitle: _NS("Audio Device")];
  405.     [o_mu_device setTitle: _NS("Audio Device")];
  406.     [o_mi_visual setTitle: _NS("Visualizations")];
  407.     [o_mu_visual setTitle: _NS("Visualizations")];
  408.     [o_mu_video setTitle: _NS("Video")];
  409.     [o_mi_half_window setTitle: _NS("Half Size")];
  410.     [o_mi_normal_window setTitle: _NS("Normal Size")];
  411.     [o_mi_double_window setTitle: _NS("Double Size")];
  412.     [o_mi_fittoscreen setTitle: _NS("Fit to Screen")];
  413.     [o_mi_fullscreen setTitle: _NS("Fullscreen")];
  414.     [o_mi_floatontop setTitle: _NS("Float on Top")];
  415.     [o_mi_videotrack setTitle: _NS("Video Track")];
  416.     [o_mu_videotrack setTitle: _NS("Video Track")];
  417.     [o_mi_screen setTitle: _NS("Video Device")];
  418.     [o_mu_screen setTitle: _NS("Video Device")];
  419.     [o_mi_subtitle setTitle: _NS("Subtitles Track")];
  420.     [o_mu_subtitle setTitle: _NS("Subtitles Track")];
  421.     [o_mi_deinterlace setTitle: _NS("Deinterlace")];
  422.     [o_mu_deinterlace setTitle: _NS("Deinterlace")];
  423.     [o_mi_ffmpeg_pp setTitle: _NS("Post processing")];
  424.     [o_mu_ffmpeg_pp setTitle: _NS("Post processing")];
  425.     [o_mu_window setTitle: _NS("Window")];
  426.     [o_mi_minimize setTitle: _NS("Minimize Window")];
  427.     [o_mi_close_window setTitle: _NS("Close Window")];
  428.     [o_mi_controller setTitle: _NS("Controller")];
  429.     [o_mi_equalizer setTitle: _NS("Equalizer")];
  430.     [o_mi_playlist setTitle: _NS("Playlist")];
  431.     [o_mi_info setTitle: _NS("Info")];
  432.     [o_mi_messages setTitle: _NS("Messages")];
  433.     [o_mi_bring_atf setTitle: _NS("Bring All to Front")];
  434.     [o_mu_help setTitle: _NS("Help")];
  435.     [o_mi_readme setTitle: _NS("ReadMe...")];
  436.     [o_mi_documentation setTitle: _NS("Online Documentation")];
  437.     [o_mi_reportabug setTitle: _NS("Report a Bug")];
  438.     [o_mi_website setTitle: _NS("VideoLAN Website")];
  439.     [o_mi_license setTitle: _NS("License")];
  440.     /* dock menu */
  441.     [o_dmi_play setTitle: _NS("Play")];
  442.     [o_dmi_stop setTitle: _NS("Stop")];
  443.     [o_dmi_next setTitle: _NS("Next")];
  444.     [o_dmi_previous setTitle: _NS("Previous")];
  445.     [o_dmi_mute setTitle: _NS("Mute")];
  446.     /* error panel */
  447.     [o_error setTitle: _NS("Error")];
  448.     [o_err_lbl setStringValue: _NS("An error has occurred which probably prevented the execution of your request:")];
  449.     [o_err_bug_lbl setStringValue: _NS("If you believe that it is a bug, please follow the instructions at:")];
  450.     [o_err_btn_msgs setTitle: _NS("Open Messages Window")];
  451.     [o_err_btn_dismiss setTitle: _NS("Dismiss")];
  452.     [o_err_ckbk_surpress setTitle: _NS("Suppress further errors")];
  453.     [o_info_window setTitle: _NS("Info")];
  454. }
  455. - (void)applicationWillFinishLaunching:(NSNotification *)o_notification
  456. {
  457.     o_msg_lock = [[NSLock alloc] init];
  458.     o_msg_arr = [[NSMutableArray arrayWithCapacity: 200] retain];
  459.     o_img_play = [[NSImage imageNamed: @"play"] retain];
  460.     o_img_play_pressed = [[NSImage imageNamed: @"play_blue"] retain];
  461.     o_img_pause = [[NSImage imageNamed: @"pause"] retain];
  462.     o_img_pause_pressed = [[NSImage imageNamed: @"pause_blue"] retain];
  463.     [p_intf->p_sys->o_sendport setDelegate: self];
  464.     [[NSRunLoop currentRunLoop]
  465.         addPort: p_intf->p_sys->o_sendport
  466.         forMode: NSDefaultRunLoopMode];
  467.     [NSTimer scheduledTimerWithTimeInterval: 0.5
  468.         target: self selector: @selector(manageIntf:)
  469.         userInfo: nil repeats: FALSE];
  470.     [NSThread detachNewThreadSelector: @selector(manage)
  471.         toTarget: self withObject: nil];
  472.     [o_controls setupVarMenuItem: o_mi_add_intf target: (vlc_object_t *)p_intf
  473.         var: "intf-add" selector: @selector(toggleVar:)];
  474.     vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
  475. }
  476. - (BOOL)application:(NSApplication *)o_app openFile:(NSString *)o_filename
  477. {
  478.     NSDictionary *o_dic = [NSDictionary dictionaryWithObjectsAndKeys: o_filename, @"ITEM_URL", nil];
  479.     [o_playlist appendArray:
  480.         [NSArray arrayWithObject: o_dic] atPos: -1 enqueue: NO];
  481.     return( TRUE );
  482. }
  483. - (NSString *)localizedString:(char *)psz
  484. {
  485.     NSString * o_str = nil;
  486.     if( psz != NULL )
  487.     {
  488.         o_str = [[[NSString alloc] initWithUTF8String: psz] autorelease];
  489.     }
  490.     if ( o_str == NULL )
  491.     {
  492.         msg_Err( VLCIntf, "could not translate: %s", psz );
  493.     }
  494.     return( o_str );
  495. }
  496. - (char *)delocalizeString:(NSString *)id
  497. {
  498.     NSData * o_data = [id dataUsingEncoding: NSUTF8StringEncoding
  499.                           allowLossyConversion: NO];
  500.     char * psz_string;
  501.     if ( o_data == nil )
  502.     {
  503.         o_data = [id dataUsingEncoding: NSUTF8StringEncoding
  504.                      allowLossyConversion: YES];
  505.         psz_string = malloc( [o_data length] + 1 );
  506.         [o_data getBytes: psz_string];
  507.         psz_string[ [o_data length] ] = '';
  508.         msg_Err( VLCIntf, "cannot convert to wanted encoding: %s",
  509.                  psz_string );
  510.     }
  511.     else
  512.     {
  513.         psz_string = malloc( [o_data length] + 1 );
  514.         [o_data getBytes: psz_string];
  515.         psz_string[ [o_data length] ] = '';
  516.     }
  517.     return psz_string;
  518. }
  519. /* i_width is in pixels */
  520. - (NSString *)wrapString: (NSString *)o_in_string toWidth: (int) i_width
  521. {
  522.     NSMutableString *o_wrapped;
  523.     NSString *o_out_string;
  524.     NSRange glyphRange, effectiveRange, charRange;
  525.     NSRect lineFragmentRect;
  526.     unsigned glyphIndex, breaksInserted = 0;
  527.     NSTextStorage *o_storage = [[NSTextStorage alloc] initWithString: o_in_string
  528.         attributes: [NSDictionary dictionaryWithObjectsAndKeys:
  529.         [NSFont labelFontOfSize: 0.0], NSFontAttributeName, nil]];
  530.     NSLayoutManager *o_layout_manager = [[NSLayoutManager alloc] init];
  531.     NSTextContainer *o_container = [[NSTextContainer alloc]
  532.         initWithContainerSize: NSMakeSize(i_width, 2000)];
  533.     [o_layout_manager addTextContainer: o_container];
  534.     [o_container release];
  535.     [o_storage addLayoutManager: o_layout_manager];
  536.     [o_layout_manager release];
  537.     o_wrapped = [o_in_string mutableCopy];
  538.     glyphRange = [o_layout_manager glyphRangeForTextContainer: o_container];
  539.     for( glyphIndex = glyphRange.location ; glyphIndex < NSMaxRange(glyphRange) ;
  540.             glyphIndex += effectiveRange.length) {
  541.         lineFragmentRect = [o_layout_manager lineFragmentRectForGlyphAtIndex: glyphIndex
  542.                                             effectiveRange: &effectiveRange];
  543.         charRange = [o_layout_manager characterRangeForGlyphRange: effectiveRange
  544.                                     actualGlyphRange: &effectiveRange];
  545.         if ([o_wrapped lineRangeForRange:
  546.                 NSMakeRange(charRange.location + breaksInserted, charRange.length)].length > charRange.length) {
  547.             [o_wrapped insertString: @"n" atIndex: NSMaxRange(charRange) + breaksInserted];
  548.             breaksInserted++;
  549.         }
  550.     }
  551.     o_out_string = [NSString stringWithString: o_wrapped];
  552.     [o_wrapped release];
  553.     [o_storage release];
  554.     return o_out_string;
  555. }
  556. /*****************************************************************************
  557.  * hasDefinedShortcutKey: Check to see if the key press is a defined VLC
  558.  * shortcut key.  If it is, pass it off to VLC for handling and return YES,
  559.  * otherwise ignore it and return NO (where it will get handled by Cocoa).
  560.  *****************************************************************************/
  561. - (BOOL)hasDefinedShortcutKey:(NSEvent *)o_event
  562. {
  563.     unichar key = 0;
  564.     vlc_value_t val;
  565.     unsigned int i_pressed_modifiers = 0;
  566.     struct hotkey *p_hotkeys;
  567.     int i;
  568.     val.i_int = 0;
  569.     p_hotkeys = p_intf->p_vlc->p_hotkeys;
  570.     i_pressed_modifiers = [o_event modifierFlags];
  571.     if( i_pressed_modifiers & NSShiftKeyMask )
  572.         val.i_int |= KEY_MODIFIER_SHIFT;
  573.     if( i_pressed_modifiers & NSControlKeyMask )
  574.         val.i_int |= KEY_MODIFIER_CTRL;
  575.     if( i_pressed_modifiers & NSAlternateKeyMask )
  576.         val.i_int |= KEY_MODIFIER_ALT;
  577.     if( i_pressed_modifiers & NSCommandKeyMask )
  578.         val.i_int |= KEY_MODIFIER_COMMAND;
  579.     key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
  580.     val.i_int |= CocoaKeyToVLC( key );
  581.     for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
  582.     {
  583.         if( p_hotkeys[i].i_key == val.i_int )
  584.         {
  585.             var_Set( p_intf->p_vlc, "key-pressed", val );
  586.             return YES;
  587.         }
  588.     }
  589.     return NO;
  590. }
  591. - (id)getControls
  592. {
  593.     if ( o_controls )
  594.     {
  595.         return o_controls;
  596.     }
  597.     return nil;
  598. }
  599. - (id)getPlaylist
  600. {
  601.     if ( o_playlist )
  602.     {
  603.         return o_playlist;
  604.     }
  605.     return nil;
  606. }
  607. - (id)getInfo
  608. {
  609.     if ( o_info )
  610.     {
  611.         return o_info;
  612.     }
  613.     return  nil;
  614. }
  615. - (void)manage
  616. {
  617.     NSDate * o_sleep_date;
  618.     playlist_t * p_playlist;
  619.     vlc_value_t val;
  620.     /* new thread requires a new pool */
  621.     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
  622.     vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
  623.     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  624.                                               FIND_ANYWHERE );
  625.     if( p_playlist != NULL )
  626.     {
  627.         var_AddCallback( p_playlist, "intf-change", PlaylistChanged, self );
  628.         var_AddCallback( p_playlist, "item-change", PlaylistChanged, self );
  629.         var_AddCallback( p_playlist, "playlist-current", PlaylistChanged, self );
  630.         vlc_object_release( p_playlist );
  631.     }
  632.     while( !p_intf->b_die )
  633.     {
  634.         vlc_mutex_lock( &p_intf->change_lock );
  635. #define p_input p_intf->p_sys->p_input
  636.         if( p_input == NULL )
  637.         {
  638.             p_input = (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
  639.                                            FIND_ANYWHERE );
  640.             /* Refresh the interface */
  641.             if( p_input )
  642.             {
  643.                 msg_Dbg( p_intf, "input has changed, refreshing interface" );
  644.                 p_intf->p_sys->b_input_update = VLC_TRUE;
  645.             }
  646.         }
  647.         else if( p_input->b_die || p_input->b_dead )
  648.         {
  649.             /* input stopped */
  650.             p_intf->p_sys->b_intf_update = VLC_TRUE;
  651.             p_intf->p_sys->i_play_status = END_S;
  652.             [o_scrollfield setStringValue: _NS("VLC media player") ];
  653.             vlc_object_release( p_input );
  654.             p_input = NULL;
  655.         }
  656. #undef p_input
  657.         vlc_mutex_unlock( &p_intf->change_lock );
  658.         o_sleep_date = [NSDate dateWithTimeIntervalSinceNow: .1];
  659.         [NSThread sleepUntilDate: o_sleep_date];
  660.     }
  661.     [self terminate];
  662.     [o_pool release];
  663. }
  664. - (void)manageIntf:(NSTimer *)o_timer
  665. {
  666.     vlc_value_t val;
  667.     if( p_intf->p_vlc->b_die == VLC_TRUE )
  668.     {
  669.         [o_timer invalidate];
  670.         return;
  671.     }
  672. #define p_input p_intf->p_sys->p_input
  673.     if( p_intf->p_sys->b_input_update )
  674.     {
  675.         /* Called when new input is opened */
  676.         p_intf->p_sys->b_current_title_update = VLC_TRUE;
  677.         p_intf->p_sys->b_intf_update = VLC_TRUE;
  678.         p_intf->p_sys->b_input_update = VLC_FALSE;
  679.     }
  680.     if( p_intf->p_sys->b_intf_update )
  681.     {
  682.         vlc_bool_t b_input = VLC_FALSE;
  683.         vlc_bool_t b_plmul = VLC_FALSE;
  684.         vlc_bool_t b_control = VLC_FALSE;
  685.         vlc_bool_t b_seekable = VLC_FALSE;
  686.         vlc_bool_t b_chapters = VLC_FALSE;
  687.         playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  688.                                                    FIND_ANYWHERE );
  689.         b_plmul = p_playlist->i_size > 1;
  690.         vlc_object_release( p_playlist );
  691.         if( ( b_input = ( p_input != NULL ) ) )
  692.         {
  693.             /* seekable streams */
  694.             var_Get( p_input, "seekable", &val);
  695.             b_seekable = val.b_bool;
  696.             /* check wether slow/fast motion is possible*/
  697.             b_control = p_input->input.b_can_pace_control;
  698.             /* chapters & titles */
  699.             //b_chapters = p_input->stream.i_area_nb > 1;
  700.         }
  701.         [o_btn_stop setEnabled: b_input];
  702.         [o_btn_ff setEnabled: b_seekable];
  703.         [o_btn_rewind setEnabled: b_seekable];
  704.         [o_btn_prev setEnabled: (b_plmul || b_chapters)];
  705.         [o_btn_next setEnabled: (b_plmul || b_chapters)];
  706.         [o_timeslider setFloatValue: 0.0];
  707.         [o_timeslider setEnabled: b_seekable];
  708.         [o_timefield setStringValue: @"0:00:00"];
  709.         p_intf->p_sys->b_intf_update = VLC_FALSE;
  710.     }
  711.     if ( p_intf->p_sys->b_playlist_update )
  712.     {
  713.        [o_playlist playlistUpdated];
  714.         p_intf->p_sys->b_playlist_update = VLC_FALSE;
  715.     }
  716.     if( p_intf->p_sys->b_fullscreen_update )
  717.     {
  718.         playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  719.                                                    FIND_ANYWHERE );
  720.         [o_btn_fullscreen setState: ( var_Get( p_playlist, "fullscreen", &val )>=0 && val.b_bool ) ];
  721.         vlc_object_release( p_playlist );
  722.         p_intf->p_sys->b_fullscreen_update = VLC_FALSE;
  723.     }
  724.     if( p_input && !p_input->b_die )
  725.     {
  726.         vlc_value_t val;
  727.         if( p_intf->p_sys->b_current_title_update )
  728.         {
  729.             NSString *o_temp;
  730.             vout_thread_t *p_vout;
  731.             playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  732.                                                        FIND_ANYWHERE );
  733.             if( p_playlist == NULL )
  734.             {
  735.                 return;
  736.             }
  737.             vlc_mutex_lock( &p_playlist->object_lock );
  738.             o_temp = [NSString stringWithUTF8String:
  739.                 p_playlist->pp_items[p_playlist->i_index]->input.psz_name];
  740.             if( o_temp == NULL )
  741.                 o_temp = [NSString stringWithCString:
  742.                     p_playlist->pp_items[p_playlist->i_index]->input.psz_name];
  743.             vlc_mutex_unlock( &p_playlist->object_lock );
  744.             [o_scrollfield setStringValue: o_temp ];
  745.             /*p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
  746.                                                     FIND_ANYWHERE );
  747.             if( p_vout != NULL )
  748.             {
  749.                 id o_vout_wnd;
  750.                 NSEnumerator * o_enum = [[NSApp orderedWindows] objectEnumerator];
  751.                 while( ( o_vout_wnd = [o_enum nextObject] ) )
  752.                 {
  753.                     if( [[o_vout_wnd className] isEqualToString: @"VLCWindow"] )
  754.                     {
  755.                         ;[o_vout_wnd updateTitle];
  756.                     }
  757.                 }
  758.                 vlc_object_release( (vlc_object_t *)p_vout );
  759.             }*/
  760.             [o_playlist updateRowSelection];
  761.             vlc_object_release( p_playlist );
  762.             p_intf->p_sys->b_current_title_update = FALSE;
  763.         }
  764.         if( p_input && [o_timeslider isEnabled] )
  765.         {
  766.             /* Update the slider */
  767.             vlc_value_t time;
  768.             NSString * o_time;
  769.             mtime_t i_seconds;
  770.             vlc_value_t pos;
  771.             float f_updated;
  772.             var_Get( p_input, "position", &pos );
  773.             f_updated = 10000. * pos.f_float;
  774.             [o_timeslider setFloatValue: f_updated];
  775.             var_Get( p_input, "time", &time );
  776.             i_seconds = time.i_time / 1000000;
  777.             o_time = [NSString stringWithFormat: @"%d:%02d:%02d",
  778.                             (int) (i_seconds / (60 * 60)),
  779.                             (int) (i_seconds / 60 % 60),
  780.                             (int) (i_seconds % 60)];
  781.             [o_timefield setStringValue: o_time];
  782.         }
  783.         /* Manage volume status */
  784.         [self manageVolumeSlider];
  785.         /* Manage Playing status */
  786.         var_Get( p_input, "state", &val );
  787.         if( p_intf->p_sys->i_play_status != val.i_int )
  788.         {
  789.             p_intf->p_sys->i_play_status = val.i_int;
  790.             [self playStatusUpdated: p_intf->p_sys->i_play_status];
  791.         }
  792.     }
  793.     else
  794.     {
  795.         p_intf->p_sys->i_play_status = END_S;
  796.         p_intf->p_sys->b_intf_update = VLC_TRUE;
  797.         [self playStatusUpdated: p_intf->p_sys->i_play_status];
  798.         [self setSubmenusEnabled: FALSE];
  799.     }
  800. #undef p_input
  801.     [self updateMessageArray];
  802.     [NSTimer scheduledTimerWithTimeInterval: 0.3
  803.         target: self selector: @selector(manageIntf:)
  804.         userInfo: nil repeats: FALSE];
  805. }
  806. - (void)setupMenus
  807. {
  808. #define p_input p_intf->p_sys->p_input
  809.     if( p_input != NULL )
  810.     {
  811.         [o_controls setupVarMenuItem: o_mi_program target: (vlc_object_t *)p_input
  812.             var: "program" selector: @selector(toggleVar:)];
  813.         [o_controls setupVarMenuItem: o_mi_title target: (vlc_object_t *)p_input
  814.             var: "title" selector: @selector(toggleVar:)];
  815.         [o_controls setupVarMenuItem: o_mi_chapter target: (vlc_object_t *)p_input
  816.             var: "chapter" selector: @selector(toggleVar:)];
  817.         [o_controls setupVarMenuItem: o_mi_audiotrack target: (vlc_object_t *)p_input
  818.             var: "audio-es" selector: @selector(toggleVar:)];
  819.         [o_controls setupVarMenuItem: o_mi_videotrack target: (vlc_object_t *)p_input
  820.             var: "video-es" selector: @selector(toggleVar:)];
  821.         [o_controls setupVarMenuItem: o_mi_subtitle target: (vlc_object_t *)p_input
  822.             var: "spu-es" selector: @selector(toggleVar:)];
  823.         aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
  824.                                                     FIND_ANYWHERE );
  825.         if ( p_aout != NULL )
  826.         {
  827.             [o_controls setupVarMenuItem: o_mi_channels target: (vlc_object_t *)p_aout
  828.                 var: "audio-channels" selector: @selector(toggleVar:)];
  829.             [o_controls setupVarMenuItem: o_mi_device target: (vlc_object_t *)p_aout
  830.                 var: "audio-device" selector: @selector(toggleVar:)];
  831.             [o_controls setupVarMenuItem: o_mi_visual target: (vlc_object_t *)p_aout
  832.                 var: "visual" selector: @selector(toggleVar:)];
  833.             vlc_object_release( (vlc_object_t *)p_aout );
  834.         }
  835.         vout_thread_t * p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
  836.                                                             FIND_ANYWHERE );
  837.         if ( p_vout != NULL )
  838.         {
  839.             vlc_object_t * p_dec_obj;
  840.             [o_controls setupVarMenuItem: o_mi_screen target: (vlc_object_t *)p_vout
  841.                 var: "video-device" selector: @selector(toggleVar:)];
  842.             [o_controls setupVarMenuItem: o_mi_deinterlace target: (vlc_object_t *)p_vout
  843.                 var: "deinterlace" selector: @selector(toggleVar:)];
  844.             p_dec_obj = (vlc_object_t *)vlc_object_find(
  845.                                                  (vlc_object_t *)p_vout,
  846.                                                  VLC_OBJECT_DECODER,
  847.                                                  FIND_PARENT );
  848.             if ( p_dec_obj != NULL )
  849.             {
  850.                [o_controls setupVarMenuItem: o_mi_ffmpeg_pp target:
  851.                     (vlc_object_t *)p_dec_obj var:"ffmpeg-pp-q" selector:
  852.                     @selector(toggleVar:)];
  853.                 vlc_object_release(p_dec_obj);
  854.             }
  855.             vlc_object_release( (vlc_object_t *)p_vout );
  856.         }
  857.     }
  858. #undef p_input
  859. }
  860. - (void)updateMessageArray
  861. {
  862.     int i_start, i_stop;
  863.     vlc_value_t quiet;
  864.     vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
  865.     i_stop = *p_intf->p_sys->p_sub->pi_stop;
  866.     vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
  867.     if( p_intf->p_sys->p_sub->i_start != i_stop )
  868.     {
  869.         NSColor *o_white = [NSColor whiteColor];
  870.         NSColor *o_red = [NSColor redColor];
  871.         NSColor *o_yellow = [NSColor yellowColor];
  872.         NSColor *o_gray = [NSColor grayColor];
  873.         NSColor * pp_color[4] = { o_white, o_red, o_yellow, o_gray };
  874.         static const char * ppsz_type[4] = { ": ", " error: ",
  875.                                              " warning: ", " debug: " };
  876.         for( i_start = p_intf->p_sys->p_sub->i_start;
  877.              i_start != i_stop;
  878.              i_start = (i_start+1) % VLC_MSG_QSIZE )
  879.         {
  880.             NSString *o_msg;
  881.             NSDictionary *o_attr;
  882.             NSAttributedString *o_msg_color;
  883.             int i_type = p_intf->p_sys->p_sub->p_msg[i_start].i_type;
  884.             [o_msg_lock lock];
  885.             if( [o_msg_arr count] + 2 > 400 )
  886.             {
  887.                 unsigned rid[] = { 0, 1 };
  888.                 [o_msg_arr removeObjectsFromIndices: (unsigned *)&rid
  889.                            numIndices: sizeof(rid)/sizeof(rid[0])];
  890.             }
  891.             o_attr = [NSDictionary dictionaryWithObject: o_gray
  892.                 forKey: NSForegroundColorAttributeName];
  893.             o_msg = [NSString stringWithFormat: @"%s%s",
  894.                 p_intf->p_sys->p_sub->p_msg[i_start].psz_module,
  895.                 ppsz_type[i_type]];
  896.             o_msg_color = [[NSAttributedString alloc]
  897.                 initWithString: o_msg attributes: o_attr];
  898.             [o_msg_arr addObject: [o_msg_color autorelease]];
  899.             o_attr = [NSDictionary dictionaryWithObject: pp_color[i_type]
  900.                 forKey: NSForegroundColorAttributeName];
  901.             o_msg = [NSString stringWithFormat: @"%sn",
  902.                 p_intf->p_sys->p_sub->p_msg[i_start].psz_msg];
  903.             o_msg_color = [[NSAttributedString alloc]
  904.                 initWithString: o_msg attributes: o_attr];
  905.             [o_msg_arr addObject: [o_msg_color autorelease]];
  906.             [o_msg_lock unlock];
  907.             var_Get( p_intf->p_vlc, "verbose", &quiet );
  908.             if( i_type == 1 && quiet.i_int > -1 )
  909.             {
  910.                 NSString *o_my_msg = [NSString stringWithFormat: @"%s: %sn",
  911.                     p_intf->p_sys->p_sub->p_msg[i_start].psz_module,
  912.                     p_intf->p_sys->p_sub->p_msg[i_start].psz_msg];
  913.                 NSRange s_r = NSMakeRange( [[o_err_msg string] length], 0 );
  914.                 [o_err_msg setEditable: YES];
  915.                 [o_err_msg setSelectedRange: s_r];
  916.                 [o_err_msg insertText: o_my_msg];
  917.                 [o_error makeKeyAndOrderFront: self];
  918.                 [o_err_msg setEditable: NO];
  919.             }
  920.         }
  921.         vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
  922.         p_intf->p_sys->p_sub->i_start = i_start;
  923.         vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
  924.     }
  925. }
  926. - (void)playStatusUpdated:(int)i_status
  927. {
  928.     if( i_status == PLAYING_S )
  929.     {
  930.         [o_btn_play setImage: o_img_pause];
  931.         [o_btn_play setAlternateImage: o_img_pause_pressed];
  932.         [o_btn_play setToolTip: _NS("Pause")];
  933.         [o_mi_play setTitle: _NS("Pause")];
  934.         [o_dmi_play setTitle: _NS("Pause")];
  935.     }
  936.     else
  937.     {
  938.         [o_btn_play setImage: o_img_play];
  939.         [o_btn_play setAlternateImage: o_img_play_pressed];
  940.         [o_btn_play setToolTip: _NS("Play")];
  941.         [o_mi_play setTitle: _NS("Play")];
  942.         [o_dmi_play setTitle: _NS("Play")];
  943.     }
  944. }
  945. - (void)setSubmenusEnabled:(BOOL)b_enabled
  946. {
  947.     [o_mi_program setEnabled: b_enabled];
  948.     [o_mi_title setEnabled: b_enabled];
  949.     [o_mi_chapter setEnabled: b_enabled];
  950.     [o_mi_audiotrack setEnabled: b_enabled];
  951.     [o_mi_visual setEnabled: b_enabled];
  952.     [o_mi_videotrack setEnabled: b_enabled];
  953.     [o_mi_subtitle setEnabled: b_enabled];
  954.     [o_mi_channels setEnabled: b_enabled];
  955.     [o_mi_deinterlace setEnabled: b_enabled];
  956.     [o_mi_ffmpeg_pp setEnabled: b_enabled];
  957.     [o_mi_device setEnabled: b_enabled];
  958.     [o_mi_screen setEnabled: b_enabled];
  959. }
  960. - (void)manageVolumeSlider
  961. {
  962.     audio_volume_t i_volume;
  963.     aout_VolumeGet( p_intf, &i_volume );
  964.     [o_volumeslider setFloatValue: (float)i_volume / AOUT_VOLUME_STEP];
  965.     [o_volumeslider setEnabled: TRUE];
  966.     p_intf->p_sys->b_mute = ( i_volume == 0 );
  967. }
  968. - (IBAction)timesliderUpdate:(id)sender
  969. {
  970. #define p_input p_intf->p_sys->p_input
  971.     float f_updated;
  972.     switch( [[NSApp currentEvent] type] )
  973.     {
  974.         case NSLeftMouseUp:
  975.         case NSLeftMouseDown:
  976.         case NSLeftMouseDragged:
  977.             f_updated = [sender floatValue];
  978.             break;
  979.         default:
  980.             return;
  981.     }
  982.     if( p_input != NULL )
  983.     {
  984.         vlc_value_t time;
  985.         vlc_value_t pos;
  986.         mtime_t i_seconds;
  987.         NSString * o_time;
  988.         pos.f_float = f_updated / 10000.;
  989.         var_Set( p_input, "position", pos );
  990.         [o_timeslider setFloatValue: f_updated];
  991.         var_Get( p_input, "time", &time );
  992.         i_seconds = time.i_time / 1000000;
  993.         o_time = [NSString stringWithFormat: @"%d:%02d:%02d",
  994.                         (int) (i_seconds / (60 * 60)),
  995.                         (int) (i_seconds / 60 % 60),
  996.                         (int) (i_seconds % 60)];
  997.         [o_timefield setStringValue: o_time];
  998.     }
  999. #undef p_input
  1000. }
  1001. - (void)terminate
  1002. {
  1003.     playlist_t * p_playlist;
  1004.     vout_thread_t * p_vout;
  1005.     /* Stop playback */
  1006.     if( ( p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
  1007.                                         FIND_ANYWHERE ) ) )
  1008.     {
  1009.         playlist_Stop( p_playlist );
  1010.         vlc_object_release( p_playlist );
  1011.     }
  1012.     /* FIXME - Wait here until all vouts are terminated because
  1013.        libvlc's VLC_CleanUp destroys interfaces before vouts, which isn't
  1014.        good on OS X. We definitly need a cleaner way to handle this,
  1015.        but this may hopefully be good enough for now.
  1016.          -- titer 2003/11/22 */
  1017.     while( ( p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
  1018.                                        FIND_ANYWHERE ) ) )
  1019.     {
  1020.         vlc_object_release( p_vout );
  1021.         msleep( 100000 );
  1022.     }
  1023.     msleep( 500000 );
  1024.     if( o_img_pause_pressed != nil )
  1025.     {
  1026.         [o_img_pause_pressed release];
  1027.         o_img_pause_pressed = nil;
  1028.     }
  1029.     if( o_img_pause_pressed != nil )
  1030.     {
  1031.         [o_img_pause_pressed release];
  1032.         o_img_pause_pressed = nil;
  1033.     }
  1034.     if( o_img_pause != nil )
  1035.     {
  1036.         [o_img_pause release];
  1037.         o_img_pause = nil;
  1038.     }
  1039.     if( o_img_play != nil )
  1040.     {
  1041.         [o_img_play release];
  1042.         o_img_play = nil;
  1043.     }
  1044.     if( o_msg_arr != nil )
  1045.     {
  1046.         [o_msg_arr removeAllObjects];
  1047.         [o_msg_arr release];
  1048.         o_msg_arr = nil;
  1049.     }
  1050.     if( o_msg_lock != nil )
  1051.     {
  1052.         [o_msg_lock release];
  1053.         o_msg_lock = nil;
  1054.     }
  1055.     /* write cached user defaults to disk */
  1056.     [[NSUserDefaults standardUserDefaults] synchronize];
  1057.     p_intf->b_die = VLC_TRUE;
  1058.     [NSApp stop:NULL];
  1059. }
  1060. - (IBAction)clearRecentItems:(id)sender
  1061. {
  1062.     [[NSDocumentController sharedDocumentController]
  1063.                           clearRecentDocuments: nil];
  1064. }
  1065. - (void)openRecentItem:(id)sender
  1066. {
  1067.     [self application: nil openFile: [sender title]];
  1068. }
  1069. - (IBAction)viewPreferences:(id)sender
  1070. {
  1071.     [o_prefs showPrefs];
  1072. }
  1073. - (IBAction)closeError:(id)sender
  1074. {
  1075.     vlc_value_t val;
  1076.     if( [o_err_ckbk_surpress state] == NSOnState )
  1077.     {
  1078.         val.i_int = -1;
  1079.         var_Set( p_intf->p_vlc, "verbose", val );
  1080.     }
  1081.     [o_err_msg setString: @""];
  1082.     [o_error performClose: self];
  1083. }
  1084. - (IBAction)openReadMe:(id)sender
  1085. {
  1086.     NSString * o_path = [[NSBundle mainBundle]
  1087.         pathForResource: @"README.MacOSX" ofType: @"rtf"];
  1088.     [[NSWorkspace sharedWorkspace] openFile: o_path
  1089.                                    withApplication: @"TextEdit"];
  1090. }
  1091. - (IBAction)openDocumentation:(id)sender
  1092. {
  1093.     NSURL * o_url = [NSURL URLWithString:
  1094.         @"http://www.videolan.org/doc/"];
  1095.     [[NSWorkspace sharedWorkspace] openURL: o_url];
  1096. }
  1097. - (IBAction)reportABug:(id)sender
  1098. {
  1099.     NSURL * o_url = [NSURL URLWithString:
  1100.         @"http://www.videolan.org/support/bug-reporting.html"];
  1101.     [[NSWorkspace sharedWorkspace] openURL: o_url];
  1102. }
  1103. - (IBAction)openWebsite:(id)sender
  1104. {
  1105.     NSURL * o_url = [NSURL URLWithString: @"http://www.videolan.org/"];
  1106.     [[NSWorkspace sharedWorkspace] openURL: o_url];
  1107. }
  1108. - (IBAction)openLicense:(id)sender
  1109. {
  1110.     NSString * o_path = [[NSBundle mainBundle]
  1111.         pathForResource: @"COPYING" ofType: nil];
  1112.     [[NSWorkspace sharedWorkspace] openFile: o_path
  1113.                                    withApplication: @"TextEdit"];
  1114. }
  1115. - (IBAction)openCrashLog:(id)sender
  1116. {
  1117.     NSString * o_path = [@"~/Library/Logs/CrashReporter/VLC.crash.log"
  1118.                                     stringByExpandingTildeInPath];
  1119.     if ( [[NSFileManager defaultManager] fileExistsAtPath: o_path ] )
  1120.     {
  1121.         [[NSWorkspace sharedWorkspace] openFile: o_path
  1122.                                     withApplication: @"Console"];
  1123.     }
  1124.     else
  1125.     {
  1126.         NSBeginInformationalAlertSheet(_NS("No CrashLog found"), @"Continue", nil, nil, o_msgs_panel, self, NULL, NULL, nil, _NS("Either you are running Mac OS X pre 10.2 or you haven't experienced any heavy crashes yet.") );
  1127.     }
  1128. }
  1129. - (void)windowDidBecomeKey:(NSNotification *)o_notification
  1130. {
  1131.     if( [o_notification object] == o_msgs_panel )
  1132.     {
  1133.         id o_msg;
  1134.         NSEnumerator * o_enum;
  1135.         [o_messages setString: @""];
  1136.         [o_msg_lock lock];
  1137.         o_enum = [o_msg_arr objectEnumerator];
  1138.         while( ( o_msg = [o_enum nextObject] ) != nil )
  1139.         {
  1140.             [o_messages insertText: o_msg];
  1141.         }
  1142.         [o_msg_lock unlock];
  1143.     }
  1144. }
  1145. @end
  1146. @implementation VLCMain (NSMenuValidation)
  1147. - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
  1148. {
  1149.     NSString *o_title = [o_mi title];
  1150.     BOOL bEnabled = TRUE;
  1151.     if( [o_title isEqualToString: _NS("License")] )
  1152.     {
  1153.         /* we need to do this only once */
  1154.         [self setupMenus];
  1155.     }
  1156.     /* Recent Items Menu */
  1157.     if( [o_title isEqualToString: _NS("Clear Menu")] )
  1158.     {
  1159.         NSMenu * o_menu = [o_mi_open_recent submenu];
  1160.         int i_nb_items = [o_menu numberOfItems];
  1161.         NSArray * o_docs = [[NSDocumentController sharedDocumentController]
  1162.                                                        recentDocumentURLs];
  1163.         UInt32 i_nb_docs = [o_docs count];
  1164.         if( i_nb_items > 1 )
  1165.         {
  1166.             while( --i_nb_items )
  1167.             {
  1168.                 [o_menu removeItemAtIndex: 0];
  1169.             }
  1170.         }
  1171.         if( i_nb_docs > 0 )
  1172.         {
  1173.             NSURL * o_url;
  1174.             NSString * o_doc;
  1175.             [o_menu insertItem: [NSMenuItem separatorItem] atIndex: 0];
  1176.             while( TRUE )
  1177.             {
  1178.                 i_nb_docs--;
  1179.                 o_url = [o_docs objectAtIndex: i_nb_docs];
  1180.                 if( [o_url isFileURL] )
  1181.                 {
  1182.                     o_doc = [o_url path];
  1183.                 }
  1184.                 else
  1185.                 {
  1186.                     o_doc = [o_url absoluteString];
  1187.                 }
  1188.                 [o_menu insertItemWithTitle: o_doc
  1189.                     action: @selector(openRecentItem:)
  1190.                     keyEquivalent: @"" atIndex: 0];
  1191.                 if( i_nb_docs == 0 )
  1192.                 {
  1193.                     break;
  1194.                 }
  1195.             }
  1196.         }
  1197.         else
  1198.         {
  1199.             bEnabled = FALSE;
  1200.         }
  1201.     }
  1202.     return( bEnabled );
  1203. }
  1204. @end
  1205. @implementation VLCMain (Internal)
  1206. - (void)handlePortMessage:(NSPortMessage *)o_msg
  1207. {
  1208.     id ** val;
  1209.     NSData * o_data;
  1210.     NSValue * o_value;
  1211.     NSInvocation * o_inv;
  1212.     NSConditionLock * o_lock;
  1213.     o_data = [[o_msg components] lastObject];
  1214.     o_inv = *((NSInvocation **)[o_data bytes]);
  1215.     [o_inv getArgument: &o_value atIndex: 2];
  1216.     val = (id **)[o_value pointerValue];
  1217.     [o_inv setArgument: val[1] atIndex: 2];
  1218.     o_lock = *(val[0]);
  1219.     [o_lock lock];
  1220.     [o_inv invoke];
  1221.     [o_lock unlockWithCondition: 1];
  1222. }
  1223. @end