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