1 /*****************************************************************************
2 * open.m: MacOS X plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: open.m,v 1.5 2002/12/30 23:45:21 massiot Exp $
7 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8 * Christophe Massiot <massiot@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
29 #include <sys/param.h> /* for MAXPATHLEN */
33 #include <IOKit/IOKitLib.h>
34 #include <IOKit/IOBSD.h>
35 #include <IOKit/storage/IOMedia.h>
36 #include <IOKit/storage/IOCDMedia.h>
37 #include <IOKit/storage/IODVDMedia.h>
39 #import <Cocoa/Cocoa.h>
50 /*****************************************************************************
51 * GetEjectableMediaOfClass
52 *****************************************************************************/
53 NSArray *GetEjectableMediaOfClass( const char *psz_class )
55 io_object_t next_media;
56 mach_port_t master_port;
57 kern_return_t kern_result;
58 NSArray *o_devices = nil;
59 NSMutableArray *p_list = nil;
60 io_iterator_t media_iterator;
61 CFMutableDictionaryRef classes_to_match;
63 kern_result = IOMasterPort( MACH_PORT_NULL, &master_port );
64 if( kern_result != KERN_SUCCESS )
69 classes_to_match = IOServiceMatching( psz_class );
70 if( classes_to_match == NULL )
75 CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectable ),
78 kern_result = IOServiceGetMatchingServices( master_port, classes_to_match,
80 if( kern_result != KERN_SUCCESS )
85 p_list = [NSMutableArray arrayWithCapacity: 1];
87 next_media = IOIteratorNext( media_iterator );
88 if( next_media != NULL )
91 size_t dev_path_length;
92 CFTypeRef str_bsd_path;
96 str_bsd_path = IORegistryEntryCreateCFProperty( next_media,
100 if( str_bsd_path == NULL )
102 IOObjectRelease( next_media );
106 snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' );
107 dev_path_length = strlen( psz_buf );
109 if( CFStringGetCString( str_bsd_path,
110 (char*)&psz_buf + dev_path_length,
111 sizeof(psz_buf) - dev_path_length,
112 kCFStringEncodingASCII ) )
114 [p_list addObject: [NSString stringWithCString: psz_buf]];
117 CFRelease( str_bsd_path );
119 IOObjectRelease( next_media );
121 } while( ( next_media = IOIteratorNext( media_iterator ) ) != NULL );
124 IOObjectRelease( media_iterator );
126 o_devices = [NSArray arrayWithArray: p_list];
131 /*****************************************************************************
132 * VLCOpen implementation
133 *****************************************************************************/
134 @implementation VLCOpen
138 intf_thread_t * p_intf = [NSApp getIntf];
140 [o_panel setTitle: _NS("Open Target")];
141 [o_mrl_lbl setTitle: _NS("Media Resource Locator (MRL)")];
143 [o_btn_ok setTitle: _NS("OK")];
144 [o_btn_cancel setTitle: _NS("Cancel")];
146 [[o_tabview tabViewItemAtIndex: 0] setLabel: _NS("File")];
147 [[o_tabview tabViewItemAtIndex: 1] setLabel: _NS("Disc")];
148 [[o_tabview tabViewItemAtIndex: 2] setLabel: _NS("Network")];
150 [o_file_btn_browse setTitle: _NS("Browse...")];
151 [o_file_stream setTitle: _NS("Treat as a pipe rather than as a file")];
153 [o_disc_device_lbl setStringValue: _NS("Device name")];
154 [o_disc_title_lbl setStringValue: _NS("Title")];
155 [o_disc_chapter_lbl setStringValue: _NS("Chapter")];
156 [o_disc_videots_btn_browse setStringValue: _NS("Browse...")];
158 [[o_disc_type cellAtRow:0 column:0] setTitle: _NS("DVD")];
159 [[o_disc_type cellAtRow:1 column:0] setTitle: _NS("DVD with menus")];
160 [[o_disc_type cellAtRow:2 column:0] setTitle: _NS("VCD")];
161 [[o_disc_type cellAtRow:3 column:0] setTitle: _NS("VIDEO_TS folder")];
163 [o_net_udp_port_lbl setStringValue: _NS("Port")];
164 [o_net_udpm_addr_lbl setStringValue: _NS("Address")];
165 [o_net_udpm_port_lbl setStringValue: _NS("Port")];
166 [o_net_cs_addr_lbl setStringValue: _NS("Address")];
167 [o_net_cs_port_lbl setStringValue: _NS("Port")];
168 [o_net_http_url_lbl setStringValue: _NS("URL")];
170 [[o_net_mode cellAtRow:0 column:0] setTitle: _NS("UDP/RTP")];
171 [[o_net_mode cellAtRow:1 column:0] setTitle: _NS("UDP/RTP Multicast")];
172 [[o_net_mode cellAtRow:2 column:0] setTitle: _NS("Channel server")];
173 [[o_net_mode cellAtRow:3 column:0] setTitle: _NS("HTTP/FTP/MMS")];
175 [o_net_udp_port setIntValue: config_GetInt( p_intf, "server-port" )];
176 [o_net_udp_port_stp setIntValue: config_GetInt( p_intf, "server-port" )];
177 [o_net_cs_port setIntValue: config_GetInt( p_intf, "channel-port" )];
178 [o_net_cs_port_stp setIntValue: config_GetInt( p_intf, "channel-port" )];
180 [[NSNotificationCenter defaultCenter] addObserver: self
181 selector: @selector(openFilePathChanged:)
182 name: NSControlTextDidChangeNotification
183 object: o_file_path];
185 [[NSNotificationCenter defaultCenter] addObserver: self
186 selector: @selector(openDiscInfoChanged:)
187 name: NSControlTextDidChangeNotification
188 object: o_disc_device];
189 [[NSNotificationCenter defaultCenter] addObserver: self
190 selector: @selector(openDiscInfoChanged:)
191 name: NSControlTextDidChangeNotification
192 object: o_disc_title];
193 [[NSNotificationCenter defaultCenter] addObserver: self
194 selector: @selector(openDiscInfoChanged:)
195 name: NSControlTextDidChangeNotification
196 object: o_disc_chapter];
197 [[NSNotificationCenter defaultCenter] addObserver: self
198 selector: @selector(openDiscInfoChanged:)
199 name: NSControlTextDidChangeNotification
200 object: o_disc_videots_folder];
202 [[NSNotificationCenter defaultCenter] addObserver: self
203 selector: @selector(openNetInfoChanged:)
204 name: NSControlTextDidChangeNotification
205 object: o_net_udp_port];
206 [[NSNotificationCenter defaultCenter] addObserver: self
207 selector: @selector(openNetInfoChanged:)
208 name: NSControlTextDidChangeNotification
209 object: o_net_udpm_addr];
210 [[NSNotificationCenter defaultCenter] addObserver: self
211 selector: @selector(openNetInfoChanged:)
212 name: NSControlTextDidChangeNotification
213 object: o_net_udpm_port];
214 [[NSNotificationCenter defaultCenter] addObserver: self
215 selector: @selector(openNetInfoChanged:)
216 name: NSControlTextDidChangeNotification
217 object: o_net_cs_addr];
218 [[NSNotificationCenter defaultCenter] addObserver: self
219 selector: @selector(openNetInfoChanged:)
220 name: NSControlTextDidChangeNotification
221 object: o_net_cs_port];
222 [[NSNotificationCenter defaultCenter] addObserver: self
223 selector: @selector(openNetInfoChanged:)
224 name: NSControlTextDidChangeNotification
225 object: o_net_http_url];
228 - (void)openTarget:(int)i_type
232 [o_tabview selectTabViewItemAtIndex: i_type];
234 i_result = [NSApp runModalForWindow: o_panel];
239 NSString *o_source = [o_mrl stringValue];
241 [o_playlist appendArray:
242 [NSArray arrayWithObject: o_source] atPos: -1];
246 - (void)tabView:(NSTabView *)o_tv didSelectTabViewItem:(NSTabViewItem *)o_tvi
248 NSString *o_label = [o_tvi label];
250 if( [o_label isEqualToString: _NS("File")] )
252 [self openFilePathChanged: nil];
254 else if( [o_label isEqualToString: _NS("Disc")] )
256 [self openDiscTypeChanged: nil];
258 else if( [o_label isEqualToString: _NS("Network")] )
260 [self openNetModeChanged: nil];
264 - (IBAction)openFileGeneric:(id)sender
266 [self openFilePathChanged: nil];
267 [self openTarget: 0];
270 - (IBAction)openDisc:(id)sender
272 [self openDiscTypeChanged: nil];
273 [self openTarget: 1];
276 - (IBAction)openNet:(id)sender
278 [self openNetModeChanged: nil];
279 [self openTarget: 2];
282 - (void)openFilePathChanged:(NSNotification *)o_notification
284 NSString *o_mrl_string;
285 NSString *o_filename = [o_file_path stringValue];
286 vlc_bool_t b_stream = [o_file_stream state];
288 o_mrl_string = [NSString stringWithFormat: @"%s://%@",
289 b_stream ? "stream" : "file",
291 [o_mrl setStringValue: o_mrl_string];
294 - (IBAction)openFileStreamChanged:(id)sender
296 [self openFilePathChanged: nil];
299 - (IBAction)openDiscTypeChanged:(id)sender
302 vlc_bool_t b_vts, b_device, b_title_chapter;
304 [o_disc_device removeAllItems];
306 o_type = [[o_disc_type selectedCell] title];
308 if ( [o_type isEqualToString: _NS("VIDEO_TS folder")] )
310 b_vts = 1; b_device = b_title_chapter = 0;
316 const char *psz_class = NULL;
317 b_vts = 0; b_device = 1;
319 if ( [o_type isEqualToString: _NS("VCD")] )
321 psz_class = kIOCDMediaClass;
325 else if ( [o_type isEqualToString: _NS("DVD")] )
327 psz_class = kIODVDMediaClass;
331 else /* DVD with menus */
333 psz_class = kIODVDMediaClass;
338 o_devices = GetEjectableMediaOfClass( psz_class );
339 if ( o_devices != nil )
341 int i_devices = [o_devices count];
347 for( i = 0; i < i_devices; i++ )
350 addItemWithObjectValue: [o_devices objectAtIndex: i]];
353 [o_disc_device selectItemAtIndex: 0];
357 [o_disc_device setStringValue:
358 [NSString stringWithFormat: _NS("No %@s found"), o_disc]];
363 [o_disc_device setEnabled: b_device];
364 [o_disc_title setEnabled: b_title_chapter];
365 [o_disc_title_stp setEnabled: b_title_chapter];
366 [o_disc_chapter setEnabled: b_title_chapter];
367 [o_disc_chapter_stp setEnabled: b_title_chapter];
368 [o_disc_videots_folder setEnabled: b_vts];
369 [o_disc_videots_btn_browse setEnabled: b_vts];
371 [self openDiscInfoChanged: nil];
374 - (IBAction)openDiscStepperChanged:(id)sender
376 int i_tag = [sender tag];
380 [o_disc_title setIntValue: [o_disc_title_stp intValue]];
382 else if( i_tag == 1 )
384 [o_disc_chapter setIntValue: [o_disc_chapter_stp intValue]];
387 [self openDiscInfoChanged: nil];
390 - (void)openDiscInfoChanged:(NSNotification *)o_notification
395 NSString *o_mrl_string;
396 int i_title, i_chapter;
398 o_type = [[o_disc_type selectedCell] title];
399 o_device = [o_disc_device stringValue];
400 i_title = [o_disc_title intValue];
401 i_chapter = [o_disc_chapter intValue];
402 o_videots = [o_disc_videots_folder stringValue];
404 if ( [o_type isEqualToString: _NS("VCD")] )
406 if ( [o_device isEqualToString:
407 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
409 o_mrl_string = [NSString stringWithFormat: @"vcd://%@@%i,%i",
410 o_device, i_title, i_chapter];
412 else if ( [o_type isEqualToString: _NS("DVD")] )
414 if ( [o_device isEqualToString:
415 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
417 o_mrl_string = [NSString stringWithFormat: @"dvdold://%@@%i,%i",
418 o_device, i_title, i_chapter];
420 else if ( [o_type isEqualToString: _NS("DVD with menus")] )
422 if ( [o_device isEqualToString:
423 [NSString stringWithFormat: _NS("No %@s found"), _NS("DVD")]] )
425 o_mrl_string = [NSString stringWithFormat: @"dvdplay://%@", o_device];
427 else /* VIDEO_TS folder */
429 o_mrl_string = [NSString stringWithFormat: @"dvdread://%@", o_videots];
432 [o_mrl setStringValue: o_mrl_string];
435 - (IBAction)openNetModeChanged:(id)sender
443 o_mode = [[o_net_mode selectedCell] title];
445 if( [o_mode isEqualToString: @"UDP/RTP"] ) b_udp = TRUE;
446 else if( [o_mode isEqualToString: @"UDP/RTP Multicast"] ) b_udpm = TRUE;
447 else if( [o_mode isEqualToString: @"Channel server"] ) b_cs = TRUE;
448 else if( [o_mode isEqualToString: @"HTTP/FTP/MMS"] ) b_http = TRUE;
450 [o_net_udp_port setEnabled: b_udp];
451 [o_net_udp_port_stp setEnabled: b_udp];
452 [o_net_udpm_addr setEnabled: b_udpm];
453 [o_net_udpm_port setEnabled: b_udpm];
454 [o_net_udpm_port_stp setEnabled: b_udpm];
455 [o_net_cs_addr setEnabled: b_cs];
456 [o_net_cs_port setEnabled: b_cs];
457 [o_net_cs_port_stp setEnabled: b_cs];
458 [o_net_http_url setEnabled: b_http];
460 [self openNetInfoChanged: nil];
463 - (IBAction)openNetStepperChanged:(id)sender
465 int i_tag = [sender tag];
469 [o_net_udp_port setIntValue: [o_net_udp_port_stp intValue]];
471 else if( i_tag == 1 )
473 [o_net_udpm_port setIntValue: [o_net_udpm_port_stp intValue]];
475 else if( i_tag == 2 )
477 [o_net_cs_port setIntValue: [o_net_cs_port_stp intValue]];
480 [self openNetInfoChanged: nil];
483 - (void)openNetInfoChanged:(NSNotification *)o_notification
486 vlc_bool_t b_channel;
487 NSString *o_mrl_string = [NSString string];
488 intf_thread_t * p_intf = [NSApp getIntf];
490 o_mode = [[o_net_mode selectedCell] title];
492 b_channel = (vlc_bool_t)[o_mode isEqualToString: _NS("Channel server")];
493 config_PutInt( p_intf, "network-channel", b_channel );
495 if( [o_mode isEqualToString: _NS("UDP/RTP")] )
497 int i_port = [o_net_udp_port intValue];
499 o_mrl_string = [NSString stringWithString: @"udp://"];
501 if( i_port != config_GetInt( p_intf, "server-port" ) )
504 [o_mrl_string stringByAppendingFormat: @"@:%i", i_port];
507 else if( [o_mode isEqualToString: _NS("UDP/RTP Multicast")] )
509 NSString *o_addr = [o_net_udpm_addr stringValue];
510 int i_port = [o_net_udpm_port intValue];
512 o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr];
514 if( i_port != config_GetInt( p_intf, "server-port" ) )
517 [o_mrl_string stringByAppendingFormat: @":%i", i_port];
520 else if( [o_mode isEqualToString: _NS("Channel server")] )
522 NSString *o_addr = [o_net_cs_addr stringValue];
523 int i_port = [o_net_cs_port intValue];
525 if( p_intf->p_vlc->p_channel == NULL )
527 network_ChannelCreate( p_intf );
530 config_PutPsz( p_intf, "channel-server", [o_addr lossyCString] );
533 config_PutInt( p_intf, "channel-port", i_port );
536 /* FIXME: we should use a playlist server instead */
537 o_mrl_string = [NSString stringWithString: @"udp://"];
539 else if( [o_mode isEqualToString: _NS("HTTP/FTP/MMS")] )
541 NSString *o_url = [o_net_http_url stringValue];
543 if ( ![o_url hasPrefix:@"http:"] && ![o_url hasPrefix:@"ftp:"]
544 && ![o_url hasPrefix:@"mms"] )
545 o_mrl_string = [NSString stringWithFormat: @"http://%@", o_url];
547 o_mrl_string = o_url;
550 [o_mrl setStringValue: o_mrl_string];
553 - (IBAction)openFileBrowse:(id)sender
555 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
557 [o_open_panel setAllowsMultipleSelection: NO];
558 [o_open_panel setTitle: _NS("Open File")];
559 [o_open_panel setPrompt: _NS("Open")];
561 if( [o_open_panel runModalForDirectory: nil
562 file: nil types: nil] == NSOKButton )
564 NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
565 [o_file_path setStringValue: o_filename];
566 [self openFilePathChanged: nil];
570 - (IBAction)openVTSBrowse:(id)sender
572 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
574 [o_open_panel setAllowsMultipleSelection: NO];
575 [o_open_panel setCanChooseFiles: NO];
576 [o_open_panel setCanChooseDirectories: YES];
577 [o_open_panel setTitle: _NS("Open VIDEO_TS Directory")];
578 [o_open_panel setPrompt: _NS("Open")];
580 if( [o_open_panel runModalForDirectory: nil
581 file: nil types: nil] == NSOKButton )
583 NSString *o_dirname = [[o_open_panel filenames] objectAtIndex: 0];
584 [o_disc_videots_folder setStringValue: o_dirname];
585 [self openDiscInfoChanged: nil];
589 - (IBAction)openFile:(id)sender
591 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
593 [o_open_panel setAllowsMultipleSelection: NO];
594 [o_open_panel setTitle: _NS("Open File")];
595 [o_open_panel setPrompt: _NS("Open")];
597 if( [o_open_panel runModalForDirectory: nil
598 file: nil types: nil] == NSOKButton )
600 [o_playlist appendArray: [o_open_panel filenames] atPos: -1];
604 - (IBAction)panelCancel:(id)sender
606 [NSApp stopModalWithCode: 0];
609 - (IBAction)panelOk:(id)sender
611 if( [[o_mrl stringValue] length] )
613 [NSApp stopModalWithCode: 1];