]> git.sesse.net Git - vlc/blob - modules/gui/macosx/open.m
macosx: exposed qtcapture's width and height options in the open panel
[vlc] / modules / gui / macosx / open.m
1 /*****************************************************************************
2  * open.m: Open dialogues for VLC's MacOS X port
3  *****************************************************************************
4  * Copyright (C) 2002-2011 the VideoLAN team
5  * $Id$
6  *
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>
12  *
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.
17  *
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.
22  *
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  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #import <stdlib.h>                                      /* malloc(), free() */
32 #import <sys/param.h>                                    /* for MAXPATHLEN */
33
34 #import <paths.h>
35 #import <IOKit/IOBSD.h>
36 #import <IOKit/storage/IOMedia.h>
37 #import <IOKit/storage/IOCDMedia.h>
38 #import <IOKit/storage/IODVDMedia.h>
39 #import <IOKit/storage/IOBDMedia.h>
40 #import <Cocoa/Cocoa.h>
41 #import <QTKit/QTKit.h>
42
43 #import "intf.h"
44 #import "playlist.h"
45 #import "open.h"
46 #import "output.h"
47 #import "eyetv.h"
48
49 #import <vlc_url.h>
50
51 NSArray               *qtkvideoDevices;
52 #define setEyeTVUnconnected \
53 [o_capture_lbl setStringValue: _NS("No device is selected")]; \
54 [o_capture_long_lbl setStringValue: _NS("Any device is not selected.\n\nChose abailable device in above pull-down menu\n.")]; \
55 [o_capture_lbl displayIfNeeded]; \
56 [o_capture_long_lbl displayIfNeeded]; \
57 [self showCaptureView: o_capture_label_view]
58
59 #define kVLCMediaAudioCD "AudioCD"
60 #define kVLCMediaDVD "DVD"
61 #define kVLCMediaVCD "VCD"
62 #define kVLCMediaSVCD "SVCD"
63 #define kVLCMediaBD "Bluray"
64 #define kVLCMediaVideoTSFolder "VIDEO_TS"
65 #define kVLCMediaBDMVFolder "BDMV"
66 #define kVLCMediaUnknown "Unknown"
67
68
69 /*****************************************************************************
70  * VLCOpen implementation
71  *****************************************************************************/
72 @implementation VLCOpen
73
74 static VLCOpen *_o_sharedMainInstance = nil;
75
76 + (VLCOpen *)sharedInstance
77 {
78     return _o_sharedMainInstance ? _o_sharedMainInstance : [[self alloc] init];
79 }
80
81 - (id)init
82 {
83     if( _o_sharedMainInstance) {
84         [self dealloc];
85     } else {
86         _o_sharedMainInstance = [super init];
87         p_intf = VLCIntf;
88     }
89  
90     return _o_sharedMainInstance;
91 }
92
93 - (void)dealloc
94 {
95     [o_specialMediaFolders release];
96     [o_opticalDevices release];
97     if( o_file_slave_path )
98         [o_file_slave_path release];
99     [o_mrl release];
100     [super dealloc];
101 }
102
103 - (void)awakeFromNib
104 {
105     [o_panel setTitle: _NS("Open Source")];
106     [o_mrl_lbl setStringValue: _NS("Media Resource Locator (MRL)")];
107
108     [o_btn_ok setTitle: _NS("Open")];
109     [o_btn_cancel setTitle: _NS("Cancel")];
110
111     [[o_tabview tabViewItemAtIndex: 0] setLabel: _NS("File")];
112     [[o_tabview tabViewItemAtIndex: 1] setLabel: _NS("Disc")];
113     [[o_tabview tabViewItemAtIndex: 2] setLabel: _NS("Network")];
114     [[o_tabview tabViewItemAtIndex: 3] setLabel: _NS("Capture")];
115
116     [o_file_name setStringValue: @""];
117     [o_file_name_stub setStringValue: _NS("Choose a file")];
118     [o_file_icon_well setImage: [NSImage imageNamed:@"generic"]];
119     [o_file_btn_browse setTitle: _NS("Browse...")];
120     [o_file_stream setTitle: _NS("Treat as a pipe rather than as a file")];
121     [o_file_stream setHidden: NO];
122     [o_file_slave_ckbox setTitle: _NS("Play another media synchronously")];
123     [o_file_slave_select_btn setTitle: _NS("Choose...")];
124     [o_file_slave_filename_lbl setStringValue: @""];
125     [o_file_slave_icon_well setImage: NULL];
126     [o_file_subtitles_filename_lbl setStringValue: @""];
127     [o_file_subtitles_icon_well setImage: NULL];
128
129     [o_disc_selector_pop removeAllItems];
130     [o_disc_selector_pop setHidden: NO];
131     NSString *o_videots = _NS("Open VIDEO_TS folder");
132     NSString *o_bdmv = _NS("Open BDMV folder");
133     [o_disc_nodisc_lbl setStringValue: _NS("Insert Disc")];
134     [o_disc_nodisc_videots_btn setTitle: o_videots];
135     [o_disc_nodisc_bdmv_btn setTitle: o_bdmv];
136     [o_disc_audiocd_lbl setStringValue: _NS("Audio CD")];
137     [o_disc_audiocd_trackcount_lbl setStringValue: @""];
138     [o_disc_audiocd_videots_btn setTitle: o_videots];
139     [o_disc_audiocd_bdmv_btn setTitle: o_bdmv];
140     [o_disc_dvd_lbl setStringValue: @""];
141     [o_disc_dvd_disablemenus_btn setTitle: _NS("Disable DVD menus")];
142     [o_disc_dvd_videots_btn setTitle: o_videots];
143     [o_disc_dvd_bdmv_btn setTitle: o_bdmv];
144     [o_disc_dvdwomenus_lbl setStringValue: @""];
145     [o_disc_dvdwomenus_enablemenus_btn setTitle: _NS("Enable DVD menus")];
146     [o_disc_dvdwomenus_videots_btn setTitle: o_videots];
147     [o_disc_dvdwomenus_bdmv_btn setTitle: o_bdmv];
148     [o_disc_dvdwomenus_title_lbl setStringValue: _NS("Title")];
149     [o_disc_dvdwomenus_chapter_lbl setStringValue: _NS("Chapter")];
150     [o_disc_vcd_title_lbl setStringValue: _NS("Title")];
151     [o_disc_vcd_chapter_lbl setStringValue: _NS("Chapter")];
152     [o_disc_vcd_videots_btn setTitle: o_videots];
153     [o_disc_vcd_bdmv_btn setTitle: o_bdmv];
154     [o_disc_bd_videots_btn setTitle: o_videots];
155     [o_disc_bd_bdmv_btn setTitle: o_bdmv];
156
157     [o_net_udp_port_lbl setStringValue: _NS("Port")];
158     [o_net_udpm_addr_lbl setStringValue: _NS("IP Address")];
159     [o_net_udpm_port_lbl setStringValue: _NS("Port")];
160     [o_net_http_url_lbl setStringValue: _NS("URL")];
161     [o_net_help_lbl setStringValue: _NS("To Open a usual network stream (HTTP, RTSP, RTMP, 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.")];
162     [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.")];
163     [o_net_udp_cancel_btn setTitle: _NS("Cancel")];
164     [o_net_udp_ok_btn setTitle: _NS("Open")];
165     [o_net_openUDP_btn setTitle: _NS("Open RTP/UDP Stream")];
166     [o_net_udp_mode_lbl setStringValue: _NS("Mode")];
167     [o_net_udp_protocol_lbl setStringValue: _NS("Protocol")];
168     [o_net_udp_address_lbl setStringValue: _NS("Address")];
169
170     [[o_net_mode cellAtRow:0 column:0] setTitle: _NS("Unicast")];
171     [[o_net_mode cellAtRow:1 column:0] setTitle: _NS("Multicast")];
172
173     [o_net_udp_port setIntValue: config_GetInt( p_intf, "server-port" )];
174     [o_net_udp_port_stp setIntValue: config_GetInt( p_intf, "server-port" )];
175
176     [o_eyetv_chn_bgbar setUsesThreadedAnimation: YES];
177
178     [o_capture_mode_pop removeAllItems];
179     [o_capture_mode_pop addItemWithTitle: _NS("Capture Device")];
180     [o_capture_mode_pop addItemWithTitle: _NS("Screen")];
181     [o_capture_mode_pop addItemWithTitle: @"EyeTV"];
182     [o_screen_long_lbl setStringValue: _NS("This input allows you to save, stream or display your current screen contents.")];
183     [o_screen_fps_lbl setStringValue: _NS("Frames per Second:")];
184     [o_screen_left_lbl setStringValue: _NS("Subscreen left:")];
185     [o_screen_top_lbl setStringValue: _NS("Subscreen top:")];
186     [o_screen_width_lbl setStringValue: _NS("Subscreen width:")];
187     [o_screen_height_lbl setStringValue: _NS("Subscreen height:")];
188     [o_screen_follow_mouse_ckb setTitle: _NS("Follow the mouse")];
189     [o_eyetv_currentChannel_lbl setStringValue: _NS("Current channel:")];
190     [o_eyetv_previousProgram_btn setTitle: _NS("Previous Channel")];
191     [o_eyetv_nextProgram_btn setTitle: _NS("Next Channel")];
192     [o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
193     [o_eyetv_noInstance_lbl setStringValue: _NS("EyeTV is not launched")];
194     [o_eyetv_noInstanceLong_lbl setStringValue: _NS("VLC could not connect to EyeTV.\nMake sure that you installed VLC's EyeTV plugin.")];
195     [o_eyetv_launchEyeTV_btn setTitle: _NS("Launch EyeTV now")];
196     [o_eyetv_getPlugin_btn setTitle: _NS("Download Plugin")];
197     [o_qtk_long_lbl setStringValue: _NS("This input allows you to process input signals from QuickTime-compatible video devices.\nLive Audio input is not supported.")];
198     [o_capture_width_lbl setStringValue: _NS("Image width:")];
199     [o_capture_height_lbl setStringValue: _NS("Image height:")];
200
201     [self qtkvideoDevices];
202     [o_qtk_device_pop removeAllItems];
203     msg_Dbg( VLCIntf, "Found %lu capture devices", [qtkvideoDevices count] );
204     if([qtkvideoDevices count] == 0){
205         [o_qtk_device_pop addItemWithTitle: _NS("None")];
206         [qtk_currdevice_uid release];
207     }else {
208         if (!qtk_currdevice_uid) {
209             qtk_currdevice_uid = [[[QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeVideo] uniqueID]
210                                                                 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
211         }
212         for(int ivideo = 0; ivideo < [qtkvideoDevices count]; ivideo++){
213             QTCaptureDevice *qtk_device;
214             qtk_device = [qtkvideoDevices objectAtIndex:ivideo];
215             [o_qtk_device_pop addItemWithTitle: [qtk_device localizedDisplayName]];
216             if([[[qtk_device uniqueID]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:qtk_currdevice_uid]){
217                 [o_qtk_device_pop selectItemAtIndex:ivideo];
218             }
219         }
220     }
221
222     [self setSubPanel];
223
224     [[NSNotificationCenter defaultCenter] addObserver: self
225         selector: @selector(openNetInfoChanged:)
226         name: NSControlTextDidChangeNotification
227         object: o_net_udp_port];
228     [[NSNotificationCenter defaultCenter] addObserver: self
229         selector: @selector(openNetInfoChanged:)
230         name: NSControlTextDidChangeNotification
231         object: o_net_udpm_addr];
232     [[NSNotificationCenter defaultCenter] addObserver: self
233         selector: @selector(openNetInfoChanged:)
234         name: NSControlTextDidChangeNotification
235         object: o_net_udpm_port];
236     [[NSNotificationCenter defaultCenter] addObserver: self
237         selector: @selector(openNetInfoChanged:)
238         name: NSControlTextDidChangeNotification
239         object: o_net_http_url];
240
241     [[NSDistributedNotificationCenter defaultCenter] addObserver: self
242                                                         selector: @selector(eyetvChanged:)
243                                                             name: NULL
244                                                           object: @"VLCEyeTVSupport"
245                                               suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];
246
247     [[NSNotificationCenter defaultCenter] addObserver: self
248                                              selector: @selector(screenFPSfieldChanged:)
249                                                  name: NSControlTextDidChangeNotification
250                                                object: o_screen_fps_fld];
251
252     /* register clicks on text fields */
253     [[NSNotificationCenter defaultCenter] addObserver: self
254                                              selector: @selector(textFieldWasClicked:)
255                                                  name: @"VLCOpenTextFieldWasClicked"
256                                                object: nil];
257
258     /* we want to be notified about removed or added media */
259     o_specialMediaFolders = [[NSMutableArray alloc] init];
260     o_opticalDevices = [[NSMutableArray alloc] init];
261     NSWorkspace *sharedWorkspace = [NSWorkspace sharedWorkspace];
262         [[sharedWorkspace notificationCenter] addObserver:self selector:@selector(scanOpticalMedia:) name:NSWorkspaceDidMountNotification object:nil];
263         [[sharedWorkspace notificationCenter] addObserver:self selector:@selector(scanOpticalMedia:) name:NSWorkspaceDidUnmountNotification object:nil];
264         [[sharedWorkspace notificationCenter] addObserver:self selector:@selector(scanOpticalMedia:) name:NSWorkspaceDidRenameVolumeNotification object:nil];
265     [self scanOpticalMedia:nil];
266
267     [self setMRL: @""];
268 }
269
270 - (void)setMRL:(NSString *)newMRL
271 {
272     [o_mrl release];
273     o_mrl = newMRL;
274     [o_mrl retain];
275     [o_mrl_fld setStringValue: newMRL];
276     if ([o_mrl length] > 0)
277         [o_btn_ok setEnabled: YES];
278     else
279         [o_btn_ok setEnabled: NO];
280 }
281
282 - (NSString *)MRL
283 {
284     return o_mrl;
285 }
286
287 - (void)setSubPanel
288 {
289     int i_index;
290     module_config_t * p_item;
291
292     [o_file_sub_ckbox setTitle: _NS("Load subtitles file:")];
293     [o_file_sub_btn_settings setTitle: _NS("Settings...")];
294     [o_file_sub_btn_browse setTitle: _NS("Browse...")];
295     [o_file_sub_override setTitle: _NS("Override parametters")];
296     [o_file_sub_delay_lbl setStringValue: _NS("Delay")];
297     [o_file_sub_delay_stp setEnabled: NO];
298     [o_file_sub_fps_lbl setStringValue: _NS("FPS")];
299     [o_file_sub_fps_stp setEnabled: NO];
300     [o_file_sub_encoding_lbl setStringValue: _NS("Subtitles encoding")];
301     [o_file_sub_encoding_pop removeAllItems];
302     [o_file_sub_size_lbl setStringValue: _NS("Font size")];
303     [o_file_sub_size_pop removeAllItems];
304     [o_file_sub_align_lbl setStringValue: _NS("Subtitles alignment")];
305     [o_file_sub_align_pop removeAllItems];
306     [o_file_sub_ok_btn setStringValue: _NS("OK")];
307     [o_file_sub_font_box setTitle: _NS("Font Properties")];
308     [o_file_sub_file_box setTitle: _NS("Subtitle File")];
309
310     p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-encoding" );
311
312     if( p_item )
313     {
314         for( i_index = 0; p_item->ppsz_list && p_item->ppsz_list[i_index];
315              i_index++ )
316         {
317             [o_file_sub_encoding_pop addItemWithTitle:
318                 [NSString stringWithUTF8String: p_item->ppsz_list[i_index]]];
319         }
320         [o_file_sub_encoding_pop selectItemWithTitle:
321                 [NSString stringWithUTF8String: p_item->value.psz]];
322     }
323
324     p_item = config_FindConfig( VLC_OBJECT(p_intf), "subsdec-align" );
325
326     if ( p_item )
327     {
328         for ( i_index = 0; i_index < p_item->i_list; i_index++ )
329         {
330             [o_file_sub_align_pop addItemWithTitle:
331                 [NSString stringWithUTF8String:
332                 p_item->ppsz_list_text[i_index]]];
333         }
334         [o_file_sub_align_pop selectItemAtIndex: p_item->value.i];
335     }
336
337     p_item = config_FindConfig( VLC_OBJECT(p_intf), "freetype-rel-fontsize" );
338
339     if ( p_item )
340     {
341         for ( i_index = 0; i_index < p_item->i_list; i_index++ )
342         {
343             [o_file_sub_size_pop addItemWithTitle:
344                 [NSString stringWithUTF8String:
345                 p_item->ppsz_list_text[i_index]]];
346             if ( p_item->value.i == p_item->pi_list[i_index] )
347             {
348                 [o_file_sub_size_pop selectItemAtIndex: i_index];
349             }
350         }
351     }
352 }
353
354 - (void)openTarget:(int)i_type
355 {
356     int i_result;
357
358     b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
359
360     [o_tabview selectTabViewItemAtIndex: i_type];
361     [o_file_sub_ckbox setState: NSOffState];
362  
363     i_result = [NSApp runModalForWindow: o_panel];
364     [o_panel close];
365
366     if( i_result )
367     {
368         NSMutableDictionary *o_dic;
369         NSMutableArray *o_options = [NSMutableArray array];
370         unsigned int i;
371
372         o_dic = [NSMutableDictionary dictionaryWithObject: [self MRL] forKey: @"ITEM_URL"];
373         if( [o_file_sub_ckbox state] == NSOnState )
374         {
375             module_config_t * p_item;
376
377             [o_options addObject: [NSString stringWithFormat: @"sub-file=%@", [o_file_sub_path stringValue]]];
378             if( [o_file_sub_override state] == NSOnState )
379             {
380                 [o_options addObject: [NSString stringWithFormat: @"sub-delay=%i", (int)( [o_file_sub_delay intValue] * 10 )]];
381                 [o_options addObject: [NSString stringWithFormat: @"sub-fps=%f", [o_file_sub_fps floatValue]]];
382             }
383             [o_options addObject: [NSString stringWithFormat:
384                     @"subsdec-encoding=%@",
385                     [o_file_sub_encoding_pop titleOfSelectedItem]]];
386             [o_options addObject: [NSString stringWithFormat:
387                     @"subsdec-align=%i",
388                     [o_file_sub_align_pop indexOfSelectedItem]]];
389
390             p_item = config_FindConfig( VLC_OBJECT(p_intf),
391                                             "freetype-rel-fontsize" );
392
393             if ( p_item )
394             {
395                 [o_options addObject: [NSString stringWithFormat:
396                     @"freetype-rel-fontsize=%i",
397                     p_item->pi_list[[o_file_sub_size_pop indexOfSelectedItem]]]];
398             }
399         }
400         if( [o_output_ckbox state] == NSOnState )
401         {
402             for (i = 0 ; i < [[o_sout_options mrl] count] ; i++)
403             {
404                 [o_options addObject: [NSString stringWithString:
405                       [[(VLCOutput *)o_sout_options mrl] objectAtIndex: i]]];
406             }
407         }
408         if( [o_file_slave_ckbox state] && o_file_slave_path )
409            [o_options addObject: [NSString stringWithFormat: @"input-slave=%@", o_file_slave_path]];
410         if( [[[o_tabview selectedTabViewItem] label] isEqualToString: _NS("Capture")] )
411         {
412             if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Screen")] )
413             {
414                 [o_options addObject: [NSString stringWithFormat: @"screen-fps=%f", [o_screen_fps_fld floatValue]]];
415                 [o_options addObject: [NSString stringWithFormat: @"screen-left=%i", [o_screen_left_fld intValue]]];
416                 [o_options addObject: [NSString stringWithFormat: @"screen-top=%i", [o_screen_top_fld intValue]]];
417                 [o_options addObject: [NSString stringWithFormat: @"screen-width=%i", [o_screen_width_fld intValue]]];
418                 [o_options addObject: [NSString stringWithFormat: @"screen-height=%i", [o_screen_height_fld intValue]]];
419                 if( [o_screen_follow_mouse_ckb intValue] == YES )
420                     [o_options addObject: @"screen-follow-mouse"];
421                 else
422                     [o_options addObject: @"no-screen-follow-mouse"];
423             }
424             else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Capture Device")] )
425             {
426                 [o_options addObject: [NSString stringWithFormat: @"qtcapture-width=%i", [o_capture_width_fld intValue]]];
427                 [o_options addObject: [NSString stringWithFormat: @"qtcapture-height=%i", [o_capture_height_fld intValue]]];
428             }
429         }
430
431         /* apply the options to our item(s) */
432         [o_dic setObject: (NSArray *)[o_options copy] forKey: @"ITEM_OPTIONS"];
433         if( b_autoplay )
434             [o_playlist appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue:NO];
435         else
436             [o_playlist appendArray: [NSArray arrayWithObject: o_dic] atPos: -1 enqueue:YES];
437     }
438 }
439
440 - (IBAction)qtkChanged:(id)sender
441 {
442     NSValue *sizes = [[[[qtkvideoDevices objectAtIndex:[o_qtk_device_pop indexOfSelectedItem]] formatDescriptions] objectAtIndex: 0] attributeForKey: QTFormatDescriptionVideoEncodedPixelsSizeAttribute];
443
444     [o_capture_width_fld setIntValue: [sizes sizeValue].width];
445     [o_capture_height_fld setIntValue: [sizes sizeValue].height];
446     [o_capture_width_stp setIntValue: [o_capture_width_fld intValue]];
447     [o_capture_height_stp setIntValue: [o_capture_height_fld intValue]];
448     qtk_currdevice_uid = [[[qtkvideoDevices objectAtIndex:[o_qtk_device_pop indexOfSelectedItem]] uniqueID]
449                           stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
450     [self setMRL:[NSString stringWithFormat:@"qtcapture://%@", qtk_currdevice_uid]];
451 }
452
453 - (void)tabView:(NSTabView *)o_tv didSelectTabViewItem:(NSTabViewItem *)o_tvi
454 {
455     NSString *o_label = [o_tvi label];
456
457     if( [o_label isEqualToString: _NS("File")] )
458     {
459         [self openFilePathChanged: nil];
460     }
461     else if( [o_label isEqualToString: _NS("Disc")] )
462     {
463         [self scanOpticalMedia: nil];
464     }
465     else if( [o_label isEqualToString: _NS("Network")] )
466     {
467         [self openNetInfoChanged: nil];
468     }
469     else if( [o_label isEqualToString: _NS("Capture")] )
470     {
471         [self openCaptureModeChanged: nil];
472     }
473 }
474
475 - (IBAction)expandMRLfieldAction:(id)sender
476 {
477     NSRect o_win_rect, o_view_rect;
478     o_win_rect = [o_panel frame];
479     o_view_rect = [o_mrl_view frame];
480
481     if( [o_mrl_btn state] == NSOffState )
482     {
483         /* we need to collaps, restore the panel size */
484         o_win_rect.size.height = o_win_rect.size.height - o_view_rect.size.height;
485         o_win_rect.origin.y = ( o_win_rect.origin.y + o_view_rect.size.height ) - o_view_rect.size.height;
486
487         /* remove the MRL view */
488         [o_mrl_view removeFromSuperview];
489     } else {
490         /* we need to expand */
491         [o_mrl_view setFrame: NSMakeRect( 0,
492                                          [o_mrl_btn frame].origin.y,
493                                          o_view_rect.size.width,
494                                          o_view_rect.size.height )];
495         [o_mrl_view setNeedsDisplay: NO];
496         [o_mrl_view setAutoresizesSubviews: YES];
497
498         /* enlarge panel size for MRL view */
499         o_win_rect.size.height = o_win_rect.size.height + o_view_rect.size.height;
500     }
501
502     [o_panel setFrame: o_win_rect display:YES animate: YES];
503     [o_panel displayIfNeeded];
504     if( [o_mrl_btn state] == NSOnState )
505         [[o_panel contentView] addSubview: o_mrl_view];
506 }
507
508 - (IBAction)inputSlaveAction:(id)sender
509 {
510     if( sender == o_file_slave_ckbox )
511         [o_file_slave_select_btn setEnabled: [o_file_slave_ckbox state]];
512     else
513     {
514         NSOpenPanel *o_open_panel;
515         o_open_panel = [NSOpenPanel openPanel];
516         [o_open_panel setCanChooseFiles: YES];
517         [o_open_panel setCanChooseDirectories: NO];
518         if( [o_open_panel runModal] == NSOKButton )
519         {
520             if( o_file_slave_path )
521                 [o_file_slave_path release];
522             o_file_slave_path = [[[o_open_panel URLs] objectAtIndex: 0] path];
523             [o_file_slave_path retain];
524         }
525     }
526     if( o_file_slave_path && [o_file_slave_ckbox state] == NSOnState)
527     {
528         [o_file_slave_filename_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:o_file_slave_path]];
529         [o_file_slave_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: o_file_slave_path]];
530     }
531     else
532     {
533         [o_file_slave_filename_lbl setStringValue: @""];
534         [o_file_slave_icon_well setImage: NULL];
535     }
536 }
537
538 - (void)openFileGeneric
539 {
540     [self openFilePathChanged: nil];
541     [self openTarget: 0];
542 }
543
544 - (void)openDisc
545 {
546     [o_specialMediaFolders removeAllObjects];
547     [o_opticalDevices removeAllObjects];
548     [self scanOpticalMedia: nil];
549     [self openTarget: 1];
550 }
551
552 - (void)openNet
553 {
554     [self openNetInfoChanged: nil];
555     [self openTarget: 2];
556 }
557
558 - (void)openCapture
559 {
560     [self openCaptureModeChanged: nil];
561     [self openTarget: 3];
562 }
563
564 - (void)openFilePathChanged:(NSNotification *)o_notification
565 {
566     if ( o_file_path && [o_file_path length] > 0 )
567     {
568         bool b_stream = [o_file_stream state];
569         BOOL b_dir = NO;
570
571         [[NSFileManager defaultManager] fileExistsAtPath:o_file_path isDirectory:&b_dir];
572
573         char *psz_uri = make_URI([o_file_path UTF8String], "file");
574         if( !psz_uri ) return;
575
576         NSMutableString *o_mrl_string = [NSMutableString stringWithUTF8String: psz_uri ];
577         NSRange offile = [o_mrl_string rangeOfString:@"file"];
578         free( psz_uri );
579
580         if( b_dir )
581             [o_mrl_string replaceCharactersInRange:offile withString: @"directory"];
582         else if( b_stream )
583             [o_mrl_string replaceCharactersInRange:offile withString: @"stream"];
584
585         [o_file_name setStringValue: [[NSFileManager defaultManager] displayNameAtPath:o_file_path]];
586         [o_file_name_stub setHidden: YES];
587         [o_file_stream setHidden: NO];
588         [o_file_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: o_file_path]];
589         [o_file_icon_well setHidden: NO];
590         [self setMRL: o_mrl_string];
591     }
592     else
593     {
594         [o_file_name setStringValue: @""];
595         [o_file_name_stub setHidden: NO];
596         [o_file_stream setHidden: YES];
597         [o_file_icon_well setImage: [NSImage imageNamed:@"generic"]];
598         [self setMRL: @""];
599     }
600 }
601
602 - (IBAction)openFileBrowse:(id)sender
603 {
604     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
605  
606     [o_open_panel setAllowsMultipleSelection: NO];
607     [o_open_panel setCanChooseDirectories: YES];
608     [o_open_panel setTitle: _NS("Open File")];
609     [o_open_panel setPrompt: _NS("Open")];
610
611     [o_open_panel beginSheetForDirectory:nil
612         file:nil
613         types:nil
614         modalForWindow:[sender window]
615         modalDelegate: self
616         didEndSelector: @selector(pathChosenInPanel:
617                         withReturn:
618                         contextInfo:)
619         contextInfo: nil];
620 }
621
622 - (void)pathChosenInPanel: (NSOpenPanel *) sheet withReturn:(int)returnCode contextInfo:(void  *)contextInfo
623 {
624     if (returnCode == NSFileHandlingPanelOKButton)
625     {
626         if( o_file_path )
627             [o_file_path release];
628         o_file_path = [[[sheet URLs] objectAtIndex: 0] path];
629         [o_file_path retain];
630         [self openFilePathChanged: nil];
631     }
632 }
633
634 - (IBAction)openFileStreamChanged:(id)sender
635 {
636     [self openFilePathChanged: nil];
637 }
638
639 - (void)showOpticalMediaView: theView
640 {
641     NSRect o_view_rect;
642     o_view_rect = [theView frame];
643     if( o_currentOpticalMediaView )
644     {
645         [o_currentOpticalMediaView removeFromSuperviewWithoutNeedingDisplay];
646         [o_currentOpticalMediaView release];
647     }
648     [theView setFrame: NSMakeRect( 233, 0, o_view_rect.size.width, o_view_rect.size.height)];
649     [theView setNeedsDisplay: YES];
650     [theView setAutoresizesSubviews: YES];
651     [[[o_tabview tabViewItemAtIndex: [o_tabview indexOfTabViewItemWithIdentifier:@"optical"]] view] addSubview: theView];
652     [theView displayIfNeeded];
653     o_currentOpticalMediaView = theView;
654     [o_currentOpticalMediaView retain];
655 }
656
657 - (NSString *) getBSDNodeFromMountPath:(NSString *)mountPath
658 {
659     OSStatus err;
660     FSRef ref;
661     FSVolumeRefNum actualVolume;
662     err = FSPathMakeRef ( (const UInt8 *) [mountPath fileSystemRepresentation], &ref, NULL );
663
664     // get a FSVolumeRefNum from mountPath
665     if ( noErr == err ) {
666         FSCatalogInfo   catalogInfo;
667         err = FSGetCatalogInfo ( &ref,
668                                 kFSCatInfoVolume,
669                                 &catalogInfo,
670                                 NULL,
671                                 NULL,
672                                 NULL
673                                 );
674         if ( noErr == err ) {
675             actualVolume = catalogInfo.volume;
676         }
677     }
678
679     GetVolParmsInfoBuffer volumeParms;
680     err = FSGetVolumeParms( actualVolume, &volumeParms, sizeof(volumeParms) );
681     if ( noErr != err ) {
682         msg_Err( p_intf, "error retrieving volume params, bailing out" );
683         return @"";
684     }
685
686     NSString *bsdName = [NSString stringWithUTF8String:(char *)volumeParms.vMDeviceID];
687     return [NSString stringWithFormat:@"/dev/r%@", bsdName];
688 }
689
690 - (char *)getVolumeTypeFromMountPath:(NSString *)mountPath
691 {
692     OSStatus err;
693     FSRef ref;
694     FSVolumeRefNum actualVolume;
695     err = FSPathMakeRef ( (const UInt8 *) [mountPath fileSystemRepresentation], &ref, NULL );
696
697     // get a FSVolumeRefNum from mountPath
698     if ( noErr == err ) {
699         FSCatalogInfo   catalogInfo;
700         err = FSGetCatalogInfo ( &ref,
701                                 kFSCatInfoVolume,
702                                 &catalogInfo,
703                                 NULL,
704                                 NULL,
705                                 NULL
706                                 );
707         if ( noErr == err ) {
708             actualVolume = catalogInfo.volume;
709         }
710     }
711
712     GetVolParmsInfoBuffer volumeParms;
713     err = FSGetVolumeParms( actualVolume, &volumeParms, sizeof(volumeParms) );
714
715     CFMutableDictionaryRef      matchingDict;
716     io_service_t                        service;
717
718     matchingDict = IOBSDNameMatching(kIOMasterPortDefault, 0, volumeParms.vMDeviceID);
719     service = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
720
721     char *returnValue;
722     if (IO_OBJECT_NULL != service) {
723         if (IOObjectConformsTo(service, kIOCDMediaClass)) {
724             returnValue = kVLCMediaAudioCD;
725         }
726         else if(IOObjectConformsTo(service, kIODVDMediaClass))
727             returnValue = kVLCMediaDVD;
728         else if(IOObjectConformsTo(service, kIOBDMediaClass))
729             returnValue = kVLCMediaBD;
730         else
731         {
732             if ([mountPath rangeOfString:@"VIDEO_TS"].location != NSNotFound)
733                 returnValue = kVLCMediaVideoTSFolder;
734             else if ([mountPath rangeOfString:@"BDMV"].location != NSNotFound)
735                 returnValue = kVLCMediaBDMVFolder;
736             else
737             {
738                 NSArray * topLevelItems;
739                 topLevelItems = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath: mountPath error: NULL];
740                 for (int i = 0; i < [topLevelItems count]; i++) {
741                     if([[topLevelItems objectAtIndex:i] rangeOfString:@"SVCD"].location != NSNotFound) {
742                         returnValue = kVLCMediaSVCD;
743                         break;
744                     }
745                     if([[topLevelItems objectAtIndex:i] rangeOfString:@"VCD"].location != NSNotFound) {
746                         returnValue = kVLCMediaVCD;
747                         break;
748                     }
749                 }
750                 if(!returnValue)
751                     returnValue = kVLCMediaUnknown;
752             }
753         }
754
755         IOObjectRelease(service);
756     }
757     return returnValue;
758 }
759
760 - (void)showOpticalAtIndex: (NSNumber *)n_index
761 {
762     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
763
764     unsigned int index = [n_index intValue];
765     char *diskType = [self getVolumeTypeFromMountPath:[o_opticalDevices objectAtIndex: index]];
766
767     if (diskType == kVLCMediaDVD || diskType == kVLCMediaVideoTSFolder)
768     {
769         [o_disc_dvd_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:[o_opticalDevices objectAtIndex: index]]];
770         [o_disc_dvdwomenus_lbl setStringValue: [o_disc_dvd_lbl stringValue]];
771         [o_disc_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: [o_opticalDevices objectAtIndex: index]]];
772         NSString *pathToOpen;
773         if (diskType == kVLCMediaVideoTSFolder)
774             pathToOpen = [o_opticalDevices objectAtIndex: index];
775         else
776             pathToOpen = [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: index]];
777         if (!b_nodvdmenus) {
778             [self setMRL: [NSString stringWithFormat: @"dvdnav://%@", pathToOpen]];
779             [self showOpticalMediaView: o_disc_dvd_view];
780         } else {
781             [self setMRL: [NSString stringWithFormat: @"dvdread://%@@%i:%i-", pathToOpen, [o_disc_dvdwomenus_title intValue], [o_disc_dvdwomenus_chapter intValue]]];
782             [self showOpticalMediaView: o_disc_dvdwomenus_view];
783         }
784     }
785     else if (diskType == kVLCMediaAudioCD)
786     {
787         [o_disc_audiocd_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:[o_opticalDevices objectAtIndex: index]]];
788         [o_disc_audiocd_trackcount_lbl setStringValue: [NSString stringWithFormat:_NS("%i tracks"), [[[NSFileManager defaultManager] subpathsOfDirectoryAtPath: [o_opticalDevices objectAtIndex: index] error:NULL] count] - 1]]; // minus .TOC.plist
789         [self showOpticalMediaView: o_disc_audiocd_view];
790         [o_disc_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: [o_opticalDevices objectAtIndex: index]]];
791         [self setMRL: [NSString stringWithFormat: @"cdda://%@", [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: index]]]];
792     }
793     else if (diskType == kVLCMediaVCD || diskType == kVLCMediaSVCD)
794     {
795         [o_disc_vcd_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:[o_opticalDevices objectAtIndex: index]]];
796         [self showOpticalMediaView: o_disc_vcd_view];
797         [o_disc_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: [o_opticalDevices objectAtIndex: index]]];
798         [self setMRL: [NSString stringWithFormat: @"vcd://%@@%i:%i", [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: index]], [o_disc_vcd_title intValue], [o_disc_vcd_chapter intValue]]];
799     }
800     else if (diskType == kVLCMediaBD || diskType == kVLCMediaBDMVFolder)
801     {
802         [o_disc_bd_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:[o_opticalDevices objectAtIndex: index]]];
803         [self showOpticalMediaView: o_disc_bd_view];
804         [o_disc_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: [o_opticalDevices objectAtIndex: index]]];
805         if (diskType == kVLCMediaBD)
806             [self setMRL: [NSString stringWithFormat: @"bluray://%@", [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: index]]]];
807         else
808             [self setMRL: [NSString stringWithFormat: @"bluray://%@", [o_opticalDevices objectAtIndex: index]]];
809     }
810     else
811     {
812         msg_Warn( VLCIntf, "unknown disk type, no idea what to display" );
813         [o_disc_icon_well setImage: [NSImage imageNamed:@"NSApplicationIcon"]];
814         [self showOpticalMediaView: o_disc_nodisc_view];
815     }
816
817     [[o_disc_icon_well image] setSize: NSMakeSize(128,128)];
818     [o_pool release];
819 }
820
821 - (void)scanOpticalMedia:(NSNotification *)o_notification
822 {
823     [o_opticalDevices removeAllObjects];
824     [o_disc_selector_pop removeAllItems];
825     [o_opticalDevices addObjectsFromArray: [[NSWorkspace sharedWorkspace] mountedRemovableMedia]];
826     if ([o_specialMediaFolders count] > 0)
827         [o_opticalDevices addObjectsFromArray: o_specialMediaFolders];
828     if ([o_opticalDevices count] > 0) {
829         for (int i = 0; i < [o_opticalDevices count] ; i++)
830             [o_disc_selector_pop addItemWithTitle: [[NSFileManager defaultManager] displayNameAtPath:[o_opticalDevices objectAtIndex: i]]];
831
832         if ([o_disc_selector_pop numberOfItems] <= 1)
833             [o_disc_selector_pop setHidden: YES];
834         else
835             [o_disc_selector_pop setHidden: NO];
836
837         [NSThread detachNewThreadSelector:@selector(showOpticalAtIndex:) toTarget:self withObject:[NSNumber numberWithInt:[o_disc_selector_pop indexOfSelectedItem]]];
838     }
839     else
840     {
841         msg_Dbg( VLCIntf, "no optical media found" );
842         [o_disc_selector_pop setHidden: YES];
843         [o_disc_icon_well setImage: [NSImage imageNamed: @"NSApplicationIcon"]];
844         [self showOpticalMediaView: o_disc_nodisc_view];
845     }
846 }
847
848 - (IBAction)discSelectorChanged:(id)sender
849 {
850     [NSThread detachNewThreadSelector:@selector(showOpticalAtIndex:) toTarget:self withObject:[NSNumber numberWithInt:[o_disc_selector_pop indexOfSelectedItem]]];
851 }
852
853 - (IBAction)openSpecialMediaFolder:(id)sender
854 {
855     /* this is currently for VIDEO_TS and BDMV folders */
856     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
857
858     [o_open_panel setAllowsMultipleSelection: NO];
859     [o_open_panel setCanChooseFiles: NO];
860     [o_open_panel setCanChooseDirectories: YES];
861     [o_open_panel setTitle: [sender title]];
862     [o_open_panel setPrompt: _NS("Open")];
863
864     if ([o_open_panel runModal] == NSOKButton)
865     {
866         NSString *o_path = [[[o_open_panel URLs] objectAtIndex: 0] path];
867         if ([o_path length] > 0 )
868         {
869             if ([o_path rangeOfString:@"VIDEO_TS"].location != NSNotFound || [o_path rangeOfString:@"BDMV"].location != NSNotFound)
870             {
871                 [o_specialMediaFolders addObject: o_path];
872                 [self scanOpticalMedia: nil];
873             }
874             else
875                 msg_Dbg( VLCIntf, "chosen directory is no suitable special media folder" );
876         }
877     }
878 }
879
880 - (IBAction)dvdreadOptionChanged:(id)sender
881 {
882     if (sender == o_disc_dvdwomenus_enablemenus_btn) {
883         b_nodvdmenus = NO;
884         [self setMRL: [NSString stringWithFormat: @"dvdnav://%@", [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: [o_disc_selector_pop indexOfSelectedItem]]]]];
885         [self showOpticalMediaView: o_disc_dvd_view];
886         return;
887     }
888     if (sender == o_disc_dvd_disablemenus_btn) {
889         b_nodvdmenus = YES;
890         [self showOpticalMediaView: o_disc_dvdwomenus_view];
891     }
892
893     if (sender == o_disc_dvdwomenus_title)
894         [o_disc_dvdwomenus_title_stp setIntValue: [o_disc_dvdwomenus_title intValue]];
895     if (sender == o_disc_dvdwomenus_title_stp)
896         [o_disc_dvdwomenus_title setIntValue: [o_disc_dvdwomenus_title_stp intValue]];
897     if (sender == o_disc_dvdwomenus_chapter)
898         [o_disc_dvdwomenus_chapter_stp setIntValue: [o_disc_dvdwomenus_chapter intValue]];
899     if (sender == o_disc_dvdwomenus_chapter_stp)
900         [o_disc_dvdwomenus_chapter setIntValue: [o_disc_dvdwomenus_chapter_stp intValue]];
901
902     [self setMRL: [NSString stringWithFormat: @"dvdread://%@@%i:%i-", [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: [o_disc_selector_pop indexOfSelectedItem]]], [o_disc_dvdwomenus_title intValue], [o_disc_dvdwomenus_chapter intValue]]];
903 }
904
905 - (IBAction)vcdOptionChanged:(id)sender
906 {
907     if (sender == o_disc_vcd_title)
908         [o_disc_vcd_title_stp setIntValue: [o_disc_vcd_title intValue]];
909     if (sender == o_disc_vcd_title_stp)
910         [o_disc_vcd_title setIntValue: [o_disc_vcd_title_stp intValue]];
911     if (sender == o_disc_vcd_chapter)
912         [o_disc_vcd_chapter_stp setIntValue: [o_disc_vcd_chapter intValue]];
913     if (sender == o_disc_vcd_chapter_stp)
914         [o_disc_vcd_chapter setIntValue: [o_disc_vcd_chapter_stp intValue]];
915
916     [self setMRL: [NSString stringWithFormat: @"vcd://%@@%i:%i", [self getBSDNodeFromMountPath:[o_opticalDevices objectAtIndex: [o_disc_selector_pop indexOfSelectedItem]]], [o_disc_vcd_title intValue], [o_disc_vcd_chapter intValue]]];
917 }
918
919 - (void)textFieldWasClicked:(NSNotification *)o_notification
920 {
921     if( [o_notification object] == o_net_udp_port )
922         [o_net_mode selectCellAtRow: 0 column: 0];
923     else if( [o_notification object] == o_net_udpm_addr ||
924              [o_notification object] == o_net_udpm_port )
925         [o_net_mode selectCellAtRow: 1 column: 0];
926     else
927         [o_net_mode selectCellAtRow: 2 column: 0];
928
929     [self openNetInfoChanged: nil];
930 }
931
932 - (IBAction)openNetModeChanged:(id)sender
933 {
934     if( sender == o_net_mode )
935     {
936         if( [[sender selectedCell] tag] == 0 )
937             [o_panel makeFirstResponder: o_net_udp_port];
938         else if ( [[sender selectedCell] tag] == 1 )
939             [o_panel makeFirstResponder: o_net_udpm_addr];
940         else
941             msg_Warn( p_intf, "Unknown sender tried to change UDP/RTP mode" );
942     }
943
944     [self openNetInfoChanged: nil];
945 }
946
947 - (IBAction)openNetStepperChanged:(id)sender
948 {
949     int i_tag = [sender tag];
950
951     if( i_tag == 0 )
952     {
953         [o_net_udp_port setIntValue: [o_net_udp_port_stp intValue]];
954         [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
955                                                             object: o_net_udp_port];
956         [o_panel makeFirstResponder: o_net_udp_port];
957     }
958     else if( i_tag == 1 )
959     {
960         [o_net_udpm_port setIntValue: [o_net_udpm_port_stp intValue]];
961         [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
962                                                             object: o_net_udpm_port];
963         [o_panel makeFirstResponder: o_net_udpm_port];
964     }
965
966     [self openNetInfoChanged: nil];
967 }
968
969 - (void)openNetInfoChanged:(NSNotification *)o_notification
970 {
971     NSString *o_mrl_string = [NSString string];
972
973     if( [o_net_udp_panel isVisible] )
974     {
975         NSString *o_mode;
976         o_mode = [[o_net_mode selectedCell] title];
977
978         if( [o_mode isEqualToString: _NS("Unicast")] )
979         {
980             int i_port = [o_net_udp_port intValue];
981
982             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
983                 o_mrl_string = [NSString stringWithString: @"udp://"];
984             else
985                 o_mrl_string = [NSString stringWithString: @"rtp://"];
986
987             if( i_port != config_GetInt( p_intf, "server-port" ) )
988             {
989                 o_mrl_string =
990                     [o_mrl_string stringByAppendingFormat: @"@:%i", i_port];
991             }
992         }
993         else if( [o_mode isEqualToString: _NS("Multicast")] )
994         {
995             NSString *o_addr = [o_net_udpm_addr stringValue];
996             int i_port = [o_net_udpm_port intValue];
997
998             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
999                 o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr];
1000             else
1001                 o_mrl_string = [NSString stringWithFormat: @"rtp://@%@", o_addr];
1002
1003             if( i_port != config_GetInt( p_intf, "server-port" ) )
1004             {
1005                 o_mrl_string =
1006                     [o_mrl_string stringByAppendingFormat: @":%i", i_port];
1007             }
1008         }
1009     }
1010     else
1011     {
1012         o_mrl_string = [o_net_http_url stringValue];
1013     }
1014     [self setMRL: o_mrl_string];
1015 }
1016
1017 - (IBAction)openNetUDPButtonAction:(id)sender
1018 {
1019     if( sender == o_net_openUDP_btn )
1020     {
1021         [NSApp beginSheet: o_net_udp_panel
1022            modalForWindow: o_panel
1023             modalDelegate: self
1024            didEndSelector: NULL
1025               contextInfo: nil];
1026         [self openNetInfoChanged: nil];
1027     }
1028     else if( sender == o_net_udp_cancel_btn )
1029     {
1030         [o_net_udp_panel orderOut: sender];
1031         [NSApp endSheet: o_net_udp_panel];
1032     }
1033     else if( sender == o_net_udp_ok_btn )
1034     {
1035         NSString *o_mrl_string = [NSString string];
1036         if( [[[o_net_mode selectedCell] title] isEqualToString: _NS("Unicast")] )
1037         {
1038             int i_port = [o_net_udp_port intValue];
1039             
1040             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
1041                 o_mrl_string = [NSString stringWithString: @"udp://"];
1042             else
1043                 o_mrl_string = [NSString stringWithString: @"rtp://"];
1044
1045             if( i_port != config_GetInt( p_intf, "server-port" ) )
1046             {
1047                 o_mrl_string =
1048                 [o_mrl_string stringByAppendingFormat: @"@:%i", i_port];
1049             }
1050         }
1051         else if( [[[o_net_mode selectedCell] title] isEqualToString: _NS("Multicast")] )
1052         {
1053             NSString *o_addr = [o_net_udpm_addr stringValue];
1054             int i_port = [o_net_udpm_port intValue];
1055             
1056             if( [[o_net_udp_protocol_mat selectedCell] tag] == 0 )
1057                 o_mrl_string = [NSString stringWithFormat: @"udp://@%@", o_addr];
1058             else
1059                 o_mrl_string = [NSString stringWithFormat: @"rtp://@%@", o_addr];
1060
1061             if( i_port != config_GetInt( p_intf, "server-port" ) )
1062             {
1063                 o_mrl_string =
1064                 [o_mrl_string stringByAppendingFormat: @":%i", i_port];
1065             }
1066         }
1067         [self setMRL: o_mrl_string];
1068         [o_net_http_url setStringValue: o_mrl_string];
1069         [o_net_udp_panel orderOut: sender];
1070         [NSApp endSheet: o_net_udp_panel];
1071     }
1072 }
1073     
1074 - (void)openFile
1075 {
1076     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
1077     int i;
1078     b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
1079  
1080     [o_open_panel setAllowsMultipleSelection: YES];
1081     [o_open_panel setCanChooseDirectories: YES];
1082     [o_open_panel setTitle: _NS("Open File")];
1083     [o_open_panel setPrompt: _NS("Open")];
1084  
1085     if( [o_open_panel runModal] == NSOKButton )
1086     {
1087         NSArray *o_array = [NSArray array];
1088         NSArray *o_values = [[o_open_panel URLs]
1089                 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
1090
1091         for( i = 0; i < (int)[o_values count]; i++)
1092         {
1093             NSDictionary *o_dic;
1094             char *psz_uri = make_URI([[[o_values objectAtIndex:i] path] UTF8String], "file");
1095             if( !psz_uri )
1096                 continue;
1097
1098             o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
1099
1100             free( psz_uri );
1101
1102             o_array = [o_array arrayByAddingObject: o_dic];
1103         }
1104         if( b_autoplay )
1105             [o_playlist appendArray: o_array atPos: -1 enqueue:NO];
1106         else
1107             [o_playlist appendArray: o_array atPos: -1 enqueue:YES];
1108     }
1109 }
1110
1111 - (void)showCaptureView: theView
1112 {
1113     NSRect o_view_rect;
1114     o_view_rect = [theView frame];
1115     if( o_currentCaptureView )
1116     {
1117         [o_currentCaptureView removeFromSuperviewWithoutNeedingDisplay];
1118         [o_currentCaptureView release];
1119     }
1120     [theView setFrame: NSMakeRect( 0, -10, o_view_rect.size.width, o_view_rect.size.height)];
1121     [theView setNeedsDisplay: YES];
1122     [theView setAutoresizesSubviews: YES];
1123     [[[o_tabview tabViewItemAtIndex: 3] view] addSubview: theView];
1124     [theView displayIfNeeded];
1125     o_currentCaptureView = theView;
1126     [o_currentCaptureView retain];
1127 }
1128
1129 - (IBAction)openCaptureModeChanged:(id)sender
1130 {
1131     if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: @"EyeTV"] )
1132     {
1133         if( [[[VLCMain sharedInstance] eyeTVController] isEyeTVrunning] == YES )
1134         {
1135             if( [[[VLCMain sharedInstance] eyeTVController] isDeviceConnected] == YES )
1136             {
1137                 [self showCaptureView: o_eyetv_running_view];
1138                 [self setupChannelInfo];
1139             }
1140             else
1141             {
1142                 setEyeTVUnconnected;
1143             }
1144         }
1145         else
1146             [self showCaptureView: o_eyetv_notLaunched_view];
1147         [self setMRL: @""];
1148     } 
1149     else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Screen")] )
1150     {
1151         [self showCaptureView: o_screen_view];
1152         [self setMRL: @"screen://"];
1153         [o_screen_height_fld setIntValue: config_GetInt( p_intf, "screen-height" )];
1154         [o_screen_width_fld setIntValue: config_GetInt( p_intf, "screen-width" )];
1155         [o_screen_fps_fld setFloatValue: config_GetFloat( p_intf, "screen-fps" )];
1156         [o_screen_left_fld setIntValue: config_GetInt( p_intf, "screen-left" )];
1157         [o_screen_top_fld setIntValue: config_GetInt( p_intf, "screen-top" )];
1158         [o_screen_follow_mouse_ckb setIntValue: config_GetInt( p_intf, "screen-follow-mouse" )];
1159     }
1160     else if( [[[o_capture_mode_pop selectedItem] title] isEqualToString: _NS("Capture Device")] )
1161     {
1162         [self showCaptureView: o_qtk_view];
1163         if ([o_capture_width_fld intValue] <= 0)
1164             [self qtkChanged:nil];
1165
1166         if(!qtk_currdevice_uid)
1167             [self setMRL: @""];
1168         else
1169             [self setMRL:[NSString stringWithFormat:@"qtcapture://%@", qtk_currdevice_uid]];
1170     }
1171 }
1172
1173 - (IBAction)screenStepperChanged:(id)sender
1174 {
1175     [o_screen_fps_fld setFloatValue: [o_screen_fps_stp floatValue]];
1176     [o_panel makeFirstResponder: o_screen_fps_fld];
1177     [self setMRL: @"screen://"];
1178 }
1179
1180 - (void)screenFPSfieldChanged:(NSNotification *)o_notification
1181 {
1182     [o_screen_fps_stp setFloatValue: [o_screen_fps_fld floatValue]];
1183     if( [[o_screen_fps_fld stringValue] isEqualToString: @""] )
1184         [o_screen_fps_fld setFloatValue: 1.0];
1185     [self setMRL: @"screen://"];
1186 }
1187
1188 - (IBAction)eyetvSwitchChannel:(id)sender
1189 {
1190     if( sender == o_eyetv_nextProgram_btn )
1191     {
1192         int chanNum = [[[VLCMain sharedInstance] eyeTVController] switchChannelUp: YES];
1193         [o_eyetv_channels_pop selectItemWithTag:chanNum];
1194         [self setMRL: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1195     }
1196     else if( sender == o_eyetv_previousProgram_btn )
1197     {
1198         int chanNum = [[[VLCMain sharedInstance] eyeTVController] switchChannelUp: NO];
1199         [o_eyetv_channels_pop selectItemWithTag:chanNum];
1200         [self setMRL: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1201     }
1202     else if( sender == o_eyetv_channels_pop )
1203     {
1204         int chanNum = [[sender selectedItem] tag];
1205         [[[VLCMain sharedInstance] eyeTVController] selectChannel:chanNum];
1206         [self setMRL: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
1207     }
1208     else
1209         msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" );
1210 }
1211
1212 - (IBAction)eyetvLaunch:(id)sender
1213 {
1214     [[[VLCMain sharedInstance] eyeTVController] launchEyeTV];
1215 }
1216
1217 - (IBAction)eyetvGetPlugin:(id)sender
1218 {
1219     [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: @"http://www.videolan.org/vlc/eyetv"]];
1220 }
1221
1222 - (void)eyetvChanged:(NSNotification *)o_notification
1223 {
1224     if( [[o_notification name] isEqualToString: @"DeviceAdded"] )
1225     {
1226         msg_Dbg( VLCIntf, "eyetv device was added" );
1227         [self showCaptureView: o_eyetv_running_view];
1228         [self setupChannelInfo];
1229     }
1230     else if( [[o_notification name] isEqualToString: @"DeviceRemoved"] )
1231     {
1232         /* leave the channel selection like that,
1233          * switch to our "no device" tab */
1234         msg_Dbg( VLCIntf, "eyetv device was removed" );
1235         setEyeTVUnconnected;
1236     }
1237     else if( [[o_notification name] isEqualToString: @"PluginQuit"] )
1238     {
1239         /* switch to the "launch eyetv" tab */
1240         msg_Dbg( VLCIntf, "eyetv was terminated" );
1241         [self showCaptureView: o_eyetv_notLaunched_view];
1242     }
1243     else if( [[o_notification name] isEqualToString: @"PluginInit"] )
1244     {
1245         /* we got no device yet */
1246         msg_Dbg( VLCIntf, "eyetv was launched, no device yet" );
1247         setEyeTVUnconnected;
1248     }
1249     else
1250         msg_Warn( VLCIntf, "unknown external notify '%s' received", [[o_notification name] UTF8String] );
1251 }    
1252
1253 /* little helper method, since this code needs to be run by multiple objects */
1254 - (void)setupChannelInfo
1255 {
1256     /* set up channel selection */
1257     [o_eyetv_channels_pop removeAllItems];
1258     [o_eyetv_chn_bgbar setHidden: NO];
1259     [o_eyetv_chn_bgbar animate: self];
1260     [o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
1261     [o_eyetv_chn_status_txt setHidden: NO];
1262  
1263     /* retrieve info */
1264     NSEnumerator *channels = [[[VLCMain sharedInstance] eyeTVController] allChannels];
1265     int x = -2;
1266     [[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("Composite input")
1267                                                action: nil
1268                                         keyEquivalent: @""] setTag:x++];
1269     [[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("S-Video input")
1270                                                action: nil
1271                                         keyEquivalent: @""] setTag:x++];
1272     if( channels ) 
1273     {
1274         NSString *channel;
1275         [[o_eyetv_channels_pop menu] addItem: [NSMenuItem separatorItem]];
1276         while( channel = [channels nextObject] )
1277         {
1278             /* we have to add items this way, because we accept duplicates
1279              * additionally, we save a bit of time */
1280             [[[o_eyetv_channels_pop menu] addItemWithTitle: channel
1281                                                    action: nil
1282                                             keyEquivalent: @""] setTag:++x];
1283         }
1284         /* make Tuner the default */
1285         [o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] eyeTVController] currentChannel]];
1286     }
1287  
1288     /* clean up GUI */
1289     [o_eyetv_chn_bgbar setHidden: YES];
1290     [o_eyetv_chn_status_txt setHidden: YES];
1291 }
1292
1293 - (IBAction)subsChanged:(id)sender
1294 {
1295     if ([o_file_sub_ckbox state] == NSOnState)
1296     {
1297         [o_file_sub_btn_settings setEnabled:YES];
1298         if ([[o_file_sub_path stringValue] length] > 0) {
1299             [o_file_subtitles_filename_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:[o_file_sub_path stringValue]]];
1300             [o_file_subtitles_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: [o_file_sub_path stringValue]]];
1301         }
1302     }
1303     else
1304     {
1305         [o_file_sub_btn_settings setEnabled:NO];
1306         [o_file_subtitles_filename_lbl setStringValue: @""];
1307         [o_file_subtitles_icon_well setImage: NULL];
1308     }
1309 }
1310
1311 - (IBAction)subSettings:(id)sender
1312 {
1313     [NSApp beginSheet: o_file_sub_sheet
1314         modalForWindow: [sender window]
1315         modalDelegate: self
1316         didEndSelector: NULL
1317         contextInfo: nil];
1318 }
1319
1320 - (IBAction)subCloseSheet:(id)sender
1321 {
1322     [self subsChanged: nil];
1323     [o_file_sub_sheet orderOut:sender];
1324     [NSApp endSheet: o_file_sub_sheet];
1325 }
1326     
1327 - (IBAction)subFileBrowse:(id)sender
1328 {
1329     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
1330  
1331     [o_open_panel setAllowsMultipleSelection: NO];
1332     [o_open_panel setTitle: _NS("Open File")];
1333     [o_open_panel setPrompt: _NS("Open")];
1334
1335     if( [o_open_panel runModal] == NSOKButton )
1336     {
1337         NSString *o_filename = [[[o_open_panel URLs] objectAtIndex: 0] path];
1338         [o_file_sub_path setStringValue: o_filename];
1339         [o_file_subtitles_filename_lbl setStringValue: [[NSFileManager defaultManager] displayNameAtPath:o_filename]];
1340         [o_file_subtitles_icon_well setImage: [[NSWorkspace sharedWorkspace] iconForFile: o_filename]];
1341     }
1342 }
1343
1344 - (IBAction)subOverride:(id)sender
1345 {
1346     BOOL b_state = [o_file_sub_override state];
1347     [o_file_sub_delay setEnabled: b_state];
1348     [o_file_sub_delay_stp setEnabled: b_state];
1349     [o_file_sub_fps setEnabled: b_state];
1350     [o_file_sub_fps_stp setEnabled: b_state];
1351 }
1352
1353 - (IBAction)subDelayStepperChanged:(id)sender
1354 {
1355     [o_file_sub_delay setIntValue: [o_file_sub_delay_stp intValue]];
1356 }
1357
1358 - (IBAction)subFpsStepperChanged:(id)sender;
1359 {
1360     [o_file_sub_fps setFloatValue: [o_file_sub_fps_stp floatValue]];
1361 }
1362
1363 - (IBAction)panelCancel:(id)sender
1364 {
1365     [NSApp stopModalWithCode: 0];
1366 }
1367
1368 - (IBAction)panelOk:(id)sender
1369 {
1370     if( [[self MRL] length] )
1371         [NSApp stopModalWithCode: 1];
1372     else
1373         NSBeep();
1374 }
1375
1376 - (NSArray *)qtkvideoDevices
1377 {
1378     if (!qtkvideoDevices)
1379         [self qtkrefreshDevices];
1380     return qtkvideoDevices;
1381 }
1382
1383 - (void)qtkrefreshDevices
1384 {
1385     [qtkvideoDevices release];
1386     qtkvideoDevices = [[[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo] arrayByAddingObjectsFromArray:[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeMuxed]] retain];
1387 }
1388
1389 @end
1390
1391 @implementation VLCOpenTextField
1392
1393 - (void)mouseDown:(NSEvent *)theEvent
1394 {
1395     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCOpenTextFieldWasClicked"
1396                                                         object: self];
1397     [super mouseDown: theEvent];
1398 }
1399
1400 @end