]> git.sesse.net Git - vlc/blob - modules/gui/macosx/open.m
* OS X interface : Added new access modules to the Open panel,
[vlc] / modules / gui / macosx / open.m
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 $
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net> 
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *
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.
14  * 
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <sys/param.h>                                    /* for MAXPATHLEN */
30 #include <string.h>
31
32 #include <paths.h>
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>
38
39 #import <Cocoa/Cocoa.h>
40
41 #include <vlc/vlc.h>
42 #include <vlc/intf.h>
43
44 #include "netutils.h"
45
46 #import "intf.h"
47 #import "playlist.h"
48 #import "open.h"
49
50 /*****************************************************************************
51  * GetEjectableMediaOfClass 
52  *****************************************************************************/
53 NSArray *GetEjectableMediaOfClass( const char *psz_class )
54 {
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;
62
63     kern_result = IOMasterPort( MACH_PORT_NULL, &master_port );
64     if( kern_result != KERN_SUCCESS )
65     {
66         return( nil );
67     }
68     
69     classes_to_match = IOServiceMatching( psz_class );
70     if( classes_to_match == NULL )
71     {
72         return( nil );
73     }
74     
75     CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectable ), 
76                           kCFBooleanTrue );
77     
78     kern_result = IOServiceGetMatchingServices( master_port, classes_to_match, 
79                                                 &media_iterator );
80     if( kern_result != KERN_SUCCESS )
81     {
82         return( nil );
83     }
84
85     p_list = [NSMutableArray arrayWithCapacity: 1];
86     
87     next_media = IOIteratorNext( media_iterator );
88     if( next_media != NULL )
89     {
90         char psz_buf[0x32];
91         size_t dev_path_length;
92         CFTypeRef str_bsd_path;
93     
94         do
95         {
96             str_bsd_path = IORegistryEntryCreateCFProperty( next_media,
97                                                             CFSTR( kIOBSDName ),
98                                                             kCFAllocatorDefault,
99                                                             0 );
100             if( str_bsd_path == NULL )
101             {
102                 IOObjectRelease( next_media );
103                 continue;
104             }
105             
106             snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' );
107             dev_path_length = strlen( psz_buf );
108             
109             if( CFStringGetCString( str_bsd_path,
110                                     (char*)&psz_buf + dev_path_length,
111                                     sizeof(psz_buf) - dev_path_length,
112                                     kCFStringEncodingASCII ) )
113             {
114                 [p_list addObject: [NSString stringWithCString: psz_buf]];
115             }
116             
117             CFRelease( str_bsd_path );
118             
119             IOObjectRelease( next_media );
120         
121         } while( ( next_media = IOIteratorNext( media_iterator ) ) != NULL );
122     }
123     
124     IOObjectRelease( media_iterator );
125
126     o_devices = [NSArray arrayWithArray: p_list];
127
128     return( o_devices );
129 }
130
131 /*****************************************************************************
132  * VLCOpen implementation 
133  *****************************************************************************/
134 @implementation VLCOpen
135
136 - (void)awakeFromNib
137 {
138     intf_thread_t * p_intf = [NSApp getIntf];
139
140     [o_panel setTitle: _NS("Open Target")];
141     [o_mrl_lbl setTitle: _NS("Media Resource Locator (MRL)")];
142
143     [o_btn_ok setTitle: _NS("OK")];
144     [o_btn_cancel setTitle: _NS("Cancel")];
145
146     [[o_tabview tabViewItemAtIndex: 0] setLabel: _NS("File")];
147     [[o_tabview tabViewItemAtIndex: 1] setLabel: _NS("Disc")];
148     [[o_tabview tabViewItemAtIndex: 2] setLabel: _NS("Network")];
149
150     [o_file_btn_browse setTitle: _NS("Browse...")];
151     [o_file_stream setTitle: _NS("Treat as a pipe rather than as a file")];
152
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...")];
157
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")];
162
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")];
169
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")];
174
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" )];
179
180     [[NSNotificationCenter defaultCenter] addObserver: self
181         selector: @selector(openFilePathChanged:)
182         name: NSControlTextDidChangeNotification
183         object: o_file_path];
184
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];
201
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];
226 }
227
228 - (void)openTarget:(int)i_type
229 {
230     int i_result;
231
232     [o_tabview selectTabViewItemAtIndex: i_type];
233
234     i_result = [NSApp runModalForWindow: o_panel];
235     [o_panel close];
236
237     if( i_result )
238     {
239         NSString *o_source = [o_mrl stringValue];
240
241         [o_playlist appendArray: 
242             [NSArray arrayWithObject: o_source] atPos: -1];
243     }
244 }
245
246 - (void)tabView:(NSTabView *)o_tv didSelectTabViewItem:(NSTabViewItem *)o_tvi
247 {
248     NSString *o_label = [o_tvi label];
249
250     if( [o_label isEqualToString: _NS("File")] )
251     {
252         [self openFilePathChanged: nil];
253     }
254     else if( [o_label isEqualToString: _NS("Disc")] )
255     {
256         [self openDiscTypeChanged: nil];
257     }
258     else if( [o_label isEqualToString: _NS("Network")] )
259     {
260         [self openNetModeChanged: nil];
261     }  
262 }
263
264 - (IBAction)openFileGeneric:(id)sender
265 {
266     [self openFilePathChanged: nil];
267     [self openTarget: 0];
268 }
269
270 - (IBAction)openDisc:(id)sender
271 {
272     [self openDiscTypeChanged: nil];
273     [self openTarget: 1];
274 }
275
276 - (IBAction)openNet:(id)sender
277 {
278     [self openNetModeChanged: nil];
279     [self openTarget: 2];
280 }
281
282 - (void)openFilePathChanged:(NSNotification *)o_notification
283 {
284     NSString *o_mrl_string;
285     NSString *o_filename = [o_file_path stringValue];
286     vlc_bool_t b_stream = [o_file_stream state];
287
288     o_mrl_string = [NSString stringWithFormat: @"%s://%@",
289                     b_stream ? "stream" : "file",
290                     o_filename];
291     [o_mrl setStringValue: o_mrl_string]; 
292 }
293
294 - (IBAction)openFileStreamChanged:(id)sender
295 {
296     [self openFilePathChanged: nil];
297 }
298
299 - (IBAction)openDiscTypeChanged:(id)sender
300 {
301     NSString *o_type;
302     vlc_bool_t b_vts, b_device, b_title_chapter;
303     
304     [o_disc_device removeAllItems];
305     
306     o_type = [[o_disc_type selectedCell] title];
307
308     if ( [o_type isEqualToString: _NS("VIDEO_TS folder")] )
309     {
310         b_vts = 1; b_device = b_title_chapter = 0;
311     }
312     else
313     {
314         NSArray *o_devices;
315         NSString *o_disc;
316         const char *psz_class = NULL;
317         b_vts = 0; b_device = 1;
318
319         if ( [o_type isEqualToString: _NS("VCD")] )
320         {
321             psz_class = kIOCDMediaClass;
322             o_disc = o_type;
323             b_title_chapter = 1;
324         }
325         else if ( [o_type isEqualToString: _NS("DVD")] )
326         {
327             psz_class = kIODVDMediaClass;
328             o_disc = o_type;
329             b_title_chapter = 1;
330         }
331         else /* DVD with menus */
332         {
333             psz_class = kIODVDMediaClass;
334             o_disc = _NS("DVD");
335             b_title_chapter = 0;
336         }
337     
338         o_devices = GetEjectableMediaOfClass( psz_class );
339         if ( o_devices != nil )
340         {
341             int i_devices = [o_devices count];
342         
343             if ( i_devices )
344             {
345                 int i;
346         
347                 for( i = 0; i < i_devices; i++ )
348                 {
349                     [o_disc_device 
350                         addItemWithObjectValue: [o_devices objectAtIndex: i]];
351                 }
352
353                 [o_disc_device selectItemAtIndex: 0];
354             }
355             else
356             {
357                 [o_disc_device setStringValue: 
358                     [NSString stringWithFormat: _NS("No %@s found"), o_disc]];
359             }
360         }
361     }
362
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];
370
371     [self openDiscInfoChanged: nil];
372 }
373
374 - (IBAction)openDiscStepperChanged:(id)sender
375 {
376     int i_tag = [sender tag];
377
378     if( i_tag == 0 )
379     {
380         [o_disc_title setIntValue: [o_disc_title_stp intValue]];
381     }
382     else if( i_tag == 1 )
383     {
384         [o_disc_chapter setIntValue: [o_disc_chapter_stp intValue]];
385     }
386
387     [self openDiscInfoChanged: nil];
388 }
389
390 - (void)openDiscInfoChanged:(NSNotification *)o_notification
391 {
392     NSString *o_type;
393     NSString *o_device;
394     NSString *o_videots;
395     NSString *o_mrl_string;
396     int i_title, i_chapter;
397
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];
403
404     if ( [o_type isEqualToString: _NS("VCD")] )
405     {
406         if ( [o_device isEqualToString:
407                 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
408             o_device = @"";
409         o_mrl_string = [NSString stringWithFormat: @"vcd://%@@%i,%i",
410                         o_device, i_title, i_chapter]; 
411     }
412     else if ( [o_type isEqualToString: _NS("DVD")] )
413     {
414         if ( [o_device isEqualToString:
415                 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
416             o_device = @"";
417         o_mrl_string = [NSString stringWithFormat: @"dvdold://%@@%i,%i",
418                         o_device, i_title, i_chapter]; 
419     }
420     else if ( [o_type isEqualToString: _NS("DVD with menus")] )
421     {
422         if ( [o_device isEqualToString:
423                 [NSString stringWithFormat: _NS("No %@s found"), _NS("DVD")]] )
424             o_device = @"";
425         o_mrl_string = [NSString stringWithFormat: @"dvdplay://%@", o_device]; 
426     }
427     else /* VIDEO_TS folder */
428     {
429         o_mrl_string = [NSString stringWithFormat: @"dvdread://%@", o_videots]; 
430     }
431
432     [o_mrl setStringValue: o_mrl_string]; 
433 }
434
435 - (IBAction)openNetModeChanged:(id)sender
436 {
437     NSString *o_mode;
438     BOOL b_udp = FALSE;
439     BOOL b_udpm = FALSE;
440     BOOL b_cs = FALSE;
441     BOOL b_http = FALSE;
442
443     o_mode = [[o_net_mode selectedCell] title];
444
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;
449
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];
459
460     [self openNetInfoChanged: nil];
461 }
462
463 - (IBAction)openNetStepperChanged:(id)sender
464 {
465     int i_tag = [sender tag];
466
467     if( i_tag == 0 )
468     {
469         [o_net_udp_port setIntValue: [o_net_udp_port_stp intValue]];
470     }
471     else if( i_tag == 1 )
472     {
473         [o_net_udpm_port setIntValue: [o_net_udpm_port_stp intValue]];
474     }
475     else if( i_tag == 2 )
476     {
477         [o_net_cs_port setIntValue: [o_net_cs_port_stp intValue]];
478     }
479
480     [self openNetInfoChanged: nil];
481 }
482
483 - (void)openNetInfoChanged:(NSNotification *)o_notification
484 {
485     NSString *o_mode;
486     vlc_bool_t b_channel;
487     NSString *o_mrl_string = [NSString string];
488     intf_thread_t * p_intf = [NSApp getIntf];
489
490     o_mode = [[o_net_mode selectedCell] title];
491
492     b_channel = (vlc_bool_t)[o_mode isEqualToString: _NS("Channel server")]; 
493     config_PutInt( p_intf, "network-channel", b_channel );
494
495     if( [o_mode isEqualToString: _NS("UDP/RTP")] )
496     {
497         int i_port = [o_net_udp_port intValue];
498
499         o_mrl_string = [NSString stringWithString: @"udp://"]; 
500
501         if( i_port != config_GetInt( p_intf, "server-port" ) )
502         {
503             o_mrl_string = 
504                 [o_mrl_string stringByAppendingFormat: @"@:%i", i_port]; 
505         } 
506     }
507     else if( [o_mode isEqualToString: _NS("UDP/RTP Multicast")] ) 
508     {
509         NSString *o_addr = [o_net_udpm_addr stringValue];
510         int i_port = [o_net_udpm_port intValue];
511
512         o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr]; 
513
514         if( i_port != config_GetInt( p_intf, "server-port" ) )
515         {
516             o_mrl_string = 
517                 [o_mrl_string stringByAppendingFormat: @":%i", i_port]; 
518         } 
519     }
520     else if( [o_mode isEqualToString: _NS("Channel server")] )
521     {
522         NSString *o_addr = [o_net_cs_addr stringValue];
523         int i_port = [o_net_cs_port intValue];
524
525         if( p_intf->p_vlc->p_channel == NULL )
526         {
527             network_ChannelCreate( p_intf );
528         } 
529
530         config_PutPsz( p_intf, "channel-server", [o_addr lossyCString] ); 
531         if( i_port < 65536 )
532         {
533             config_PutInt( p_intf, "channel-port", i_port );
534         }
535
536         /* FIXME: we should use a playlist server instead */
537         o_mrl_string = [NSString stringWithString: @"udp://"];
538     }
539     else if( [o_mode isEqualToString: _NS("HTTP/FTP/MMS")] )
540     {
541         NSString *o_url = [o_net_http_url stringValue];
542
543         if ( ![o_url hasPrefix:@"http:"] && ![o_url hasPrefix:@"ftp:"]
544               && ![o_url hasPrefix:@"mms"] )
545             o_mrl_string = [NSString stringWithFormat: @"http://%@", o_url];
546         else
547             o_mrl_string = o_url;
548     }
549
550     [o_mrl setStringValue: o_mrl_string];
551 }
552
553 - (IBAction)openFileBrowse:(id)sender
554 {
555     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
556     
557     [o_open_panel setAllowsMultipleSelection: NO];
558     [o_open_panel setTitle: _NS("Open File")];
559     [o_open_panel setPrompt: _NS("Open")];
560
561     if( [o_open_panel runModalForDirectory: nil 
562             file: nil types: nil] == NSOKButton )
563     {
564         NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
565         [o_file_path setStringValue: o_filename];
566         [self openFilePathChanged: nil];
567     }
568 }
569
570 - (IBAction)openVTSBrowse:(id)sender
571 {
572     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
573
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")];
579
580     if( [o_open_panel runModalForDirectory: nil
581             file: nil types: nil] == NSOKButton )
582     {
583         NSString *o_dirname = [[o_open_panel filenames] objectAtIndex: 0];
584         [o_disc_videots_folder setStringValue: o_dirname];
585         [self openDiscInfoChanged: nil];
586     }
587 }
588
589 - (IBAction)openFile:(id)sender
590 {
591     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
592
593     [o_open_panel setAllowsMultipleSelection: NO];
594     [o_open_panel setTitle: _NS("Open File")];
595     [o_open_panel setPrompt: _NS("Open")];
596
597     if( [o_open_panel runModalForDirectory: nil
598             file: nil types: nil] == NSOKButton )
599     {
600         [o_playlist appendArray: [o_open_panel filenames] atPos: -1];
601     }
602 }
603
604 - (IBAction)panelCancel:(id)sender
605 {
606     [NSApp stopModalWithCode: 0];
607 }
608
609 - (IBAction)panelOk:(id)sender
610 {
611     if( [[o_mrl stringValue] length] )
612     {
613         [NSApp stopModalWithCode: 1];
614     }
615     else
616     {
617         NSBeep();
618     }
619 }
620
621 @end