1 /*****************************************************************************
2 * open.m: Open dialogues for VLC's MacOS X port
3 *****************************************************************************
4 * Copyright (C) 2002-2009 the VideoLAN team
7 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8 * Christophe Massiot <massiot@via.ecp.fr>
9 * Derk-Jan Hartman <thedj@users.sourceforge.net>
10 * Benjamin Pracht <bigben at videolan dot org>
11 * Felix Paul Kühne <fkuehne at videolan dot org>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #include <stdlib.h> /* malloc(), free() */
32 #include <sys/param.h> /* for MAXPATHLEN */
36 #include <IOKit/IOKitLib.h>
37 #include <IOKit/IOBSD.h>
38 #include <IOKit/storage/IOMedia.h>
39 #include <IOKit/storage/IOCDMedia.h>
40 #include <IOKit/storage/IODVDMedia.h>
50 #define setEyeTVUnconnected \
51 [o_capture_lbl setStringValue: _NS("No device connected")]; \
52 [o_capture_long_lbl setStringValue: _NS("VLC could not detect any EyeTV compatible device.\n\nCheck the device's connection, make sure that the latest EyeTV software is installed and try again.")]; \
53 [o_capture_lbl displayIfNeeded]; \
54 [o_capture_long_lbl displayIfNeeded]; \
55 [self showCaptureView: o_capture_label_view]
58 /*****************************************************************************
59 * GetEjectableMediaOfClass
60 *****************************************************************************/
61 NSArray *GetEjectableMediaOfClass( const char *psz_class )
63 io_object_t next_media;
64 mach_port_t master_port;
65 kern_return_t kern_result;
66 NSArray *o_devices = nil;
67 NSMutableArray *p_list = nil;
68 io_iterator_t media_iterator;
69 CFMutableDictionaryRef classes_to_match;
71 kern_result = IOMasterPort( MACH_PORT_NULL, &master_port );
72 if( kern_result != KERN_SUCCESS )
77 classes_to_match = IOServiceMatching( psz_class );
78 if( classes_to_match == NULL )
83 CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectableKey ),
86 kern_result = IOServiceGetMatchingServices( master_port, classes_to_match,
88 if( kern_result != KERN_SUCCESS )
93 p_list = [NSMutableArray arrayWithCapacity: 1];
95 next_media = IOIteratorNext( media_iterator );
99 size_t dev_path_length;
100 CFTypeRef str_bsd_path;
104 str_bsd_path = IORegistryEntryCreateCFProperty( next_media,
105 CFSTR( kIOBSDNameKey ),
108 if( str_bsd_path == NULL )
110 IOObjectRelease( next_media );
114 snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' );
115 dev_path_length = strlen( psz_buf );
117 if( CFStringGetCString( str_bsd_path,
118 (char*)&psz_buf + dev_path_length,
119 sizeof(psz_buf) - dev_path_length,
120 kCFStringEncodingASCII ) )
122 [p_list addObject: [NSString stringWithUTF8String: psz_buf]];
125 CFRelease( str_bsd_path );
127 IOObjectRelease( next_media );
129 } while( ( next_media = IOIteratorNext( media_iterator ) ) );
132 IOObjectRelease( media_iterator );
134 o_devices = [NSArray arrayWithArray: p_list];
139 /*****************************************************************************
140 * VLCOpen implementation
141 *****************************************************************************/
142 @implementation VLCOpen
144 static VLCOpen *_o_sharedMainInstance = nil;
146 + (VLCOpen *)sharedInstance
148 return _o_sharedMainInstance ? _o_sharedMainInstance : [[self alloc] init];
153 if( _o_sharedMainInstance) {
156 _o_sharedMainInstance = [super init];
160 return _o_sharedMainInstance;
165 [o_panel setTitle: _NS("Open Source")];
166 [o_mrl_lbl setStringValue: _NS("Media Resource Locator (MRL)")];
168 [o_btn_ok setTitle: _NS("Open")];
169 [o_btn_cancel setTitle: _NS("Cancel")];
171 [[o_tabview tabViewItemAtIndex: 0] setLabel: _NS("File")];
172 [[o_tabview tabViewItemAtIndex: 1] setLabel: _NS("Disc")];
173 [[o_tabview tabViewItemAtIndex: 2] setLabel: _NS("Network")];
174 [[o_tabview tabViewItemAtIndex: 3] setLabel: _NS("Capture")];
176 [o_file_btn_browse setTitle: _NS("Browse...")];
177 [o_file_stream setTitle: _NS("Treat as a pipe rather than as a file")];
179 [o_disc_device_lbl setStringValue: _NS("Device name")];
180 [o_disc_title_lbl setStringValue: _NS("Title")];
181 [o_disc_chapter_lbl setStringValue: _NS("Chapter")];
182 [o_disc_videots_btn_browse setTitle: _NS("Browse...")];
183 [o_disc_dvd_menus setTitle: _NS("No DVD menus")];
185 [[o_disc_type cellAtRow:0 column:0] setTitle: _NS("VIDEO_TS folder")];
186 [[o_disc_type cellAtRow:1 column:0] setTitle: _NS("DVD")];
187 [[o_disc_type cellAtRow:2 column:0] setTitle: _NS("VCD")];
188 [[o_disc_type cellAtRow:3 column:0] setTitle: _NS("Audio CD")];
190 [o_net_udp_port_lbl setStringValue: _NS("Port")];
191 [o_net_udpm_addr_lbl setStringValue: _NS("IP Address")];
192 [o_net_udpm_port_lbl setStringValue: _NS("Port")];
193 [o_net_http_url_lbl setStringValue: _NS("URL")];
194 [o_net_help_lbl setStringValue: _NS("To Open a usual network stream (HTTP, RTSP, MMS, FTP, etc.), just enter the URL in the field above. If you want to open a RTP or UDP stream, press the button below.")];
195 [o_net_help_udp_lbl setStringValue: _NS("If you want to open a multicast stream, enter the respective IP address given by the stream provider. In unicast mode, VLC will use your machine's IP automatically.\n\nTo open a stream using a different protocol, just press Cancel to close this sheet.")];
196 [o_net_udp_cancel_btn setTitle: _NS("Cancel")];
197 [o_net_udp_ok_btn setTitle: _NS("Open")];
198 [o_net_openUDP_btn setTitle: _NS("Open RTP/UDP Stream")];
199 [o_net_udp_mode_lbl setStringValue: _NS("Mode")];
200 [o_net_udp_protocol_lbl setStringValue: _NS("Protocol")];
201 [o_net_udp_address_lbl setStringValue: _NS("Address")];
203 [[o_net_mode cellAtRow:0 column:0] setTitle: _NS("Unicast")];
204 [[o_net_mode cellAtRow:1 column:0] setTitle: _NS("Multicast")];
206 [o_net_udp_port setIntValue: config_GetInt( p_intf, "server-port" )];
207 [o_net_udp_port_stp setIntValue: config_GetInt( p_intf, "server-port" )];
209 [o_eyetv_chn_bgbar setUsesThreadedAnimation: YES];
211 [o_capture_mode_pop removeAllItems];
212 [o_capture_mode_pop addItemWithTitle: @"iSight"];
213 [o_capture_mode_pop addItemWithTitle: _NS("Screen")];
214 [o_capture_mode_pop addItemWithTitle: @"EyeTV"];
215 [o_screen_lbl setStringValue: _NS("Screen Capture Input")];
216 [o_screen_long_lbl setStringValue: _NS("This facility allows you to process your screen's output.")];
217 [o_screen_fps_lbl setStringValue: _NS("Frames per Second:")];
218 [o_screen_left_lbl setStringValue: _NS("Subscreen left:")];
219 [o_screen_top_lbl setStringValue: _NS("Subscreen top:")];
220 [o_screen_width_lbl setStringValue: _NS("Subscreen width:")];
221 [o_screen_height_lbl setStringValue: _NS("Subscreen height:")];
222 [o_screen_follow_mouse_ckb setTitle: _NS("Follow the mouse")];
223 [o_eyetv_currentChannel_lbl setStringValue: _NS("Current channel:")];
224 [o_eyetv_previousProgram_btn setTitle: _NS("Previous Channel")];
225 [o_eyetv_nextProgram_btn setTitle: _NS("Next Channel")];
226 [o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
227 [o_eyetv_noInstance_lbl setStringValue: _NS("EyeTV is not launched")];
228 [o_eyetv_noInstanceLong_lbl setStringValue: _NS("VLC could not connect to EyeTV.\nMake sure that you installed VLC's EyeTV plugin.")];
229 [o_eyetv_launchEyeTV_btn setTitle: _NS("Launch EyeTV now")];
230 [o_eyetv_getPlugin_btn setTitle: _NS("Download Plugin")];
234 [[NSNotificationCenter defaultCenter] addObserver: self
235 selector: @selector(openFilePathChanged:)
236 name: NSControlTextDidChangeNotification
237 object: o_file_path];
239 [[NSNotificationCenter defaultCenter] addObserver: self
240 selector: @selector(openDiscInfoChanged:)
241 name: NSControlTextDidChangeNotification
242 object: o_disc_device];
243 [[NSNotificationCenter defaultCenter] addObserver: self
244 selector: @selector(openDiscInfoChanged:)
245 name: NSControlTextDidChangeNotification
246 object: o_disc_title];
247 [[NSNotificationCenter defaultCenter] addObserver: self
248 selector: @selector(openDiscInfoChanged:)
249 name: NSControlTextDidChangeNotification
250 object: o_disc_chapter];
251 [[NSNotificationCenter defaultCenter] addObserver: self
252 selector: @selector(openDiscInfoChanged:)
253 name: NSControlTextDidChangeNotification
254 object: o_disc_videots_folder];
256 [[NSNotificationCenter defaultCenter] addObserver: self
257 selector: @selector(openNetInfoChanged:)
258 name: NSControlTextDidChangeNotification
259 object: o_net_udp_port];
260 [[NSNotificationCenter defaultCenter] addObserver: self
261 selector: @selector(openNetInfoChanged:)
262 name: NSControlTextDidChangeNotification
263 object: o_net_udpm_addr];
264 [[NSNotificationCenter defaultCenter] addObserver: self
265 selector: @selector(openNetInfoChanged:)
266 name: NSControlTextDidChangeNotification
267 object: o_net_udpm_port];
268 [[NSNotificationCenter defaultCenter] addObserver: self
269 selector: @selector(openNetInfoChanged:)
270 name: NSControlTextDidChangeNotification
271 object: o_net_http_url];
273 [[NSDistributedNotificationCenter defaultCenter] addObserver: self
274 selector: @selector(eyetvChanged:)
276 object: @"VLCEyeTVSupport"
277 suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];
279 [[NSNotificationCenter defaultCenter] addObserver: self
280 selector: @selector(screenFPSfieldChanged:)
281 name: NSControlTextDidChangeNotification
282 object: o_screen_fps_fld];
284 /* register clicks on text fields */
285 [[NSNotificationCenter defaultCenter] addObserver: self
286 selector: @selector(textFieldWasClicked:)
287 name: @"VLCOpenTextFieldWasClicked"
294 module_config_t * p_item;
296 [o_file_sub_ckbox setTitle: _NS("Load subtitles file:")];
297 [o_file_sub_btn_settings setTitle: _NS("Settings...")];
298 [o_file_sub_btn_browse setTitle: _NS("Browse...")];
299 [o_file_sub_override setTitle: _NS("Override parametters")];
300 [o_file_sub_delay_lbl setStringValue: _NS("Delay")];
301 [o_file_sub_delay_stp setEnabled: NO];
302 [o_file_sub_fps_lbl setStringValue: _NS("FPS")];
303 [o_file_sub_fps_stp setEnabled: NO];
304 [o_file_sub_encoding_lbl setStringValue: _NS("Subtitles encoding")];
305 [o_file_sub_encoding_pop removeAllItems];
306 [o_file_sub_size_lbl setStringValue: _NS("Font size")];
307 [o_file_sub_size_pop removeAllItems];
308 [o_file_sub_align_lbl setStringValue: _NS("Subtitles alignment")];
309 [o_file_sub_align_pop removeAllItems];
310 [o_file_sub_ok_btn setStringValue: _NS("OK")];
311 [o_file_sub_font_box setTitle: _NS("Font Properties")];
312 [o_file_sub_file_box setTitle: _NS("Subtitle File")];
314 p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-encoding" );
318 for( i_index = 0; p_item->ppsz_list && p_item->ppsz_list[i_index];
321 [o_file_sub_encoding_pop addItemWithTitle:
322 [NSString stringWithUTF8String: p_item->ppsz_list[i_index]]];
324 [o_file_sub_encoding_pop selectItemWithTitle:
325 [NSString stringWithUTF8String: p_item->value.psz]];
328 p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-align" );
332 for ( i_index = 0; i_index < p_item->i_list; i_index++ )
334 [o_file_sub_align_pop addItemWithTitle:
335 [NSString stringWithUTF8String:
336 p_item->ppsz_list_text[i_index]]];
338 [o_file_sub_align_pop selectItemAtIndex: p_item->value.i];
341 p_item = config_FindConfig( VLC_OBJECT(p_intf), "freetype-rel-fontsize" );
345 for ( i_index = 0; i_index < p_item->i_list; i_index++ )
347 [o_file_sub_size_pop addItemWithTitle:
348 [NSString stringWithUTF8String:
349 p_item->ppsz_list_text[i_index]]];
350 if ( p_item->value.i == p_item->pi_list[i_index] )
352 [o_file_sub_size_pop selectItemAtIndex: i_index];
358 - (void)openTarget:(int)i_type
362 b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
364 [o_tabview selectTabViewItemAtIndex: i_type];
365 [o_file_sub_ckbox setState: NSOffState];
367 i_result = [NSApp runModalForWindow: o_panel];
372 NSMutableDictionary *o_dic;
373 NSMutableArray *o_options = [NSMutableArray array];
376 o_dic = [NSMutableDictionary dictionaryWithObject: [o_mrl stringValue] forKey: @"ITEM_URL"];
377 if( [o_file_sub_ckbox state] == NSOnState )
379 module_config_t * p_item;
381 [o_options addObject: [NSString stringWithFormat: @"sub-file=%@", [o_file_sub_path stringValue]]];
382 if( [o_file_sub_override state] == NSOnState )
384 [o_options addObject: [NSString stringWithFormat: @"sub-delay=%i", (int)( [o_file_sub_delay intValue] * 10 )]];
385 [o_options addObject: [NSString stringWithFormat: @"sub-fps=%f", [o_file_sub_fps floatValue]]];
387 [o_options addObject: [NSString stringWithFormat:
388 @"subsdec-encoding=%@",
389 [o_file_sub_encoding_pop titleOfSelectedItem]]];
390 [o_options addObject: [NSString stringWithFormat:
392 [o_file_sub_align_pop indexOfSelectedItem]]];
394 p_item = config_FindConfig( VLC_OBJECT(p_intf),
395 "freetype-rel-fontsize" );
399 [o_options addObject: [NSString stringWithFormat:
400 @"freetype-rel-fontsize=%i",
401 p_item->pi_list[[o_file_sub_size_pop indexOfSelectedItem]]]];
404 if( [o_output_ckbox state] == NSOnState )
406 for (i = 0 ; i < [[o_sout_options mrl] count] ; i++)
408 [o_options addObject: [NSString stringWithString:
409 [[(VLCOutput *)o_sout_options mrl] objectAtIndex: i]]];
412 if( [[[o_tabview selectedTabViewItem] label] isEqualToString: _NS("Capture")] )
414 if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Screen")] )
415 [o_options addObject: [NSString stringWithFormat: @"screen-fps=%f", [o_screen_fps_fld floatValue]]];
416 [o_options addObject: [NSString stringWithFormat: @"screen-left=%i", [o_screen_left_fld intValue]]];
417 [o_options addObject: [NSString stringWithFormat: @"screen-top=%i", [o_screen_top_fld intValue]]];
418 [o_options addObject: [NSString stringWithFormat: @"screen-width=%i", [o_screen_width_fld intValue]]];
419 [o_options addObject: [NSString stringWithFormat: @"screen-height=%i", [o_screen_height_fld intValue]]];
420 if( [o_screen_follow_mouse_ckb intValue] == YES )
421 [o_options addObject: @"screen-follow-mouse"];
423 [o_options addObject: @"no-screen-follow-mouse"];
426 /* apply the options to our item(s) */
427 [o_dic setObject: (NSArray *)[o_options copy] forKey: @"ITEM_OPTIONS"];
429 [o_playlist appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue:NO];
431 [o_playlist appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue:YES];
435 - (void)tabView:(NSTabView *)o_tv didSelectTabViewItem:(NSTabViewItem *)o_tvi
437 NSString *o_label = [o_tvi label];
439 if( [o_label isEqualToString: _NS("File")] )
441 [self openFilePathChanged: nil];
443 else if( [o_label isEqualToString: _NS("Disc")] )
445 [self openDiscTypeChanged: nil];
447 else if( [o_label isEqualToString: _NS("Network")] )
449 [self openNetInfoChanged: nil];
451 else if( [o_label isEqualToString: _NS("Capture")] )
453 [self openCaptureModeChanged: nil];
457 - (IBAction)expandMRLfieldAction:(id)sender
459 NSRect o_win_rect, o_view_rect;
460 o_win_rect = [o_panel frame];
461 o_view_rect = [o_mrl_view frame];
463 if( [o_mrl_btn state] == NSOffState )
465 /* we need to collaps, restore the panel size */
466 o_win_rect.size.height = o_win_rect.size.height - o_view_rect.size.height;
467 o_win_rect.origin.y = ( o_win_rect.origin.y + o_view_rect.size.height ) - o_view_rect.size.height;
469 /* remove the MRL view */
470 [o_mrl_view removeFromSuperviewWithoutNeedingDisplay];
472 /* we need to expand */
473 [o_mrl_view setFrame: NSMakeRect( 0,
474 [o_mrl_btn frame].origin.y,
475 o_view_rect.size.width,
476 o_view_rect.size.height )];
477 [o_mrl_view setNeedsDisplay: YES];
478 [o_mrl_view setAutoresizesSubviews: YES];
480 /* add the MRL view */
481 [[o_panel contentView] addSubview: o_mrl_view];
482 o_win_rect.size.height = o_win_rect.size.height + o_view_rect.size.height;
485 [o_panel setFrame: o_win_rect display:YES animate: YES];
486 [o_panel displayIfNeeded];
489 - (void)openFileGeneric
491 [self openFilePathChanged: nil];
492 [self openTarget: 0];
497 [self openDiscTypeChanged: nil];
498 [self openTarget: 1];
503 [self openNetInfoChanged: nil];
504 [self openTarget: 2];
509 [self openCaptureModeChanged: nil];
510 [self showCaptureView: o_capture_label_view];
511 [self openTarget: 3];
514 - (void)openFilePathChanged:(NSNotification *)o_notification
516 NSString *o_filename = [o_file_path stringValue];
517 bool b_stream = [o_file_stream state];
520 [[NSFileManager defaultManager] fileExistsAtPath:o_filename isDirectory:&b_dir];
522 char *psz_uri = make_URI([o_filename UTF8String]);
523 if( !psz_uri ) return;
525 NSMutableString *o_mrl_string = [NSMutableString stringWithUTF8String: psz_uri ];
526 NSRange offile = [o_mrl_string rangeOfString:@"file"];
531 [o_mrl_string replaceCharactersInRange:offile withString: @"directory"];
535 [o_mrl_string replaceCharactersInRange:offile withString: @"stream"];
537 [o_mrl setStringValue: o_mrl_string];
540 - (IBAction)openFileBrowse:(id)sender
542 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
544 [o_open_panel setAllowsMultipleSelection: NO];
545 [o_open_panel setCanChooseDirectories: YES];
546 [o_open_panel setTitle: _NS("Open File")];
547 [o_open_panel setPrompt: _NS("Open")];
549 [o_open_panel beginSheetForDirectory:nil
552 modalForWindow:[sender window]
554 didEndSelector: @selector(pathChosenInPanel:
560 - (void)pathChosenInPanel: (NSOpenPanel *) sheet withReturn:(int)returnCode contextInfo:(void *)contextInfo
562 if (returnCode == NSFileHandlingPanelOKButton)
564 NSString *o_filename = [[sheet filenames] objectAtIndex: 0];
565 [o_file_path setStringValue: o_filename];
566 [self openFilePathChanged: nil];
570 - (IBAction)openFileStreamChanged:(id)sender
572 [self openFilePathChanged: nil];
575 - (IBAction)openDiscTypeChanged:(id)sender
578 BOOL b_device, b_no_menus, b_title_chapter;
580 [o_disc_device removeAllItems];
581 b_title_chapter = ![o_disc_dvd_menus state];
583 o_type = [[o_disc_type selectedCell] title];
585 if ( [o_type isEqualToString: _NS("VIDEO_TS folder")] )
587 b_device = NO; b_no_menus = YES;
593 const char *psz_class = NULL;
596 if ( [o_type isEqualToString: _NS("VCD")] )
598 psz_class = kIOCDMediaClass;
600 b_no_menus = NO; b_title_chapter = YES;
602 else if ( [o_type isEqualToString: _NS("Audio CD")])
604 psz_class = kIOCDMediaClass;
606 b_no_menus = NO; b_title_chapter = NO;
610 psz_class = kIODVDMediaClass;
615 o_devices = GetEjectableMediaOfClass( psz_class );
616 if ( o_devices != nil )
618 int i_devices = [o_devices count];
622 for( int i = 0; i < i_devices; i++ )
625 addItemWithObjectValue: [o_devices objectAtIndex: i]];
628 [o_disc_device selectItemAtIndex: 0];
632 [o_disc_device setStringValue:
633 [NSString stringWithFormat: _NS("No %@s found"), o_disc]];
638 [o_disc_device setEnabled: b_device];
639 [o_disc_title setEnabled: b_title_chapter];
640 [o_disc_title_stp setEnabled: b_title_chapter];
641 [o_disc_chapter setEnabled: b_title_chapter];
642 [o_disc_chapter_stp setEnabled: b_title_chapter];
643 [o_disc_videots_folder setEnabled: !b_device];
644 [o_disc_videots_btn_browse setEnabled: !b_device];
645 [o_disc_dvd_menus setEnabled: b_no_menus];
647 [self openDiscInfoChanged: nil];
650 - (IBAction)openDiscStepperChanged:(id)sender
652 int i_tag = [sender tag];
656 [o_disc_title setIntValue: [o_disc_title_stp intValue]];
658 else if( i_tag == 1 )
660 [o_disc_chapter setIntValue: [o_disc_chapter_stp intValue]];
663 [self openDiscInfoChanged: nil];
666 - (void)openDiscInfoChanged:(NSNotification *)o_notification
671 NSString *o_mrl_string;
672 int i_title, i_chapter;
675 o_type = [[o_disc_type selectedCell] title];
676 o_device = [o_disc_device stringValue];
677 i_title = [o_disc_title intValue];
678 i_chapter = [o_disc_chapter intValue];
679 o_videots = [o_disc_videots_folder stringValue];
680 b_no_menus = [o_disc_dvd_menus state];
682 if ( [o_type isEqualToString: _NS("VCD")] )
684 if ( [o_device isEqualToString:
685 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
687 o_mrl_string = [NSString stringWithFormat: @"vcd://%@@%i:%i",
688 o_device, i_title, i_chapter];
690 else if ( [o_type isEqualToString: _NS("Audio CD")] )
692 if ( [o_device isEqualToString:
693 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
695 o_mrl_string = [NSString stringWithFormat: @"cdda://%@",
698 else if ( [o_type isEqualToString: _NS("DVD")] )
700 if ( [o_device isEqualToString:
701 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
704 o_mrl_string = [NSString stringWithFormat: @"dvdread://%@@%i:%i-",
705 o_device, i_title, i_chapter];
707 o_mrl_string = [NSString stringWithFormat: @"dvdnav://%@",
711 else /* VIDEO_TS folder */
714 o_mrl_string = [NSString stringWithFormat: @"dvdread://%@@%i:%i",
715 o_videots, i_title, i_chapter];
717 o_mrl_string = [NSString stringWithFormat: @"dvdnav://%@",
721 [o_mrl setStringValue: o_mrl_string];
724 - (IBAction)openDiscMenusChanged:(id)sender
726 [self openDiscInfoChanged: nil];
727 [self openDiscTypeChanged: nil];
730 - (IBAction)openVTSBrowse:(id)sender
732 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
734 [o_open_panel setAllowsMultipleSelection: NO];
735 [o_open_panel setCanChooseFiles: NO];
736 [o_open_panel setCanChooseDirectories: YES];
737 [o_open_panel setTitle: _NS("Open VIDEO_TS Directory")];
738 [o_open_panel setPrompt: _NS("Open")];
740 if( [o_open_panel runModalForDirectory: nil
741 file: nil types: nil] == NSOKButton )
743 NSString *o_dirname = [[o_open_panel filenames] objectAtIndex: 0];
744 [o_disc_videots_folder setStringValue: o_dirname];
745 [self openDiscInfoChanged: nil];
749 - (void)textFieldWasClicked:(NSNotification *)o_notification
751 if( [o_notification object] == o_net_udp_port )
752 [o_net_mode selectCellAtRow: 0 column: 0];
753 else if( [o_notification object] == o_net_udpm_addr ||
754 [o_notification object] == o_net_udpm_port )
755 [o_net_mode selectCellAtRow: 1 column: 0];
757 [o_net_mode selectCellAtRow: 2 column: 0];
759 [self openNetInfoChanged: nil];
762 - (IBAction)openNetModeChanged:(id)sender
764 if( sender == o_net_mode )
766 if( [[sender selectedCell] tag] == 0 )
767 [o_panel makeFirstResponder: o_net_udp_port];
768 else if ( [[sender selectedCell] tag] == 1 )
769 [o_panel makeFirstResponder: o_net_udpm_addr];
771 msg_Warn( p_intf, "Unknown sender tried to change UDP/RTP mode" );
774 [self openNetInfoChanged: nil];
777 - (IBAction)openNetStepperChanged:(id)sender
779 int i_tag = [sender tag];
783 [o_net_udp_port setIntValue: [o_net_udp_port_stp intValue]];
784 [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
785 object: o_net_udp_port];
786 [o_panel makeFirstResponder: o_net_udp_port];
788 else if( i_tag == 1 )
790 [o_net_udpm_port setIntValue: [o_net_udpm_port_stp intValue]];
791 [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
792 object: o_net_udpm_port];
793 [o_panel makeFirstResponder: o_net_udpm_port];
796 [self openNetInfoChanged: nil];
799 - (void)openNetInfoChanged:(NSNotification *)o_notification
801 NSString *o_mrl_string = [NSString string];
803 if( [o_net_udp_panel isVisible] )
806 o_mode = [[o_net_mode selectedCell] title];
808 if( [o_mode isEqualToString: _NS("Unicast")] )
810 int i_port = [o_net_udp_port intValue];
812 if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
813 o_mrl_string = [NSString stringWithString: @"udp://"];
815 o_mrl_string = [NSString stringWithString: @"rtp://"];
817 if( i_port != config_GetInt( p_intf, "server-port" ) )
820 [o_mrl_string stringByAppendingFormat: @"@:%i", i_port];
823 else if( [o_mode isEqualToString: _NS("Multicast")] )
825 NSString *o_addr = [o_net_udpm_addr stringValue];
826 int i_port = [o_net_udpm_port intValue];
828 if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
829 o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr];
831 o_mrl_string = [NSString stringWithFormat: @"rtp://@%@", o_addr];
833 if( i_port != config_GetInt( p_intf, "server-port" ) )
836 [o_mrl_string stringByAppendingFormat: @":%i", i_port];
842 NSString *o_url = [o_net_http_url stringValue];
844 if ( ![o_url hasPrefix:@"http:"] && ![o_url hasPrefix:@"ftp:"]
845 && ![o_url hasPrefix:@"mms"] && ![o_url hasPrefix:@"rtsp"] )
846 o_mrl_string = [NSString stringWithFormat: @"http://%@", o_url];
848 o_mrl_string = o_url;
850 [o_mrl setStringValue: o_mrl_string];
853 - (IBAction)openNetUDPButtonAction:(id)sender
855 if( sender == o_net_openUDP_btn )
857 [NSApp beginSheet: o_net_udp_panel
858 modalForWindow: o_panel
862 [self openNetInfoChanged: nil];
864 else if( sender == o_net_udp_cancel_btn )
866 [o_net_udp_panel orderOut: sender];
867 [NSApp endSheet: o_net_udp_panel];
869 else if( sender == o_net_udp_ok_btn )
871 NSString *o_mrl_string = [NSString string];
872 if( [[[o_net_mode selectedCell] title] isEqualToString: _NS("Unicast")] )
874 int i_port = [o_net_udp_port intValue];
876 if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
877 o_mrl_string = [NSString stringWithString: @"udp://"];
879 o_mrl_string = [NSString stringWithString: @"rtp://"];
881 if( i_port != config_GetInt( p_intf, "server-port" ) )
884 [o_mrl_string stringByAppendingFormat: @"@:%i", i_port];
887 else if( [[[o_net_mode selectedCell] title] isEqualToString: _NS("Multicast")] )
889 NSString *o_addr = [o_net_udpm_addr stringValue];
890 int i_port = [o_net_udpm_port intValue];
892 if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
893 o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr];
895 o_mrl_string = [NSString stringWithFormat: @"rtp://@%@", o_addr];
897 if( i_port != config_GetInt( p_intf, "server-port" ) )
900 [o_mrl_string stringByAppendingFormat: @":%i", i_port];
903 [o_mrl setStringValue: o_mrl_string];
904 [o_net_http_url setStringValue: o_mrl_string];
905 [o_net_udp_panel orderOut: sender];
906 [NSApp endSheet: o_net_udp_panel];
912 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
914 b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
916 [o_open_panel setAllowsMultipleSelection: YES];
917 [o_open_panel setCanChooseDirectories: YES];
918 [o_open_panel setTitle: _NS("Open File")];
919 [o_open_panel setPrompt: _NS("Open")];
921 if( [o_open_panel runModalForDirectory: nil
922 file: nil types: nil] == NSOKButton )
924 NSArray *o_array = [NSArray array];
925 NSArray *o_values = [[o_open_panel filenames]
926 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
928 for( i = 0; i < (int)[o_values count]; i++)
931 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
932 o_array = [o_array arrayByAddingObject: o_dic];
935 [o_playlist appendArray: o_array atPos: -1 enqueue:NO];
937 [o_playlist appendArray: o_array atPos: -1 enqueue:YES];
941 - (void)showCaptureView: theView
944 o_view_rect = [theView frame];
945 if( o_currentCaptureView )
947 [o_currentCaptureView removeFromSuperviewWithoutNeedingDisplay];
948 [o_currentCaptureView release];
950 [theView setFrame: NSMakeRect( 0, -10, o_view_rect.size.width, o_view_rect.size.height)];
951 [theView setNeedsDisplay: YES];
952 [theView setAutoresizesSubviews: YES];
953 [[[o_tabview tabViewItemAtIndex: 3] view] addSubview: theView];
954 [theView displayIfNeeded];
955 o_currentCaptureView = theView;
956 [o_currentCaptureView retain];
959 - (IBAction)openCaptureModeChanged:(id)sender
961 if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: @"EyeTV"] )
963 if( [[[VLCMain sharedInstance] eyeTVController] isEyeTVrunning] == YES )
965 if( [[[VLCMain sharedInstance] eyeTVController] isDeviceConnected] == YES )
967 [self showCaptureView: o_eyetv_running_view];
968 [self setupChannelInfo];
976 [self showCaptureView: o_eyetv_notLaunched_view];
977 [o_mrl setStringValue: @""];
979 else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Screen")] )
981 [self showCaptureView: o_screen_view];
982 [o_mrl setStringValue: @"screen://"];
983 [o_screen_height_fld setIntValue: config_GetInt( p_intf, "screen-height" )];
984 [o_screen_width_fld setIntValue: config_GetInt( p_intf, "screen-width" )];
985 [o_screen_fps_fld setFloatValue: config_GetFloat( p_intf, "screen-fps" )];
986 [o_screen_left_fld setIntValue: config_GetInt( p_intf, "screen-left" )];
987 [o_screen_top_fld setIntValue: config_GetInt( p_intf, "screen-top" )];
988 [o_screen_follow_mouse_ckb setIntValue: config_GetInt( p_intf, "screen-follow-mouse" )];
990 else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: @"iSight"] )
992 [o_capture_lbl setStringValue: _NS("iSight Capture Input")];
993 [o_capture_long_lbl setStringValue: _NS("This facility allows you to process your iSight's input signal.\n\nNo settings are available in this version, so you will be provided a 640px*480px raw video stream.\n\nLive Audio input is not supported.")];
994 [o_capture_lbl displayIfNeeded];
995 [o_capture_long_lbl displayIfNeeded];
997 [self showCaptureView: o_capture_label_view];
998 [o_mrl setStringValue: @"qtcapture://"];
1002 - (IBAction)screenStepperChanged:(id)sender
1004 [o_screen_fps_fld setFloatValue: [o_screen_fps_stp floatValue]];
1005 [o_panel makeFirstResponder: o_screen_fps_fld];
1006 [o_mrl setStringValue: @"screen://"];
1009 - (void)screenFPSfieldChanged:(NSNotification *)o_notification
1011 [o_screen_fps_stp setFloatValue: [o_screen_fps_fld floatValue]];
1012 if( [[o_screen_fps_fld stringValue] isEqualToString: @""] )
1013 [o_screen_fps_fld setFloatValue: 1.0];
1014 [o_mrl setStringValue: @"screen://"];
1017 - (IBAction)eyetvSwitchChannel:(id)sender
1019 if( sender == o_eyetv_nextProgram_btn )
1021 int chanNum = [[[VLCMain sharedInstance] eyeTVController] switchChannelUp: YES];
1022 [o_eyetv_channels_pop selectItemWithTag:chanNum];
1023 [o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1025 else if( sender == o_eyetv_previousProgram_btn )
1027 int chanNum = [[[VLCMain sharedInstance] eyeTVController] switchChannelUp: NO];
1028 [o_eyetv_channels_pop selectItemWithTag:chanNum];
1029 [o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1031 else if( sender == o_eyetv_channels_pop )
1033 int chanNum = [[sender selectedItem] tag];
1034 [[[VLCMain sharedInstance] eyeTVController] selectChannel:chanNum];
1035 [o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1038 msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" );
1041 - (IBAction)eyetvLaunch:(id)sender
1043 [[[VLCMain sharedInstance] eyeTVController] launchEyeTV];
1046 - (IBAction)eyetvGetPlugin:(id)sender
1048 [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: @"http://www.videolan.org/vlc/eyetv"]];
1051 - (void)eyetvChanged:(NSNotification *)o_notification
1053 if( [[o_notification name] isEqualToString: @"DeviceAdded"] )
1055 msg_Dbg( VLCIntf, "eyetv device was added" );
1056 [self showCaptureView: o_eyetv_running_view];
1057 [self setupChannelInfo];
1059 else if( [[o_notification name] isEqualToString: @"DeviceRemoved"] )
1061 /* leave the channel selection like that,
1062 * switch to our "no device" tab */
1063 msg_Dbg( VLCIntf, "eyetv device was removed" );
1064 setEyeTVUnconnected;
1066 else if( [[o_notification name] isEqualToString: @"PluginQuit"] )
1068 /* switch to the "launch eyetv" tab */
1069 msg_Dbg( VLCIntf, "eyetv was terminated" );
1070 [self showCaptureView: o_eyetv_notLaunched_view];
1072 else if( [[o_notification name] isEqualToString: @"PluginInit"] )
1074 /* we got no device yet */
1075 msg_Dbg( VLCIntf, "eyetv was launched, no device yet" );
1076 setEyeTVUnconnected;
1079 msg_Warn( VLCIntf, "unknown external notify '%s' received", [[o_notification name] UTF8String] );
1082 /* little helper method, since this code needs to be run by multiple objects */
1083 - (void)setupChannelInfo
1085 /* set up channel selection */
1086 [o_eyetv_channels_pop removeAllItems];
1087 [o_eyetv_chn_bgbar setHidden: NO];
1088 [o_eyetv_chn_bgbar animate: self];
1089 [o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
1090 [o_eyetv_chn_status_txt setHidden: NO];
1093 NSEnumerator *channels = [[[VLCMain sharedInstance] eyeTVController] allChannels];
1095 [[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("Composite input")
1097 keyEquivalent: @""] setTag:x++];
1098 [[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("S-Video input")
1100 keyEquivalent: @""] setTag:x++];
1104 [[o_eyetv_channels_pop menu] addItem: [NSMenuItem separatorItem]];
1105 while( channel = [channels nextObject] )
1107 /* we have to add items this way, because we accept duplicates
1108 * additionally, we save a bit of time */
1109 [[[o_eyetv_channels_pop menu] addItemWithTitle: channel
1111 keyEquivalent: @""] setTag:++x];
1113 /* make Tuner the default */
1114 [o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] eyeTVController] currentChannel]];
1118 [o_eyetv_chn_bgbar setHidden: YES];
1119 [o_eyetv_chn_status_txt setHidden: YES];
1122 - (IBAction)subsChanged:(id)sender
1124 if ([o_file_sub_ckbox state] == NSOnState)
1126 [o_file_sub_btn_settings setEnabled:YES];
1130 [o_file_sub_btn_settings setEnabled:NO];
1134 - (IBAction)subSettings:(id)sender
1136 [NSApp beginSheet: o_file_sub_sheet
1137 modalForWindow: [sender window]
1139 didEndSelector: NULL
1143 - (IBAction)subCloseSheet:(id)sender
1145 [o_file_sub_sheet orderOut:sender];
1146 [NSApp endSheet: o_file_sub_sheet];
1149 - (IBAction)subFileBrowse:(id)sender
1151 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
1153 [o_open_panel setAllowsMultipleSelection: NO];
1154 [o_open_panel setTitle: _NS("Open File")];
1155 [o_open_panel setPrompt: _NS("Open")];
1157 if( [o_open_panel runModalForDirectory: nil
1158 file: nil types: nil] == NSOKButton )
1160 NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
1161 [o_file_sub_path setStringValue: o_filename];
1165 - (IBAction)subOverride:(id)sender
1167 BOOL b_state = [o_file_sub_override state];
1168 [o_file_sub_delay setEnabled: b_state];
1169 [o_file_sub_delay_stp setEnabled: b_state];
1170 [o_file_sub_fps setEnabled: b_state];
1171 [o_file_sub_fps_stp setEnabled: b_state];
1174 - (IBAction)subDelayStepperChanged:(id)sender
1176 [o_file_sub_delay setIntValue: [o_file_sub_delay_stp intValue]];
1179 - (IBAction)subFpsStepperChanged:(id)sender;
1181 [o_file_sub_fps setFloatValue: [o_file_sub_fps_stp floatValue]];
1184 - (IBAction)panelCancel:(id)sender
1186 [NSApp stopModalWithCode: 0];
1189 - (IBAction)panelOk:(id)sender
1191 if( [[o_mrl stringValue] length] )
1193 [NSApp stopModalWithCode: 1];
1203 @implementation VLCOpenTextField
1205 - (void)mouseDown:(NSEvent *)theEvent
1207 [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
1209 [super mouseDown: theEvent];