1 /*****************************************************************************
2 * intf.m: MacOS X interface plugin
3 *****************************************************************************
4 * Copyright (C) 2002-2003 VideoLAN
5 * $Id: intf.m,v 1.47 2003/02/06 23:55:28 massiot Exp $
7 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8 * Christophe Massiot <massiot@via.ecp.fr>
9 * Derk-Jan Hartman <thedj@users.sourceforge.net>
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.
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.
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 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
29 #include <stdlib.h> /* malloc(), free() */
30 #include <sys/param.h> /* for MAXPATHLEN */
38 /*****************************************************************************
40 *****************************************************************************/
41 static void Run ( intf_thread_t *p_intf );
43 /*****************************************************************************
44 * OpenIntf: initialize interface
45 *****************************************************************************/
46 int E_(OpenIntf) ( vlc_object_t *p_this )
48 intf_thread_t *p_intf = (intf_thread_t*) p_this;
50 p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
51 if( p_intf->p_sys == NULL )
56 memset( p_intf->p_sys, 0, sizeof( *p_intf->p_sys ) );
58 p_intf->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
59 p_intf->p_sys->o_sendport = [[NSPort port] retain];
61 p_intf->p_sys->p_sub = msg_Subscribe( p_intf );
65 [[VLCApplication sharedApplication] autorelease];
66 [NSApp initIntlSupport];
67 [NSApp setIntf: p_intf];
69 [NSBundle loadNibNamed: @"MainMenu" owner: NSApp];
74 /*****************************************************************************
75 * CloseIntf: destroy interface
76 *****************************************************************************/
77 void E_(CloseIntf) ( vlc_object_t *p_this )
79 intf_thread_t *p_intf = (intf_thread_t*) p_this;
81 msg_Unsubscribe( p_intf, p_intf->p_sys->p_sub );
83 config_SaveConfigFile( p_intf, MODULE_STRING );
85 [p_intf->p_sys->o_sendport release];
86 [p_intf->p_sys->o_pool release];
88 free( p_intf->p_sys );
91 /*****************************************************************************
93 *****************************************************************************/
94 static void Run( intf_thread_t *p_intf )
96 /* Do it again - for some unknown reason, vlc_thread_create() often
97 * fails to go to real-time priority with the first launched thread
99 vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
104 /*****************************************************************************
105 * VLCApplication implementation
106 *****************************************************************************/
107 @implementation VLCApplication
111 /* default encoding: ISO-8859-1 */
112 i_encoding = NSISOLatin1StringEncoding;
114 return( [super init] );
117 - (void)initIntlSupport
119 char *psz_lang = getenv( "LANG" );
121 if( psz_lang == NULL )
126 if( strncmp( psz_lang, "pl", 2 ) == 0 )
128 i_encoding = NSISOLatin2StringEncoding;
130 else if( strncmp( psz_lang, "ja", 2 ) == 0 )
132 i_encoding = NSJapaneseEUCStringEncoding;
134 else if( strncmp( psz_lang, "ru", 2 ) == 0 )
136 #define CFSENC2NSSENC(e) CFStringConvertEncodingToNSStringEncoding(e)
137 i_encoding = CFSENC2NSSENC( kCFStringEncodingKOI8_R );
142 - (NSString *)localizedString:(char *)psz
144 NSString * o_str = nil;
148 UInt32 uiLength = (UInt32)strlen( psz );
149 NSData * o_data = [NSData dataWithBytes: psz length: uiLength];
150 o_str = [[[NSString alloc] initWithData: o_data
151 encoding: i_encoding] autorelease];
157 - (void)setIntf:(intf_thread_t *)_p_intf
162 - (intf_thread_t *)getIntf
167 - (void)terminate:(id)sender
169 p_intf->p_vlc->b_die = VLC_TRUE;
174 int ExecuteOnMainThread( id target, SEL sel, void * p_arg )
178 NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
180 if( [target respondsToSelector: @selector(performSelectorOnMainThread:
181 withObject:waitUntilDone:)] )
183 [target performSelectorOnMainThread: sel
184 withObject: [NSValue valueWithPointer: p_arg]
187 else if( NSApp != nil && [NSApp respondsToSelector: @selector(getIntf)] )
192 NSPort * o_recv_port;
193 NSInvocation * o_inv;
194 NSPortMessage * o_msg;
195 intf_thread_t * p_intf;
196 NSConditionLock * o_lock;
197 NSMethodSignature * o_sig;
199 id * val[] = { &o_lock, &o_v2 };
201 p_intf = (intf_thread_t *)[NSApp getIntf];
203 o_recv_port = [[NSPort port] retain];
204 o_v1 = [NSValue valueWithPointer: val];
205 o_v2 = [NSValue valueWithPointer: p_arg];
207 o_sig = [target methodSignatureForSelector: sel];
208 o_inv = [NSInvocation invocationWithMethodSignature: o_sig];
209 [o_inv setArgument: &o_v1 atIndex: 2];
210 [o_inv setTarget: target];
211 [o_inv setSelector: sel];
213 o_array = [NSArray arrayWithObject:
214 [NSData dataWithBytes: &o_inv length: sizeof(o_inv)]];
215 o_msg = [[NSPortMessage alloc]
216 initWithSendPort: p_intf->p_sys->o_sendport
217 receivePort: o_recv_port components: o_array];
219 o_lock = [[NSConditionLock alloc] initWithCondition: 0];
220 [o_msg sendBeforeDate: [NSDate distantPast]];
221 [o_lock lockWhenCondition: 1];
226 [o_recv_port release];
238 /*****************************************************************************
239 * VLCMain implementation
240 *****************************************************************************/
241 @implementation VLCMain
245 [o_window setTitle: _NS("VLC - Controller")];
246 [o_window setExcludedFromWindowsMenu: TRUE];
248 /* button controls */
249 [o_btn_playlist setToolTip: _NS("Playlist")];
250 [o_btn_prev setToolTip: _NS("Previous")];
251 [o_btn_slower setToolTip: _NS("Slower")];
252 [o_btn_play setToolTip: _NS("Play")];
253 [o_btn_stop setToolTip: _NS("Stop")];
254 [o_btn_faster setToolTip: _NS("Faster")];
255 [o_btn_next setToolTip: _NS("Next")];
256 [o_btn_prefs setToolTip: _NS("Preferences")];
257 [o_volumeslider setToolTip: _NS("Volume")];
258 [o_timeslider setToolTip: _NS("Position")];
261 [o_msgs_panel setDelegate: self];
262 [o_msgs_panel setTitle: _NS("Messages")];
263 [o_msgs_panel setExcludedFromWindowsMenu: TRUE];
264 [o_msgs_btn_ok setTitle: _NS("Close")];
265 [o_msgs_btn_crashlog setTitle: _NS("Open CrashLog")];
268 [o_mi_about setTitle: _NS("About VLC Media Player")];
269 [o_mi_prefs setTitle: _NS("Preferences")];
270 [o_mi_hide setTitle: _NS("Hide VLC")];
271 [o_mi_hide_others setTitle: _NS("Hide Others")];
272 [o_mi_show_all setTitle: _NS("Show All")];
273 [o_mi_quit setTitle: _NS("Quit VLC")];
275 [o_mu_file setTitle: _NS("File")];
276 [o_mi_open_generic setTitle: _NS("Open...")];
277 [o_mi_open_file setTitle: _NS("Open File...")];
278 [o_mi_open_disc setTitle: _NS("Open Disc...")];
279 [o_mi_open_net setTitle: _NS("Open Network...")];
280 [o_mi_open_recent setTitle: _NS("Open Recent")];
281 [o_mi_open_recent_cm setTitle: _NS("Clear Menu")];
283 [o_mu_edit setTitle: _NS("Edit")];
284 [o_mi_cut setTitle: _NS("Cut")];
285 [o_mi_copy setTitle: _NS("Copy")];
286 [o_mi_paste setTitle: _NS("Paste")];
287 [o_mi_clear setTitle: _NS("Clear")];
288 [o_mi_select_all setTitle: _NS("Select All")];
290 [o_mu_controls setTitle: _NS("Controls")];
291 [o_mi_play setTitle: _NS("Play")];
292 [o_mi_stop setTitle: _NS("Stop")];
293 [o_mi_faster setTitle: _NS("Faster")];
294 [o_mi_slower setTitle: _NS("Slower")];
295 [o_mi_previous setTitle: _NS("Previous")];
296 [o_mi_next setTitle: _NS("Next")];
297 [o_mi_loop setTitle: _NS("Loop")];
298 [o_mi_program setTitle: _NS("Program")];
299 [o_mi_title setTitle: _NS("Title")];
300 [o_mi_chapter setTitle: _NS("Chapter")];
301 [o_mi_language setTitle: _NS("Language")];
302 [o_mi_subtitle setTitle: _NS("Subtitles")];
304 [o_mu_audio setTitle: _NS("Audio")];
305 [o_mi_vol_up setTitle: _NS("Volume Up")];
306 [o_mi_vol_down setTitle: _NS("Volume Down")];
307 [o_mi_mute setTitle: _NS("Mute")];
308 [o_mi_channels setTitle: _NS("Channels")];
309 [o_mi_device setTitle: _NS("Device")];
311 [o_mu_video setTitle: _NS("Video")];
312 [o_mi_fullscreen setTitle: _NS("Fullscreen")];
313 [o_mi_screen setTitle: _NS("Screen")];
314 [o_mi_deinterlace setTitle: _NS("Deinterlace")];
316 [o_mu_window setTitle: _NS("Window")];
317 [o_mi_minimize setTitle: _NS("Minimize Window")];
318 [o_mi_close_window setTitle: _NS("Close Window")];
319 [o_mi_controller setTitle: _NS("Controller")];
320 [o_mi_playlist setTitle: _NS("Playlist")];
321 [o_mi_messages setTitle: _NS("Messages")];
323 [o_mi_bring_atf setTitle: _NS("Bring All to Front")];
325 [o_mu_help setTitle: _NS("Help")];
326 [o_mi_readme setTitle: _NS("ReadMe...")];
327 [o_mi_reportabug setTitle: _NS("Report A Bug")];
328 [o_mi_website setTitle: _NS("VideoLAN Website")];
329 [o_mi_license setTitle: _NS("License")];
332 [o_dmi_play setTitle: _NS("Play")];
333 [o_dmi_stop setTitle: _NS("Stop")];
334 [o_dmi_next setTitle: _NS("Next")];
335 [o_dmi_previous setTitle: _NS("Previous")];
338 [o_error setTitle: _NS("Error")];
339 [o_err_lbl setStringValue: _NS("An error has occurred which probably prevented the execution of your request:")];
340 [o_err_bug_lbl setStringValue: _NS("If you believe that it is a bug, please follow the instructions at:")];
341 [o_err_btn_msgs setTitle: _NS("Open Messages Window")];
342 [o_err_btn_dismiss setTitle: _NS("Dismiss")];
344 [self setSubmenusEnabled: FALSE];
345 [self manageVolumeSlider];
348 - (void)applicationWillFinishLaunching:(NSNotification *)o_notification
350 intf_thread_t * p_intf = [NSApp getIntf];
352 o_msg_lock = [[NSLock alloc] init];
353 o_msg_arr = [[NSMutableArray arrayWithCapacity: 200] retain];
355 o_img_play = [[NSImage imageNamed: @"play"] retain];
356 o_img_pause = [[NSImage imageNamed: @"pause"] retain];
358 [p_intf->p_sys->o_sendport setDelegate: self];
359 [[NSRunLoop currentRunLoop]
360 addPort: p_intf->p_sys->o_sendport
361 forMode: NSDefaultRunLoopMode];
363 [NSTimer scheduledTimerWithTimeInterval: 0.5
364 target: self selector: @selector(manageIntf:)
365 userInfo: nil repeats: TRUE];
367 [NSThread detachNewThreadSelector: @selector(manage)
368 toTarget: self withObject: nil];
371 - (BOOL)application:(NSApplication *)o_app openFile:(NSString *)o_filename
373 [o_playlist appendArray:
374 [NSArray arrayWithObject: o_filename] atPos: -1 enqueue: NO];
381 NSDate * o_sleep_date;
382 intf_thread_t * p_intf = [NSApp getIntf];
383 NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
385 vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_LOW );
387 while( !p_intf->b_die )
389 playlist_t * p_playlist;
391 vlc_mutex_lock( &p_intf->change_lock );
393 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
396 if( p_playlist != NULL )
398 vlc_mutex_lock( &p_playlist->object_lock );
400 [self manage: p_playlist];
402 vlc_mutex_unlock( &p_playlist->object_lock );
403 vlc_object_release( p_playlist );
406 vlc_mutex_unlock( &p_intf->change_lock );
408 o_sleep_date = [NSDate dateWithTimeIntervalSinceNow: .5];
409 [NSThread sleepUntilDate: o_sleep_date];
417 - (void)manage:(playlist_t *)p_playlist
419 intf_thread_t * p_intf = [NSApp getIntf];
421 #define p_input p_playlist->p_input
425 vout_thread_t * p_vout = NULL;
426 aout_instance_t * p_aout = NULL;
427 vlc_bool_t b_need_menus = VLC_FALSE;
429 vlc_mutex_lock( &p_input->stream.stream_lock );
431 if( !p_input->b_die )
433 /* New input or stream map change */
434 if( p_input->stream.b_changed )
436 p_intf->p_sys->b_playing = 1;
437 [self manageMode: p_playlist];
438 b_need_menus = VLC_TRUE;
441 if( p_intf->p_sys->i_part !=
442 p_input->stream.p_selected_area->i_part )
444 p_intf->p_sys->b_chapter_update = 1;
445 b_need_menus = VLC_TRUE;
448 p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
453 audio_volume_t i_volume;
455 if( var_Get( (vlc_object_t *)p_aout, "intf-change", &val )
458 p_intf->p_sys->b_aout_update = 1;
459 b_need_menus = VLC_TRUE;
462 aout_VolumeGet( p_aout, &i_volume );
463 vlc_object_release( (vlc_object_t *)p_aout );
465 p_intf->p_sys->b_mute = ( i_volume == 0 );
468 p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
474 if( var_Get( (vlc_object_t *)p_vout, "intf-change", &val )
477 p_intf->p_sys->b_vout_update = 1;
478 b_need_menus = VLC_TRUE;
481 vlc_object_release( (vlc_object_t *)p_vout );
486 [self setupMenus: p_input];
490 vlc_mutex_unlock( &p_input->stream.stream_lock );
492 else if( p_intf->p_sys->b_playing && !p_intf->b_die )
494 p_intf->p_sys->b_playing = 0;
495 [self manageMode: p_playlist];
501 - (void)manageMode:(playlist_t *)p_playlist
503 intf_thread_t * p_intf = [NSApp getIntf];
505 if( p_playlist->p_input != NULL )
507 /* get ready for menu regeneration */
508 p_intf->p_sys->b_program_update = 1;
509 p_intf->p_sys->b_title_update = 1;
510 p_intf->p_sys->b_chapter_update = 1;
511 p_intf->p_sys->b_audio_update = 1;
512 p_intf->p_sys->b_spu_update = 1;
513 p_intf->p_sys->i_part = 0;
515 p_playlist->p_input->stream.b_changed = 0;
516 msg_Dbg( p_intf, "stream has changed, refreshing interface" );
520 vout_thread_t * p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
524 vlc_object_detach( p_vout );
525 vlc_object_release( p_vout );
527 vlc_mutex_unlock( &p_playlist->object_lock );
528 vout_Destroy( p_vout );
529 vlc_mutex_lock( &p_playlist->object_lock );
532 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
536 vlc_object_detach( (vlc_object_t *)p_aout );
537 vlc_object_release( (vlc_object_t *)p_aout );
538 aout_Delete( p_aout );
542 p_intf->p_sys->b_intf_update = VLC_TRUE;
545 - (void)manageIntf:(NSTimer *)o_timer
547 intf_thread_t * p_intf = [NSApp getIntf];
549 if( p_intf->p_vlc->b_die == VLC_TRUE )
551 [o_timer invalidate];
555 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
558 if( p_playlist == NULL )
563 vlc_mutex_lock( &p_playlist->object_lock );
565 #define p_input p_playlist->p_input
567 if( p_input != NULL )
569 vlc_mutex_lock( &p_input->stream.stream_lock );
572 if( p_intf->p_sys->b_intf_update )
574 vlc_bool_t b_input = VLC_FALSE;
575 vlc_bool_t b_plmul = VLC_FALSE;
576 vlc_bool_t b_control = VLC_FALSE;
577 vlc_bool_t b_seekable = VLC_FALSE;
578 vlc_bool_t b_chapters = VLC_FALSE;
580 b_plmul = p_playlist->i_size > 1;
582 if( ( b_input = ( p_input != NULL ) ) )
584 /* seekable streams */
585 b_seekable = p_input->stream.b_seekable;
587 /* control buttons for free pace streams */
588 b_control = p_input->stream.b_pace_control;
591 b_chapters = p_input->stream.p_selected_area->i_part_nb > 1;
594 p_intf->p_sys->b_play_status =
595 p_input->stream.control.i_status != PAUSE_S;
600 p_intf->p_sys->b_play_status = VLC_FALSE;
602 [self setSubmenusEnabled: FALSE];
605 [self playStatusUpdated: p_intf->p_sys->b_play_status];
607 [o_btn_stop setEnabled: b_input];
608 [o_btn_faster setEnabled: b_control];
609 [o_btn_slower setEnabled: b_control];
610 [o_btn_prev setEnabled: (b_plmul || b_chapters)];
611 [o_btn_next setEnabled: (b_plmul || b_chapters)];
613 [o_timeslider setFloatValue: 0.0];
614 [o_timeslider setEnabled: b_seekable];
615 [o_timefield setStringValue: @"0:00:00"];
617 [self manageVolumeSlider];
619 p_intf->p_sys->b_intf_update = VLC_FALSE;
622 #define p_area p_input->stream.p_selected_area
624 if( p_intf->p_sys->b_playing && p_input != NULL )
626 vlc_bool_t b_field_update = VLC_TRUE;
628 if( !p_input->b_die && ( p_intf->p_sys->b_play_status !=
629 ( p_input->stream.control.i_status != PAUSE_S ) ) )
631 p_intf->p_sys->b_play_status =
632 !p_intf->p_sys->b_play_status;
634 [self playStatusUpdated: p_intf->p_sys->b_play_status];
637 if( p_input->stream.b_seekable )
639 if( f_slider == f_slider_old )
641 float f_updated = ( 100. * p_area->i_tell ) /
644 if( f_slider != f_updated )
646 [o_timeslider setFloatValue: f_updated];
651 off_t i_seek = ( f_slider * p_area->i_size ) / 100;
653 /* release the lock to be able to seek */
654 vlc_mutex_unlock( &p_input->stream.stream_lock );
655 input_Seek( p_input, i_seek, INPUT_SEEK_SET );
656 vlc_mutex_lock( &p_input->stream.stream_lock );
658 /* update the old value */
659 f_slider_old = f_slider;
661 b_field_update = VLC_FALSE;
668 char psz_time[ OFFSETTOTIME_MAX_SIZE ];
670 input_OffsetToTime( p_input, psz_time, p_area->i_tell );
672 o_time = [NSString stringWithCString: psz_time];
673 [o_timefield setStringValue: o_time];
676 /* disable screen saver */
677 UpdateSystemActivity( UsrActivity );
682 if( p_input != NULL )
684 vlc_mutex_unlock( &p_input->stream.stream_lock );
689 vlc_mutex_unlock( &p_playlist->object_lock );
690 vlc_object_release( p_playlist );
692 [self updateMessageArray];
695 - (void)updateMessageArray
698 intf_thread_t * p_intf = [NSApp getIntf];
700 vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
701 i_stop = *p_intf->p_sys->p_sub->pi_stop;
702 vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
704 if( p_intf->p_sys->p_sub->i_start != i_stop )
706 NSColor *o_white = [NSColor whiteColor];
707 NSColor *o_red = [NSColor redColor];
708 NSColor *o_yellow = [NSColor yellowColor];
709 NSColor *o_gray = [NSColor grayColor];
711 NSColor * pp_color[4] = { o_white, o_red, o_yellow, o_gray };
712 static const char * ppsz_type[4] = { ": ", " error: ",
713 " warning: ", " debug: " };
715 for( i_start = p_intf->p_sys->p_sub->i_start;
717 i_start = (i_start+1) % VLC_MSG_QSIZE )
720 NSDictionary *o_attr;
721 NSAttributedString *o_msg_color;
723 int i_type = p_intf->p_sys->p_sub->p_msg[i_start].i_type;
727 if( [o_msg_arr count] + 2 > 200 )
729 unsigned rid[] = { 0, 1 };
730 [o_msg_arr removeObjectsFromIndices: (unsigned *)&rid
731 numIndices: sizeof(rid)/sizeof(rid[0])];
734 o_attr = [NSDictionary dictionaryWithObject: o_gray
735 forKey: NSForegroundColorAttributeName];
736 o_msg = [NSString stringWithFormat: @"%s%s",
737 p_intf->p_sys->p_sub->p_msg[i_start].psz_module,
739 o_msg_color = [[NSAttributedString alloc]
740 initWithString: o_msg attributes: o_attr];
741 [o_msg_arr addObject: [o_msg_color autorelease]];
743 o_attr = [NSDictionary dictionaryWithObject: pp_color[i_type]
744 forKey: NSForegroundColorAttributeName];
745 o_msg = [NSString stringWithFormat: @"%s\n",
746 p_intf->p_sys->p_sub->p_msg[i_start].psz_msg];
747 o_msg_color = [[NSAttributedString alloc]
748 initWithString: o_msg attributes: o_attr];
749 [o_msg_arr addObject: [o_msg_color autorelease]];
755 NSString *o_my_msg = [NSString stringWithFormat: @"%s: %s\n",
756 p_intf->p_sys->p_sub->p_msg[i_start].psz_module,
757 p_intf->p_sys->p_sub->p_msg[i_start].psz_msg];
759 NSRange s_r = NSMakeRange( [[o_err_msg string] length], 0 );
760 [o_err_msg setEditable: YES];
761 [o_err_msg setSelectedRange: s_r];
762 [o_err_msg insertText: o_my_msg];
764 [o_error makeKeyAndOrderFront: self];
765 [o_err_msg setEditable: NO];
769 vlc_mutex_lock( p_intf->p_sys->p_sub->p_lock );
770 p_intf->p_sys->p_sub->i_start = i_start;
771 vlc_mutex_unlock( p_intf->p_sys->p_sub->p_lock );
775 - (void)playStatusUpdated:(BOOL)b_pause
779 [o_btn_play setImage: o_img_pause];
780 [o_btn_play setToolTip: _NS("Pause")];
781 [o_mi_play setTitle: _NS("Pause")];
782 [o_dmi_play setTitle: _NS("Pause")];
786 [o_btn_play setImage: o_img_play];
787 [o_btn_play setToolTip: _NS("Play")];
788 [o_mi_play setTitle: _NS("Play")];
789 [o_dmi_play setTitle: _NS("Play")];
793 - (void)setSubmenusEnabled:(BOOL)b_enabled
795 [o_mi_program setEnabled: b_enabled];
796 [o_mi_title setEnabled: b_enabled];
797 [o_mi_chapter setEnabled: b_enabled];
798 [o_mi_language setEnabled: b_enabled];
799 [o_mi_subtitle setEnabled: b_enabled];
800 [o_mi_channels setEnabled: b_enabled];
801 [o_mi_device setEnabled: b_enabled];
802 [o_mi_screen setEnabled: b_enabled];
805 - (void)manageVolumeSlider
807 audio_volume_t i_volume;
808 vlc_bool_t b_audio = VLC_FALSE;
809 intf_thread_t * p_intf = [NSApp getIntf];
811 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
817 aout_VolumeGet( p_aout, &i_volume );
818 vlc_object_release( (vlc_object_t *)p_aout );
822 i_volume = (audio_volume_t)config_GetInt( p_intf, "volume" );
825 [o_volumeslider setFloatValue: (float)i_volume / AOUT_VOLUME_STEP];
826 [o_volumeslider setEnabled: b_audio];
828 p_intf->p_sys->b_mute = ( i_volume == 0 );
834 vout_thread_t * p_vout;
835 playlist_t * p_playlist;
836 intf_thread_t * p_intf = [NSApp getIntf];
841 msg_Dbg( p_intf, "removing all playlists" );
842 while( (p_playlist = vlc_object_find( p_intf->p_vlc, VLC_OBJECT_PLAYLIST,
845 vlc_object_detach( p_playlist );
846 vlc_object_release( p_playlist );
847 playlist_Destroy( p_playlist );
853 msg_Dbg( p_intf, "removing all video outputs" );
854 while( (p_vout = vlc_object_find( p_intf->p_vlc,
855 VLC_OBJECT_VOUT, FIND_CHILD )) )
857 vlc_object_detach( p_vout );
858 vlc_object_release( p_vout );
859 vout_Destroy( p_vout );
862 if( o_img_pause != nil )
864 [o_img_pause release];
868 if( o_img_play != nil )
870 [o_img_play release];
874 if( o_msg_arr != nil )
876 [o_msg_arr removeAllObjects];
881 if( o_msg_lock != nil )
883 [o_msg_lock release];
895 /* write cached user defaults to disk */
896 [[NSUserDefaults standardUserDefaults] synchronize];
898 /* send a dummy event to break out of the event loop */
899 o_event = [NSEvent mouseEventWithType: NSLeftMouseDown
900 location: NSMakePoint( 1, 1 ) modifierFlags: 0
901 timestamp: 1 windowNumber: [[NSApp mainWindow] windowNumber]
902 context: [NSGraphicsContext currentContext] eventNumber: 1
903 clickCount: 1 pressure: 0.0];
904 [NSApp postEvent: o_event atStart: YES];
907 - (void)setupMenus:(input_thread_t *)p_input
909 unsigned int i, i_nb_items;
911 NSString * o_menu_title;
912 char psz_title[ 256 ];
914 es_descriptor_t * p_audio_es = NULL;
915 es_descriptor_t * p_spu_es = NULL;
917 intf_thread_t * p_intf = [NSApp getIntf];
919 p_intf->p_sys->b_chapter_update |= p_intf->p_sys->b_title_update;
920 p_intf->p_sys->b_audio_update |= p_intf->p_sys->b_title_update |
921 p_intf->p_sys->b_program_update;
922 p_intf->p_sys->b_spu_update |= p_intf->p_sys->b_title_update |
923 p_intf->p_sys->b_program_update;
925 if( p_intf->p_sys->b_program_update )
928 SEL pf_toggle_program;
929 pgrm_descriptor_t * p_pgrm;
931 if( p_input->stream.p_new_program )
933 p_pgrm = p_input->stream.p_new_program;
937 p_pgrm = p_input->stream.p_selected_program;
940 o_program = [o_mi_program submenu];
941 pf_toggle_program = @selector(toggleProgram:);
943 /* remove previous program items */
944 i_nb_items = [o_program numberOfItems];
945 for( i = 0; i < i_nb_items; i++ )
947 [o_program removeItemAtIndex: 0];
950 /* make (un)sensitive */
951 [o_mi_program setEnabled:
952 p_input->stream.i_pgrm_number > 1];
954 /* add program items */
955 for( i = 0 ; i < p_input->stream.i_pgrm_number ; i++ )
957 snprintf( psz_title, sizeof(psz_title), "id %d",
958 p_input->stream.pp_programs[i]->i_number );
959 psz_title[sizeof(psz_title) - 1] = '\0';
961 o_menu_title = [NSApp localizedString: psz_title];
963 o_item = [o_program addItemWithTitle: o_menu_title
964 action: pf_toggle_program keyEquivalent: @""];
965 [o_item setTag: p_input->stream.pp_programs[i]->i_number];
966 [o_item setTarget: o_controls];
968 if( p_pgrm == p_input->stream.pp_programs[i] )
970 [o_item setState: NSOnState];
974 p_intf->p_sys->b_program_update = 0;
977 if( p_intf->p_sys->b_title_update )
982 o_title = [o_mi_title submenu];
983 pf_toggle_title = @selector(toggleTitle:);
985 /* remove previous title items */
986 i_nb_items = [o_title numberOfItems];
987 for( i = 0; i < i_nb_items; i++ )
989 [o_title removeItemAtIndex: 0];
992 /* make (un)sensitive */
993 [o_mi_title setEnabled:
994 p_input->stream.i_area_nb > 1];
996 /* add title items */
997 for( i = 1 ; i < p_input->stream.i_area_nb ; i++ )
999 snprintf( psz_title, sizeof(psz_title), "Title %d (%d)", i,
1000 p_input->stream.pp_areas[i]->i_part_nb );
1001 psz_title[sizeof(psz_title) - 1] = '\0';
1003 o_menu_title = [NSApp localizedString: psz_title];
1005 o_item = [o_title addItemWithTitle: o_menu_title
1006 action: pf_toggle_title keyEquivalent: @""];
1008 [o_item setTarget: o_controls];
1010 if( ( p_input->stream.pp_areas[i] ==
1011 p_input->stream.p_selected_area ) )
1013 [o_item setState: NSOnState];
1017 p_intf->p_sys->b_title_update = 0;
1020 if( p_intf->p_sys->b_chapter_update )
1023 SEL pf_toggle_chapter;
1025 o_chapter = [o_mi_chapter submenu];
1026 pf_toggle_chapter = @selector(toggleChapter:);
1028 /* remove previous chapter items */
1029 i_nb_items = [o_chapter numberOfItems];
1030 for( i = 0; i < i_nb_items; i++ )
1032 [o_chapter removeItemAtIndex: 0];
1035 /* make (un)sensitive */
1036 [o_mi_chapter setEnabled:
1037 p_input->stream.p_selected_area->i_part_nb > 1];
1039 /* add chapter items */
1040 for( i = 0 ; i < p_input->stream.p_selected_area->i_part_nb ; i++ )
1042 snprintf( psz_title, sizeof(psz_title), "Chapter %d", i + 1 );
1043 psz_title[sizeof(psz_title) - 1] = '\0';
1045 o_menu_title = [NSApp localizedString: psz_title];
1047 o_item = [o_chapter addItemWithTitle: o_menu_title
1048 action: pf_toggle_chapter keyEquivalent: @""];
1049 [o_item setTag: i + 1];
1050 [o_item setTarget: o_controls];
1052 if( ( p_input->stream.p_selected_area->i_part == i + 1 ) )
1054 [o_item setState: NSOnState];
1058 p_intf->p_sys->i_part =
1059 p_input->stream.p_selected_area->i_part;
1061 p_intf->p_sys->b_chapter_update = 0;
1064 for( i = 0 ; i < p_input->stream.i_selected_es_number ; i++ )
1066 if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
1068 p_audio_es = p_input->stream.pp_selected_es[i];
1070 else if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
1072 p_spu_es = p_input->stream.pp_selected_es[i];
1076 if( p_intf->p_sys->b_audio_update )
1078 [self setupLangMenu: p_input mi: o_mi_language es: p_audio_es
1079 category: AUDIO_ES selector: @selector(toggleLanguage:)];
1081 p_intf->p_sys->b_audio_update = 0;
1084 if( p_intf->p_sys->b_spu_update )
1086 [self setupLangMenu: p_input mi: o_mi_subtitle es: p_spu_es
1087 category: SPU_ES selector: @selector(toggleLanguage:)];
1089 p_intf->p_sys->b_spu_update = 0;
1092 if ( p_intf->p_sys->b_aout_update )
1094 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
1097 if ( p_aout != NULL )
1102 var_Set( (vlc_object_t *)p_aout, "intf-change", val );
1104 [self setupVarMenu: o_mi_channels target: (vlc_object_t *)p_aout
1105 var: "audio-channels" selector: @selector(toggleVar:)];
1107 [self setupVarMenu: o_mi_device target: (vlc_object_t *)p_aout
1108 var: "audio-device" selector: @selector(toggleVar:)];
1110 vlc_object_release( (vlc_object_t *)p_aout );
1113 p_intf->p_sys->b_aout_update = 0;
1116 if( p_intf->p_sys->b_vout_update )
1118 vout_thread_t * p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
1121 if ( p_vout != NULL )
1126 var_Set( (vlc_object_t *)p_vout, "intf-change", val );
1128 [self setupVarMenu: o_mi_screen target: (vlc_object_t *)p_vout
1129 var: "video-device" selector: @selector(toggleVar:)];
1131 vlc_object_release( (vlc_object_t *)p_vout );
1133 [o_mi_close_window setEnabled: TRUE];
1136 p_intf->p_sys->b_vout_update = 0;
1142 - (void)setupLangMenu:(input_thread_t *)p_input
1143 mi:(NSMenuItem *)o_mi
1144 es:(es_descriptor_t *)p_es
1146 selector:(SEL)pf_callback
1148 unsigned int i, i_nb_items;
1149 NSMenu * o_menu = [o_mi submenu];
1151 /* remove previous language items */
1152 i_nb_items = [o_menu numberOfItems];
1153 for( i = 0; i < i_nb_items; i++ )
1155 [o_menu removeItemAtIndex: 0];
1158 /* make sensitive : we can't change it after we build the menu, and
1159 * before, we don't yet how many items we will have. So make it
1160 * always sensitive. --Meuuh */
1161 [o_mi setEnabled: TRUE];
1164 /* We do not use this code, because you need to start stop .avi for
1165 * it to work, so not very useful now --hartman */
1166 if ( o_mi == o_mi_subtitle ) {
1168 [o_mi setEnabled: TRUE ];
1171 o_title = _NS("Load from file..");
1172 o_lmi = [o_menu addItemWithTitle: o_title
1173 action: pf_callback keyEquivalent: @""];
1174 [o_lmi setTag: 2000];
1175 [o_lmi setTarget: o_controls];
1179 #define ES p_input->stream.pp_es[i]
1180 for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
1182 if( ( ES->i_cat == i_cat ) &&
1185 p_input->stream.p_selected_program ) )
1192 o_title = [NSApp localizedString: ES->psz_desc];
1196 char psz_title[ 256 ];
1198 snprintf( psz_title, sizeof(psz_title), _("Language 0x%x"),
1200 psz_title[sizeof(psz_title) - 1] = '\0';
1202 o_title = [NSApp localizedString: psz_title];
1205 o_lmi = [o_menu addItemWithTitle: o_title
1206 action: pf_callback keyEquivalent: @""];
1207 [o_lmi setRepresentedObject:
1208 [NSValue valueWithPointer: ES]];
1209 [o_lmi setTarget: o_controls];
1210 [o_lmi setTag: i_cat];
1212 if( /*p_es == ES*/ ES->p_decoder_fifo != NULL )
1214 [o_lmi setState: NSOnState];
1221 - (void)setupVarMenu:(NSMenuItem *)o_mi
1222 target:(vlc_object_t *)p_object
1223 var:(const char *)psz_variable
1224 selector:(SEL)pf_callback
1227 NSMenu * o_menu = [o_mi submenu];
1231 /* remove previous items */
1232 i_nb_items = [o_menu numberOfItems];
1233 for( i = 0; i < i_nb_items; i++ )
1235 [o_menu removeItemAtIndex: 0];
1238 if ( var_Get( p_object, psz_variable, &val ) < 0 )
1242 psz_value = val.psz_string;
1244 if ( var_Change( p_object, psz_variable,
1245 VLC_VAR_GETLIST, &val ) < 0 )
1251 /* make (un)sensitive */
1252 [o_mi setEnabled: ( val.p_list->i_count > 0 )];
1254 for ( i = 0; i < val.p_list->i_count; i++ )
1259 //o_title = [NSApp localizedString: val.p_list->p_values[i].psz_string];
1260 o_title = [NSString stringWithCString: val.p_list->p_values[i].psz_string];
1261 o_lmi = [o_menu addItemWithTitle: o_title
1262 action: pf_callback keyEquivalent: @""];
1263 /* FIXME: this isn't 64-bit clean ! */
1264 [o_lmi setTag: (int)psz_variable];
1265 [o_lmi setRepresentedObject:
1266 [NSValue valueWithPointer: p_object]];
1267 [o_lmi setTarget: o_controls];
1269 if ( !strcmp( psz_value, val.p_list->p_values[i].psz_string ) )
1270 [o_lmi setState: NSOnState];
1273 var_Change( p_object, psz_variable, VLC_VAR_FREELIST,
1279 - (IBAction)clearRecentItems:(id)sender
1281 [[NSDocumentController sharedDocumentController]
1282 clearRecentDocuments: nil];
1285 - (void)openRecentItem:(id)sender
1287 [self application: nil openFile: [sender title]];
1290 - (IBAction)viewPreferences:(id)sender
1292 if( o_prefs == nil )
1294 o_prefs = [[VLCPrefs alloc] init];
1297 [o_prefs createPrefPanel: @"main"];
1300 - (IBAction)timesliderUpdate:(id)sender
1304 switch( [[NSApp currentEvent] type] )
1307 case NSLeftMouseDown:
1308 f_slider = [sender floatValue];
1311 case NSLeftMouseDragged:
1312 f_updated = [sender floatValue];
1319 intf_thread_t * p_intf = [NSApp getIntf];
1321 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1324 if( p_playlist == NULL )
1329 vlc_mutex_lock( &p_playlist->object_lock );
1331 if( p_playlist->p_input != NULL )
1335 char psz_time[ OFFSETTOTIME_MAX_SIZE ];
1337 #define p_area p_playlist->p_input->stream.p_selected_area
1338 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
1339 i_tell = f_updated / 100. * p_area->i_size;
1340 input_OffsetToTime( p_playlist->p_input, psz_time, i_tell );
1341 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
1344 o_time = [NSString stringWithCString: psz_time];
1345 [o_timefield setStringValue: o_time];
1348 vlc_mutex_unlock( &p_playlist->object_lock );
1349 vlc_object_release( p_playlist );
1352 - (IBAction)closeError:(id)sender
1354 [o_err_msg setString: @""];
1355 [o_error performClose: self];
1358 - (IBAction)openReadMe:(id)sender
1360 NSString * o_path = [[NSBundle mainBundle]
1361 pathForResource: @"README.MacOSX" ofType: @"rtf"];
1363 [[NSWorkspace sharedWorkspace] openFile: o_path
1364 withApplication: @"TextEdit"];
1367 - (IBAction)reportABug:(id)sender
1369 NSURL * o_url = [NSURL URLWithString:
1370 @"http://www.videolan.org/support/bug-reporting.html"];
1372 [[NSWorkspace sharedWorkspace] openURL: o_url];
1375 - (IBAction)openWebsite:(id)sender
1377 NSURL * o_url = [NSURL URLWithString: @"http://www.videolan.org"];
1379 [[NSWorkspace sharedWorkspace] openURL: o_url];
1382 - (IBAction)openLicense:(id)sender
1384 NSString * o_path = [[NSBundle mainBundle]
1385 pathForResource: @"COPYING" ofType: nil];
1387 [[NSWorkspace sharedWorkspace] openFile: o_path
1388 withApplication: @"TextEdit"];
1391 - (IBAction)openCrashLog:(id)sender
1393 NSString * o_path = [@"~/Library/Logs/CrashReporter/vlc.crash.log"
1394 stringByExpandingTildeInPath];
1397 if ( [[NSFileManager defaultManager] fileExistsAtPath: o_path ] )
1399 [[NSWorkspace sharedWorkspace] openFile: o_path
1400 withApplication: @"Console"];
1404 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.") );
1409 - (void)windowDidBecomeKey:(NSNotification *)o_notification
1411 if( [o_notification object] == o_msgs_panel )
1414 NSEnumerator * o_enum;
1416 [o_messages setString: @""];
1420 o_enum = [o_msg_arr objectEnumerator];
1422 while( ( o_msg = [o_enum nextObject] ) != nil )
1424 [o_messages insertText: o_msg];
1427 [o_msg_lock unlock];
1433 @implementation VLCMain (NSMenuValidation)
1435 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
1437 BOOL bEnabled = TRUE;
1439 /* Recent Items Menu */
1441 if( [[o_mi title] isEqualToString: _NS("Clear Menu")] )
1443 NSMenu * o_menu = [o_mi_open_recent submenu];
1444 int i_nb_items = [o_menu numberOfItems];
1445 NSArray * o_docs = [[NSDocumentController sharedDocumentController]
1446 recentDocumentURLs];
1447 UInt32 i_nb_docs = [o_docs count];
1449 if( i_nb_items > 1 )
1451 while( --i_nb_items )
1453 [o_menu removeItemAtIndex: 0];
1462 [o_menu insertItem: [NSMenuItem separatorItem] atIndex: 0];
1468 o_url = [o_docs objectAtIndex: i_nb_docs];
1470 if( [o_url isFileURL] )
1472 o_doc = [o_url path];
1476 o_doc = [o_url absoluteString];
1479 [o_menu insertItemWithTitle: o_doc
1480 action: @selector(openRecentItem:)
1481 keyEquivalent: @"" atIndex: 0];
1483 if( i_nb_docs == 0 )
1500 @implementation VLCMain (Internal)
1502 - (void)handlePortMessage:(NSPortMessage *)o_msg
1507 NSInvocation * o_inv;
1508 NSConditionLock * o_lock;
1510 o_data = [[o_msg components] lastObject];
1511 o_inv = *((NSInvocation **)[o_data bytes]);
1512 [o_inv getArgument: &o_value atIndex: 2];
1513 val = (id **)[o_value pointerValue];
1514 [o_inv setArgument: val[1] atIndex: 2];
1519 [o_lock unlockWithCondition: 1];