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