]> git.sesse.net Git - vlc/blob - modules/gui/macosx/open.m
* modules/gui/macosx/open.m: Stream output doesn't do UDP/PS,
[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.12 2003/01/23 11:48:18 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     char * psz_sout = config_GetPsz( p_intf, "sout" );
140
141     if ( psz_sout != NULL && *psz_sout )
142     {
143         [o_sout_cbox setState: YES];
144
145         NSRect s_rect = [o_panel frame];
146         s_rect.size.height = OPEN_PANEL_FULL_HEIGHT + WINDOW_TITLE_HEIGHT;
147         [o_panel setFrame: s_rect display: NO];
148
149         NSPoint s_point;
150         s_point.x = 0;
151         s_point.y = 0;
152         [[o_panel contentView] setBoundsOrigin: s_point];
153     }
154     else
155     {
156         [o_sout_cbox setState: NO];
157
158         NSRect s_rect = [o_panel frame];
159         s_rect.size.height = OPEN_PANEL_SHORT_HEIGHT + WINDOW_TITLE_HEIGHT;
160         [o_panel setFrame: s_rect display: NO];
161
162         NSPoint s_point;
163         s_point.x = 0;
164         s_point.y = OPEN_PANEL_FULL_HEIGHT - OPEN_PANEL_SHORT_HEIGHT;
165         [[o_panel contentView] setBoundsOrigin: s_point];
166     }
167     free(psz_sout);
168
169     [o_panel setTitle: _NS("Open Source")];
170     [o_mrl_lbl setTitle: _NS("Media Resource Locator (MRL)")];
171     [o_ckbox_enqueue setTitle: _NS("Only enqueue in playlist. Do not play.")];
172
173     [o_btn_ok setTitle: _NS("OK")];
174     [o_btn_cancel setTitle: _NS("Cancel")];
175
176     [[o_tabview tabViewItemAtIndex: 0] setLabel: _NS("File")];
177     [[o_tabview tabViewItemAtIndex: 1] setLabel: _NS("Disc")];
178     [[o_tabview tabViewItemAtIndex: 2] setLabel: _NS("Network")];
179
180     [o_file_btn_browse setTitle: _NS("Browse...")];
181     [o_file_stream setTitle: _NS("Treat as a pipe rather than as a file")];
182
183     [o_file_sub_btn_browse setTitle: _NS("Browse...")];
184     [o_file_sub_ckbox setTitle: _NS("Load subtitles")];
185
186     [o_disc_device_lbl setStringValue: _NS("Device name")];
187     [o_disc_title_lbl setStringValue: _NS("Title")];
188     [o_disc_chapter_lbl setStringValue: _NS("Chapter")];
189     [o_disc_videots_btn_browse setStringValue: _NS("Browse...")];
190     [o_disc_dvd_menus setTitle: _NS("Use DVD menus")];
191
192     [[o_disc_type cellAtRow:0 column:0] setTitle: _NS("VIDEO_TS folder")];
193     [[o_disc_type cellAtRow:1 column:0] setTitle: _NS("DVD")];
194     [[o_disc_type cellAtRow:2 column:0] setTitle: _NS("VCD")];
195
196     [o_net_udp_port_lbl setStringValue: _NS("Port")];
197     [o_net_udpm_addr_lbl setStringValue: _NS("Address")];
198     [o_net_udpm_port_lbl setStringValue: _NS("Port")];
199     [o_net_cs_addr_lbl setStringValue: _NS("Address")];
200     [o_net_cs_port_lbl setStringValue: _NS("Port")];
201     [o_net_http_url_lbl setStringValue: _NS("URL")];
202
203     [[o_net_mode cellAtRow:0 column:0] setTitle: _NS("UDP/RTP")];
204     [[o_net_mode cellAtRow:1 column:0] setTitle: _NS("UDP/RTP Multicast")];
205     [[o_net_mode cellAtRow:2 column:0] setTitle: _NS("Channel server")];
206     [[o_net_mode cellAtRow:3 column:0] setTitle: _NS("HTTP/FTP/MMS")];
207
208     [o_net_udp_port setIntValue: config_GetInt( p_intf, "server-port" )];
209     [o_net_udp_port_stp setIntValue: config_GetInt( p_intf, "server-port" )];
210     [o_net_cs_port setIntValue: config_GetInt( p_intf, "channel-port" )];
211     [o_net_cs_port_stp setIntValue: config_GetInt( p_intf, "channel-port" )];
212
213     [o_sout_cbox setTitle: _NS("Stream output")];
214     [o_sout_mrl_lbl setTitle: _NS("Stream output MRL")];
215     [[o_sout_access cellAtRow:0 column:0] setTitle: _NS("File")];
216     [[o_sout_access cellAtRow:1 column:0] setTitle: _NS("UDP")];
217     [[o_sout_access cellAtRow:2 column:0] setTitle: _NS("RTP")];
218
219     [o_sout_file_btn_browse setStringValue: _NS("Browse...")];
220     [o_sout_udp_addr_lbl setStringValue: _NS("Address")];
221     [o_sout_udp_port_lbl setStringValue: _NS("Port")];
222
223     [[o_sout_mux cellAtRow:0 column:0] setTitle: _NS("PS")];
224     [[o_sout_mux cellAtRow:0 column:1] setTitle: _NS("TS")];
225
226     [[NSNotificationCenter defaultCenter] addObserver: self
227         selector: @selector(openFilePathChanged:)
228         name: NSControlTextDidChangeNotification
229         object: o_file_path];
230
231     [[NSNotificationCenter defaultCenter] addObserver: self
232         selector: @selector(openDiscInfoChanged:)
233         name: NSControlTextDidChangeNotification
234         object: o_disc_device];
235     [[NSNotificationCenter defaultCenter] addObserver: self
236         selector: @selector(openDiscInfoChanged:)
237         name: NSControlTextDidChangeNotification
238         object: o_disc_title];
239     [[NSNotificationCenter defaultCenter] addObserver: self
240         selector: @selector(openDiscInfoChanged:)
241         name: NSControlTextDidChangeNotification
242         object: o_disc_chapter];
243     [[NSNotificationCenter defaultCenter] addObserver: self
244         selector: @selector(openDiscInfoChanged:)
245         name: NSControlTextDidChangeNotification
246         object: o_disc_videots_folder];
247
248     [[NSNotificationCenter defaultCenter] addObserver: self
249         selector: @selector(openNetInfoChanged:)
250         name: NSControlTextDidChangeNotification
251         object: o_net_udp_port];
252     [[NSNotificationCenter defaultCenter] addObserver: self
253         selector: @selector(openNetInfoChanged:)
254         name: NSControlTextDidChangeNotification
255         object: o_net_udpm_addr];
256     [[NSNotificationCenter defaultCenter] addObserver: self
257         selector: @selector(openNetInfoChanged:)
258         name: NSControlTextDidChangeNotification
259         object: o_net_udpm_port];
260     [[NSNotificationCenter defaultCenter] addObserver: self
261         selector: @selector(openNetInfoChanged:)
262         name: NSControlTextDidChangeNotification
263         object: o_net_cs_addr];
264     [[NSNotificationCenter defaultCenter] addObserver: self
265         selector: @selector(openNetInfoChanged:)
266         name: NSControlTextDidChangeNotification
267         object: o_net_cs_port];
268     [[NSNotificationCenter defaultCenter] addObserver: self
269         selector: @selector(openNetInfoChanged:)
270         name: NSControlTextDidChangeNotification
271         object: o_net_http_url];
272
273     [[NSNotificationCenter defaultCenter] addObserver: self
274         selector: @selector(soutInfoChanged:)
275         name: NSControlTextDidChangeNotification
276         object: o_sout_file_path];
277     [[NSNotificationCenter defaultCenter] addObserver: self
278         selector: @selector(soutInfoChanged:)
279         name: NSControlTextDidChangeNotification
280         object: o_sout_udp_addr];
281     [[NSNotificationCenter defaultCenter] addObserver: self
282         selector: @selector(soutInfoChanged:)
283         name: NSControlTextDidChangeNotification
284         object: o_sout_udp_port];
285 }
286
287 - (void)openTarget:(int)i_type
288 {
289     int i_result;
290
291     [o_tabview selectTabViewItemAtIndex: i_type];
292     [o_ckbox_enqueue setState: NSOffState];
293     [o_file_sub_path setStringValue: @""];
294     [o_file_sub_ckbox setState: NSOffState];
295     [o_file_sub_path setEnabled: NO];
296     [o_file_sub_btn_browse setEnabled: NO];
297     
298     i_result = [NSApp runModalForWindow: o_panel];
299     [o_panel close];
300
301     if( i_result )
302     {
303         NSString *o_sout = [o_sout_mrl stringValue];
304         intf_thread_t * p_intf = [NSApp getIntf];
305         
306         if ( [o_sout_cbox state] )
307         {
308             config_PutPsz( p_intf, "sout", [o_sout lossyCString] );
309         }
310
311         NSString *o_source = [o_mrl stringValue];
312         BOOL b_enq = [o_ckbox_enqueue state] == NSOnState ? YES : NO;
313         NSString *subPath = [o_file_sub_path stringValue];
314         
315         [o_playlist appendArray: 
316             [NSArray arrayWithObject: o_source] atPos: -1 enqueue:b_enq];
317         
318         if (([o_file_sub_ckbox state] == NSOnState) && !([subPath isEqualTo: @""]))
319             config_PutPsz( p_intf, "sub-file", strdup( [subPath cString] ) );
320     }
321
322     [self soutModeChanged: nil];
323 }
324
325 - (void)tabView:(NSTabView *)o_tv didSelectTabViewItem:(NSTabViewItem *)o_tvi
326 {
327     NSString *o_label = [o_tvi label];
328
329     if( [o_label isEqualToString: _NS("File")] )
330     {
331         [self openFilePathChanged: nil];
332     }
333     else if( [o_label isEqualToString: _NS("Disc")] )
334     {
335         [self openDiscTypeChanged: nil];
336     }
337     else if( [o_label isEqualToString: _NS("Network")] )
338     {
339         [self openNetModeChanged: nil];
340     }  
341 }
342
343 - (IBAction)openFileGeneric:(id)sender
344 {
345     [self openFilePathChanged: nil];
346     [self openTarget: 0];
347 }
348
349 - (IBAction)openDisc:(id)sender
350 {
351     [self openDiscTypeChanged: nil];
352     [self openTarget: 1];
353 }
354
355 - (IBAction)openNet:(id)sender
356 {
357     [self openNetModeChanged: nil];
358     [self openTarget: 2];
359 }
360
361 - (void)openFilePathChanged:(NSNotification *)o_notification
362 {
363     NSString *o_mrl_string;
364     NSString *o_filename = [o_file_path stringValue];
365     NSString *o_ext = [o_filename pathExtension];
366     vlc_bool_t b_stream = [o_file_stream state];
367
368     if ([o_ext isEqualToString: @"bin"] ||
369         [o_ext isEqualToString: @"cue"] ||
370         [o_ext isEqualToString: @"vob"] ||
371         [o_ext isEqualToString: @"iso"])
372     {
373         o_mrl_string = o_filename;
374     }
375     else
376     {
377         o_mrl_string = [NSString stringWithFormat: @"%s://%@",
378                         b_stream ? "stream" : "file",
379                         o_filename];
380     }
381     [o_mrl setStringValue: o_mrl_string]; 
382 }
383
384 - (IBAction)openFileBrowse:(id)sender
385 {
386     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
387     
388     [o_open_panel setAllowsMultipleSelection: NO];
389     [o_open_panel setTitle: _NS("Open File")];
390     [o_open_panel setPrompt: _NS("Open")];
391
392     if( [o_open_panel runModalForDirectory: nil 
393             file: nil types: nil] == NSOKButton )
394     {
395         NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
396         [o_file_path setStringValue: o_filename];
397         [self openFilePathChanged: nil];
398     }
399 }
400
401 - (IBAction)openFileStreamChanged:(id)sender
402 {
403     [self openFilePathChanged: nil];
404 }
405
406 - (IBAction)loadSubsChanged:(id)sender
407 {
408     if ([o_file_sub_ckbox state] == NSOnState)
409     {
410         [o_file_sub_path setEnabled:YES];
411         [o_file_sub_btn_browse setEnabled:YES];
412     }
413     else
414     {
415         [o_file_sub_path setEnabled:NO];
416         [o_file_sub_btn_browse setEnabled:NO];
417     }
418 }
419
420 - (IBAction)openSubBrowse:(id)sender
421 {
422     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
423     
424     [o_open_panel setAllowsMultipleSelection: NO];
425     [o_open_panel setTitle: _NS("Open File")];
426     [o_open_panel setPrompt: _NS("Open")];
427
428     if( [o_open_panel runModalForDirectory: nil 
429             file: nil types: nil] == NSOKButton )
430     {
431         NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
432         [o_file_sub_path setStringValue: o_filename];
433     }
434 }
435
436 - (IBAction)openDiscTypeChanged:(id)sender
437 {
438     NSString *o_type;
439     vlc_bool_t b_device, b_menus, b_title_chapter;
440     
441     [o_disc_device removeAllItems];
442     b_title_chapter = ![o_disc_dvd_menus state];
443     
444     o_type = [[o_disc_type selectedCell] title];
445
446     if ( [o_type isEqualToString: _NS("VIDEO_TS folder")] )
447     {
448         b_device = 0; b_menus = 1;
449     }
450     else
451     {
452         NSArray *o_devices;
453         NSString *o_disc;
454         const char *psz_class = NULL;
455         b_device = 1;
456
457         if ( [o_type isEqualToString: _NS("VCD")] )
458         {
459             psz_class = kIOCDMediaClass;
460             o_disc = o_type;
461             b_menus = 0; b_title_chapter = 1;
462             [o_disc_dvd_menus setState: FALSE];
463         }
464         else
465         {
466             psz_class = kIODVDMediaClass;
467             o_disc = o_type;
468             b_menus = 1;
469         }
470     
471         o_devices = GetEjectableMediaOfClass( psz_class );
472         if ( o_devices != nil )
473         {
474             int i_devices = [o_devices count];
475         
476             if ( i_devices )
477             {
478                 int i;
479         
480                 for( i = 0; i < i_devices; i++ )
481                 {
482                     [o_disc_device 
483                         addItemWithObjectValue: [o_devices objectAtIndex: i]];
484                 }
485
486                 [o_disc_device selectItemAtIndex: 0];
487             }
488             else
489             {
490                 [o_disc_device setStringValue: 
491                     [NSString stringWithFormat: _NS("No %@s found"), o_disc]];
492             }
493         }
494     }
495
496     [o_disc_device setEnabled: b_device];
497     [o_disc_title setEnabled: b_title_chapter];
498     [o_disc_title_stp setEnabled: b_title_chapter];
499     [o_disc_chapter setEnabled: b_title_chapter];
500     [o_disc_chapter_stp setEnabled: b_title_chapter];
501     [o_disc_videots_folder setEnabled: !b_device];
502     [o_disc_videots_btn_browse setEnabled: !b_device];
503     [o_disc_dvd_menus setEnabled: b_menus];
504
505     [self openDiscInfoChanged: nil];
506 }
507
508 - (IBAction)openDiscStepperChanged:(id)sender
509 {
510     int i_tag = [sender tag];
511
512     if( i_tag == 0 )
513     {
514         [o_disc_title setIntValue: [o_disc_title_stp intValue]];
515     }
516     else if( i_tag == 1 )
517     {
518         [o_disc_chapter setIntValue: [o_disc_chapter_stp intValue]];
519     }
520
521     [self openDiscInfoChanged: nil];
522 }
523
524 - (void)openDiscInfoChanged:(NSNotification *)o_notification
525 {
526     NSString *o_type;
527     NSString *o_device;
528     NSString *o_videots;
529     NSString *o_mrl_string;
530     int i_title, i_chapter;
531     vlc_bool_t b_menus;
532
533     o_type = [[o_disc_type selectedCell] title];
534     o_device = [o_disc_device stringValue];
535     i_title = [o_disc_title intValue];
536     i_chapter = [o_disc_chapter intValue];
537     o_videots = [o_disc_videots_folder stringValue];
538     b_menus = [o_disc_dvd_menus state];
539
540     if ( [o_type isEqualToString: _NS("VCD")] )
541     {
542         if ( [o_device isEqualToString:
543                 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
544             o_device = @"";
545         o_mrl_string = [NSString stringWithFormat: @"vcd://%@@%i,%i",
546                         o_device, i_title, i_chapter]; 
547     }
548     else if ( [o_type isEqualToString: _NS("DVD")] )
549     {
550         if ( [o_device isEqualToString:
551                 [NSString stringWithFormat: _NS("No %@s found"), o_type]] )
552             o_device = @"";
553         if ( b_menus )
554             o_mrl_string = [NSString stringWithFormat: @"dvdplay://%@",
555                             o_device]; 
556         else
557             o_mrl_string = [NSString stringWithFormat: @"dvdold://%@@%i,%i",
558                             o_device, i_title, i_chapter]; 
559     }
560     else /* VIDEO_TS folder */
561     {
562         if ( b_menus )
563             o_mrl_string = [NSString stringWithFormat: @"dvdplay://%@",
564                             o_videots]; 
565         else
566             o_mrl_string = [NSString stringWithFormat: @"dvdread://%@@%i,%i",
567                             o_videots, i_title, i_chapter]; 
568     }
569
570     [o_mrl setStringValue: o_mrl_string]; 
571 }
572
573 - (IBAction)openDiscMenusChanged:(id)sender
574 {
575     [self openDiscInfoChanged: nil];
576     [self openDiscTypeChanged: nil];
577 }
578
579 - (IBAction)openVTSBrowse:(id)sender
580 {
581     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
582
583     [o_open_panel setAllowsMultipleSelection: NO];
584     [o_open_panel setCanChooseFiles: NO];
585     [o_open_panel setCanChooseDirectories: YES];
586     [o_open_panel setTitle: _NS("Open VIDEO_TS Directory")];
587     [o_open_panel setPrompt: _NS("Open")];
588
589     if( [o_open_panel runModalForDirectory: nil
590             file: nil types: nil] == NSOKButton )
591     {
592         NSString *o_dirname = [[o_open_panel filenames] objectAtIndex: 0];
593         [o_disc_videots_folder setStringValue: o_dirname];
594         [self openDiscInfoChanged: nil];
595     }
596 }
597
598 - (IBAction)openNetModeChanged:(id)sender
599 {
600     NSString *o_mode;
601     BOOL b_udp = FALSE;
602     BOOL b_udpm = FALSE;
603     BOOL b_cs = FALSE;
604     BOOL b_http = FALSE;
605
606     o_mode = [[o_net_mode selectedCell] title];
607
608     if( [o_mode isEqualToString: _NS("UDP/RTP")] ) b_udp = TRUE;   
609     else if( [o_mode isEqualToString: _NS("UDP/RTP Multicast")] ) b_udpm = TRUE;
610     else if( [o_mode isEqualToString: _NS("Channel server")] ) b_cs = TRUE;
611     else if( [o_mode isEqualToString: _NS("HTTP/FTP/MMS")] ) b_http = TRUE;
612
613     [o_net_udp_port setEnabled: b_udp];
614     [o_net_udp_port_stp setEnabled: b_udp];
615     [o_net_udpm_addr setEnabled: b_udpm];
616     [o_net_udpm_port setEnabled: b_udpm];
617     [o_net_udpm_port_stp setEnabled: b_udpm];
618     [o_net_cs_addr setEnabled: b_cs];
619     [o_net_cs_port setEnabled: b_cs]; 
620     [o_net_cs_port_stp setEnabled: b_cs]; 
621     [o_net_http_url setEnabled: b_http];
622
623     [self openNetInfoChanged: nil];
624 }
625
626 - (IBAction)openNetStepperChanged:(id)sender
627 {
628     int i_tag = [sender tag];
629
630     if( i_tag == 0 )
631     {
632         [o_net_udp_port setIntValue: [o_net_udp_port_stp intValue]];
633     }
634     else if( i_tag == 1 )
635     {
636         [o_net_udpm_port setIntValue: [o_net_udpm_port_stp intValue]];
637     }
638     else if( i_tag == 2 )
639     {
640         [o_net_cs_port setIntValue: [o_net_cs_port_stp intValue]];
641     }
642
643     [self openNetInfoChanged: nil];
644 }
645
646 - (void)openNetInfoChanged:(NSNotification *)o_notification
647 {
648     NSString *o_mode;
649     vlc_bool_t b_channel;
650     NSString *o_mrl_string = [NSString string];
651     intf_thread_t * p_intf = [NSApp getIntf];
652
653     o_mode = [[o_net_mode selectedCell] title];
654
655     b_channel = (vlc_bool_t)[o_mode isEqualToString: _NS("Channel server")]; 
656     config_PutInt( p_intf, "network-channel", b_channel );
657
658     if( [o_mode isEqualToString: _NS("UDP/RTP")] )
659     {
660         int i_port = [o_net_udp_port intValue];
661
662         o_mrl_string = [NSString stringWithString: @"udp://"]; 
663
664         if( i_port != config_GetInt( p_intf, "server-port" ) )
665         {
666             o_mrl_string = 
667                 [o_mrl_string stringByAppendingFormat: @"@:%i", i_port]; 
668         } 
669     }
670     else if( [o_mode isEqualToString: _NS("UDP/RTP Multicast")] ) 
671     {
672         NSString *o_addr = [o_net_udpm_addr stringValue];
673         int i_port = [o_net_udpm_port intValue];
674
675         o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr]; 
676
677         if( i_port != config_GetInt( p_intf, "server-port" ) )
678         {
679             o_mrl_string = 
680                 [o_mrl_string stringByAppendingFormat: @":%i", i_port]; 
681         } 
682     }
683     else if( [o_mode isEqualToString: _NS("Channel server")] )
684     {
685         NSString *o_addr = [o_net_cs_addr stringValue];
686         int i_port = [o_net_cs_port intValue];
687
688         if( p_intf->p_vlc->p_channel == NULL )
689         {
690             network_ChannelCreate( p_intf );
691         } 
692
693         config_PutPsz( p_intf, "channel-server", [o_addr lossyCString] ); 
694         if( i_port < 65536 )
695         {
696             config_PutInt( p_intf, "channel-port", i_port );
697         }
698
699         /* FIXME: we should use a playlist server instead */
700         o_mrl_string = [NSString stringWithString: @"udp://"];
701     }
702     else if( [o_mode isEqualToString: _NS("HTTP/FTP/MMS")] )
703     {
704         NSString *o_url = [o_net_http_url stringValue];
705
706         if ( ![o_url hasPrefix:@"http:"] && ![o_url hasPrefix:@"ftp:"]
707               && ![o_url hasPrefix:@"mms"] )
708             o_mrl_string = [NSString stringWithFormat: @"http://%@", o_url];
709         else
710             o_mrl_string = o_url;
711     }
712
713     [o_mrl setStringValue: o_mrl_string];
714 }
715
716 - (IBAction)soutChanged:(id)sender;
717 {
718     [self soutModeChanged: nil];
719
720     if ( [o_sout_cbox state] )
721     {
722         NSPoint s_point;
723         s_point.x = 0;
724         s_point.y = 0;
725         [[o_panel contentView] setBoundsOrigin: s_point];
726         [[o_panel contentView] setNeedsDisplay: YES];
727
728         NSRect s_rect = [o_panel frame];
729         s_rect.size.height = OPEN_PANEL_FULL_HEIGHT + WINDOW_TITLE_HEIGHT;
730         s_rect.origin.y -= OPEN_PANEL_FULL_HEIGHT - OPEN_PANEL_SHORT_HEIGHT;
731         [o_panel setFrame: s_rect display: YES animate: NO];
732     }
733     else
734     {
735         NSPoint s_point;
736         s_point.x = 0;
737         s_point.y = OPEN_PANEL_FULL_HEIGHT - OPEN_PANEL_SHORT_HEIGHT;
738         [[o_panel contentView] setBoundsOrigin: s_point];
739         [[o_panel contentView] setNeedsDisplay: YES];
740
741         NSRect s_rect = [o_panel frame];
742         s_rect.size.height = OPEN_PANEL_SHORT_HEIGHT + WINDOW_TITLE_HEIGHT;
743         s_rect.origin.y += OPEN_PANEL_FULL_HEIGHT - OPEN_PANEL_SHORT_HEIGHT;
744         [o_panel setFrame: s_rect display: YES animate:NO];
745     }
746 }
747
748 - (IBAction)soutFileBrowse:(id)sender
749 {
750     NSSavePanel *o_save_panel = [NSSavePanel savePanel];
751     NSString *o_mux_string;
752     if ( [[[o_sout_mux selectedCell] title] isEqualToString: _NS("PS")] )
753         o_mux_string = @"vob";
754     else
755         o_mux_string = @"ts";
756
757     NSString * o_name = [NSString stringWithFormat: @"vlc-output.%@",
758                          o_mux_string];
759
760     [o_save_panel setTitle: _NS("Save File")];
761     [o_save_panel setPrompt: _NS("Save")];
762
763     if( [o_save_panel runModalForDirectory: nil
764             file: o_name] == NSOKButton )
765     {
766         NSString *o_filename = [o_save_panel filename];
767         [o_sout_file_path setStringValue: o_filename];
768         [self soutInfoChanged: nil];
769     }
770 }
771
772 - (void)soutModeChanged:(NSNotification *)o_notification
773 {
774     NSString *o_mode;
775     BOOL b_file = FALSE;
776     BOOL b_net = FALSE;
777
778     o_mode = [[o_sout_access selectedCell] title];
779
780     if( [o_mode isEqualToString: _NS("File")] ) b_file = TRUE;   
781     else if( [o_mode isEqualToString: _NS("UDP")] ) b_net = TRUE;
782     else if( [o_mode isEqualToString: _NS("RTP")] ) b_net = TRUE;
783
784     [o_sout_file_path setEnabled: b_file];
785     [o_sout_file_btn_browse setEnabled: b_file];
786     [o_sout_udp_addr setEnabled: b_net];
787     [o_sout_udp_port setEnabled: b_net];
788     [o_sout_udp_port_stp setEnabled: b_net];
789     [[o_sout_mux cellAtRow:0 column: 0] setEnabled: !b_net];
790
791     if ( b_net )
792     {
793         [[o_sout_mux cellAtRow: 0 column:1] setState: YES];
794     }
795
796     [self soutInfoChanged: nil];
797 }
798
799 - (void)soutInfoChanged:(NSNotification *)o_notification
800 {
801     NSString *o_mode;
802     NSString *o_mux;
803     NSString *o_mrl_string;
804     NSString *o_mux_string;
805
806     o_mode = [[o_sout_access selectedCell] title];
807     o_mux = [[o_sout_mux selectedCell] title];
808
809     if ( [o_mux isEqualToString: _NS("PS")] ) o_mux_string = @"ps";
810     else o_mux_string = @"ts";
811
812     if ( [o_mode isEqualToString: _NS("File")] )
813     {
814         o_mrl_string = [NSString stringWithFormat: @"file/%@://%@",
815                         o_mux_string, [o_sout_file_path stringValue]];
816     }
817     else if ( [o_mode isEqualToString: _NS("UDP")] )
818     {
819         o_mrl_string = [NSString stringWithFormat: @"udp/%@://%@:%i",
820                         o_mux_string, [o_sout_udp_addr stringValue],
821                         [o_sout_udp_port intValue]];
822     }
823     else
824     {
825         o_mrl_string = [NSString stringWithFormat: @"rtp/%@://%@:%i",
826                         o_mux_string, [o_sout_udp_addr stringValue],
827                         [o_sout_udp_port intValue]];
828     }
829
830
831     [o_sout_mrl setStringValue: o_mrl_string];
832 }
833
834 - (IBAction)soutStepperChanged:(id)sender
835 {
836     [o_sout_udp_port setIntValue: [o_net_udp_port_stp intValue]];
837
838     [self soutInfoChanged: nil];
839 }
840
841 - (IBAction)openFile:(id)sender
842 {
843     [self openFilePathChanged: nil];
844     [self openTarget: 0];
845 }
846
847 - (IBAction)panelCancel:(id)sender
848 {
849     [NSApp stopModalWithCode: 0];
850 }
851
852 - (IBAction)panelOk:(id)sender
853 {
854     if( [[o_mrl stringValue] length] )
855     {
856         [NSApp stopModalWithCode: 1];
857     }
858     else
859     {
860         NSBeep();
861     }
862 }
863
864 @end