macosx: move re-useable code from VLCControls to a custom class
[vlc.git] / modules / gui / macosx / MainMenu.m
1 /*****************************************************************************
2  * MainMenu.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2011 Felix Paul Kühne
5  * $Id$
6  *
7  * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #import "MainMenu.h"
25 #import <vlc_common.h>
26 #import <vlc_playlist.h>
27
28 #import "intf.h"
29 #import "open.h"
30 #import "wizard.h"
31 #import "about.h"
32 #import "AudioEffects.h"
33 #import "TrackSynchronization.h"
34 #import "VideoEffects.h"
35 #import "bookmarks.h"
36 #import "simple_prefs.h"
37 #import "coredialogs.h"
38 #import "controls.h"
39 #import "playlistinfo.h"
40 #import "vout.h"
41 #import "CoreInteraction.h"
42
43 @implementation VLCMainMenu
44 static VLCMainMenu *_o_sharedInstance = nil;
45
46 + (VLCMainMenu *)sharedInstance
47 {
48     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
49 }
50
51 #pragma mark -
52 #pragma mark Initialization
53
54 - (id)init
55 {
56     if( _o_sharedInstance)
57     {
58         [self dealloc];
59         return _o_sharedInstance;
60     }
61     else
62     {
63         _o_sharedInstance = [super init];
64     }
65
66     return _o_sharedInstance;
67 }
68
69 - (void)dealloc
70 {
71     [[NSNotificationCenter defaultCenter] removeObserver: self];
72     
73     if (b_nib_about_loaded)
74         [o_about release];
75
76     if (b_nib_videoeffects_loaded)
77         [o_videoeffects release];
78
79     if (b_nib_audioeffects_loaded)
80         [o_audioeffects release];
81
82     if (b_nib_tracksynchro_loaded)
83         [o_trackSynchronization release];
84
85     [super dealloc];
86 }
87
88 - (void)awakeFromNib
89 {
90     [[NSNotificationCenter defaultCenter] addObserver: self 
91                                              selector: @selector(applicationWillFinishLaunching:)
92                                                  name: NSApplicationWillFinishLaunchingNotification
93                                                object: nil];
94 }
95
96 - (void)applicationWillFinishLaunching:(NSNotification *)o_notification
97 {
98     p_intf = VLCIntf;
99
100     NSString* o_key;
101     playlist_t *p_playlist;
102     vlc_value_t val;
103     id o_vlcmain = [VLCMain sharedInstance];
104
105     /* Check if we already did this once. Opening the other nibs calls it too,
106      because VLCMain is the owner */
107     if( b_mainMenu_setup ) return;
108
109     [self initStrings];
110
111     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-quit" )];
112     [o_mi_quit setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
113     [o_mi_quit setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
114     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-play-pause" )];
115     [o_mi_play setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
116     [o_mi_play setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
117     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-stop" )];
118     [o_mi_stop setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
119     [o_mi_stop setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
120     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-faster" )];
121     [o_mi_faster setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
122     [o_mi_faster setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
123     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-slower" )];
124     [o_mi_slower setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
125     [o_mi_slower setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
126     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-rate-normal" )];
127     [o_mi_normalSpeed setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
128     [o_mi_normalSpeed setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
129     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-prev" )];
130     [o_mi_previous setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
131     [o_mi_previous setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
132     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-next" )];
133     [o_mi_next setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
134     [o_mi_next setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
135     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-jump+short" )];
136     [o_mi_fwd setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
137     [o_mi_fwd setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
138     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-jump-short" )];
139     [o_mi_bwd setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
140     [o_mi_bwd setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
141     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-vol-up" )];
142     [o_mi_vol_up setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
143     [o_mi_vol_up setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
144     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-vol-down" )];
145     [o_mi_vol_down setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
146     [o_mi_vol_down setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
147     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-vol-mute" )];
148     [o_mi_mute setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
149     [o_mi_mute setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
150     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-toggle-fullscreen" )];
151     [o_mi_fullscreen setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
152     [o_mi_fullscreen setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
153     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-snapshot" )];
154     [o_mi_snapshot setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
155     [o_mi_snapshot setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
156     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-random" )];
157     [o_mi_random setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
158     [o_mi_random setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
159     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-zoom-half" )];
160     [o_mi_half_window setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
161     [o_mi_half_window setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
162     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-zoom-original" )];
163     [o_mi_normal_window setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
164     [o_mi_normal_window setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
165     o_key = [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, "key-zoom-double" )];
166     [o_mi_double_window setKeyEquivalent: [o_vlcmain VLCKeyToString: o_key]];
167     [o_mi_double_window setKeyEquivalentModifierMask: [o_vlcmain VLCModifiersToCocoa:o_key]];
168
169     [self setSubmenusEnabled: FALSE];
170
171     [[NSNotificationCenter defaultCenter] addObserver: self
172                                              selector: @selector(refreshVoutDeviceMenu:)
173                                                  name: NSApplicationDidChangeScreenParametersNotification
174                                                object: nil];
175
176     /* we're done */
177     b_mainMenu_setup = YES;
178
179     [self setupVarMenuItem: o_mi_add_intf target: (vlc_object_t *)p_intf
180                              var: "intf-add" selector: @selector(toggleVar:)];
181 }
182
183 - (void)initStrings
184 {
185     /* main menu */
186     [o_mi_about setTitle: [_NS("About VLC media player") \
187                            stringByAppendingString: @"..."]];
188     [o_mi_checkForUpdate setTitle: _NS("Check for Update...")];
189     [o_mi_prefs setTitle: _NS("Preferences...")];
190     [o_mi_add_intf setTitle: _NS("Add Interface")];
191     [o_mu_add_intf setTitle: _NS("Add Interface")];
192     [o_mi_services setTitle: _NS("Services")];
193     [o_mi_hide setTitle: _NS("Hide VLC")];
194     [o_mi_hide_others setTitle: _NS("Hide Others")];
195     [o_mi_show_all setTitle: _NS("Show All")];
196     [o_mi_quit setTitle: _NS("Quit VLC")];
197
198     [o_mu_file setTitle: _ANS("1:File")];
199     [o_mi_open_generic setTitle: _NS("Advanced Open File...")];
200     [o_mi_open_file setTitle: _NS("Open File...")];
201     [o_mi_open_disc setTitle: _NS("Open Disc...")];
202     [o_mi_open_net setTitle: _NS("Open Network...")];
203     [o_mi_open_capture setTitle: _NS("Open Capture Device...")];
204     [o_mi_open_recent setTitle: _NS("Open Recent")];
205     [o_mi_open_recent_cm setTitle: _NS("Clear Menu")];
206     [o_mi_open_wizard setTitle: _NS("Streaming/Exporting Wizard...")];
207
208     [o_mu_edit setTitle: _NS("Edit")];
209     [o_mi_cut setTitle: _NS("Cut")];
210     [o_mi_copy setTitle: _NS("Copy")];
211     [o_mi_paste setTitle: _NS("Paste")];
212     [o_mi_clear setTitle: _NS("Clear")];
213     [o_mi_select_all setTitle: _NS("Select All")];
214
215     [o_mu_controls setTitle: _NS("Playback")];
216     [o_mi_play setTitle: _NS("Play")];
217     [o_mi_stop setTitle: _NS("Stop")];
218     [o_mi_faster setTitle: _NS("Faster")];
219     [o_mi_slower setTitle: _NS("Slower")];
220     [o_mi_normalSpeed setTitle: _NS("Normal rate")];
221     [o_mi_trackSynchronization setTitle: _NS("Track Synchronization")];
222     [o_mi_previous setTitle: _NS("Previous")];
223     [o_mi_next setTitle: _NS("Next")];
224     [o_mi_random setTitle: _NS("Random")];
225     [o_mi_repeat setTitle: _NS("Repeat One")];
226     [o_mi_loop setTitle: _NS("Repeat All")];
227     [o_mi_quitAfterPB setTitle: _NS("Quit after Playback")];
228     [o_mi_fwd setTitle: _NS("Step Forward")];
229     [o_mi_bwd setTitle: _NS("Step Backward")];
230
231     [o_mi_program setTitle: _NS("Program")];
232     [o_mu_program setTitle: _NS("Program")];
233     [o_mi_title setTitle: _NS("Title")];
234     [o_mu_title setTitle: _NS("Title")];
235     [o_mi_chapter setTitle: _NS("Chapter")];
236     [o_mu_chapter setTitle: _NS("Chapter")];
237
238     [o_mu_audio setTitle: _NS("Audio")];
239     [o_mi_vol_up setTitle: _NS("Increase Volume")];
240     [o_mi_vol_down setTitle: _NS("Decrease Volume")];
241     [o_mi_mute setTitle: _NS("Mute")];
242     [o_mi_audiotrack setTitle: _NS("Audio Track")];
243     [o_mu_audiotrack setTitle: _NS("Audio Track")];
244     [o_mi_channels setTitle: _NS("Audio Channels")];
245     [o_mu_channels setTitle: _NS("Audio Channels")];
246     [o_mi_device setTitle: _NS("Audio Device")];
247     [o_mu_device setTitle: _NS("Audio Device")];
248     [o_mi_visual setTitle: _NS("Visualizations")];
249     [o_mu_visual setTitle: _NS("Visualizations")];
250
251     [o_mu_video setTitle: _NS("Video")];
252     [o_mi_half_window setTitle: _NS("Half Size")];
253     [o_mi_normal_window setTitle: _NS("Normal Size")];
254     [o_mi_double_window setTitle: _NS("Double Size")];
255     [o_mi_fittoscreen setTitle: _NS("Fit to Screen")];
256     [o_mi_fullscreen setTitle: _NS("Fullscreen")];
257     [o_mi_floatontop setTitle: _NS("Float on Top")];
258     [o_mi_snapshot setTitle: _NS("Snapshot")];
259     [o_mi_videotrack setTitle: _NS("Video Track")];
260     [o_mu_videotrack setTitle: _NS("Video Track")];
261     [o_mi_aspect_ratio setTitle: _NS("Aspect-ratio")];
262     [o_mu_aspect_ratio setTitle: _NS("Aspect-ratio")];
263     [o_mi_crop setTitle: _NS("Crop")];
264     [o_mu_crop setTitle: _NS("Crop")];
265     [o_mi_screen setTitle: _NS("Fullscreen Video Device")];
266     [o_mu_screen setTitle: _NS("Fullscreen Video Device")];
267     [o_mi_subtitle setTitle: _NS("Subtitles Track")];
268     [o_mu_subtitle setTitle: _NS("Subtitles Track")];
269     [o_mi_addSub setTitle: _NS("Open File...")];
270     [o_mi_deinterlace setTitle: _NS("Deinterlace")];
271     [o_mu_deinterlace setTitle: _NS("Deinterlace")];
272     [o_mi_deinterlace_mode setTitle: _NS("Deinterlace mode")];
273     [o_mu_deinterlace_mode setTitle: _NS("Deinterlace mode")];
274     [o_mi_ffmpeg_pp setTitle: _NS("Post processing")];
275     [o_mu_ffmpeg_pp setTitle: _NS("Post processing")];
276     [o_mi_teletext setTitle: _NS("Teletext")];
277     [o_mi_teletext_transparent setTitle: _NS("Transparent")];
278     [o_mi_teletext_index setTitle: _NS("Index")];
279     [o_mi_teletext_red setTitle: _NS("Red")];
280     [o_mi_teletext_green setTitle: _NS("Green")];
281     [o_mi_teletext_yellow setTitle: _NS("Yellow")];
282     [o_mi_teletext_blue setTitle: _NS("Blue")];
283
284     [o_mu_window setTitle: _NS("Window")];
285     [o_mi_minimize setTitle: _NS("Minimize Window")];
286     [o_mi_close_window setTitle: _NS("Close Window")];
287     [o_mi_player setTitle: _NS("Player...")];
288     [o_mi_controller setTitle: _NS("Controller...")];
289     [o_mi_audioeffects setTitle: _NS("Audio Effects...")];
290     [o_mi_videoeffects setTitle: _NS("Video Filters...")];
291     [o_mi_bookmarks setTitle: _NS("Bookmarks...")];
292     [o_mi_playlist setTitle: _NS("Playlist...")];
293     [o_mi_info setTitle: _NS("Media Information...")];
294     [o_mi_messages setTitle: _NS("Messages...")];
295     [o_mi_errorsAndWarnings setTitle: _NS("Errors and Warnings...")];
296
297     [o_mi_bring_atf setTitle: _NS("Bring All to Front")];
298
299     [o_mu_help setTitle: _NS("Help")];
300     [o_mi_help setTitle: _NS("VLC media player Help...")];
301     [o_mi_readme setTitle: _NS("ReadMe / FAQ...")];
302     [o_mi_license setTitle: _NS("License")];
303     [o_mi_documentation setTitle: _NS("Online Documentation...")];
304     [o_mi_website setTitle: _NS("VideoLAN Website...")];
305     [o_mi_donation setTitle: _NS("Make a donation...")];
306     [o_mi_forum setTitle: _NS("Online Forum...")];
307
308     /* dock menu */
309     [o_dmi_play setTitle: _NS("Play")];
310     [o_dmi_stop setTitle: _NS("Stop")];
311     [o_dmi_next setTitle: _NS("Next")];
312     [o_dmi_previous setTitle: _NS("Previous")];
313     [o_dmi_mute setTitle: _NS("Mute")];
314
315     /* vout menu */
316     [o_vmi_play setTitle: _NS("Play")];
317     [o_vmi_stop setTitle: _NS("Stop")];
318     [o_vmi_prev setTitle: _NS("Previous")];
319     [o_vmi_next setTitle: _NS("Next")];
320     [o_vmi_volup setTitle: _NS("Volume Up")];
321     [o_vmi_voldown setTitle: _NS("Volume Down")];
322     [o_vmi_mute setTitle: _NS("Mute")];
323     [o_vmi_fullscreen setTitle: _NS("Fullscreen")];
324     [o_vmi_snapshot setTitle: _NS("Snapshot")];
325 }
326
327 #pragma mark -
328 #pragma mark Termination
329
330 - (void)releaseRepresentedObjects:(NSMenu *)the_menu
331 {
332     if( !p_intf ) return;
333     
334     NSArray *menuitems_array = [the_menu itemArray];
335     for( int i=0; i<[menuitems_array count]; i++ )
336     {
337         NSMenuItem *one_item = [menuitems_array objectAtIndex: i];
338         if( [one_item hasSubmenu] )
339             [self releaseRepresentedObjects: [one_item submenu]];
340
341         [one_item setRepresentedObject:NULL];
342     }
343 }
344
345 #pragma mark -
346 #pragma mark Interface update
347
348 - (void)setupMenus
349 {
350     playlist_t * p_playlist = pl_Get( p_intf );
351     input_thread_t * p_input = playlist_CurrentInput( p_playlist );
352     if( p_input != NULL )
353     {
354         [self setupVarMenuItem: o_mi_program target: (vlc_object_t *)p_input
355                                  var: "program" selector: @selector(toggleVar:)];
356
357         [self setupVarMenuItem: o_mi_title target: (vlc_object_t *)p_input
358                                  var: "title" selector: @selector(toggleVar:)];
359
360         [self setupVarMenuItem: o_mi_chapter target: (vlc_object_t *)p_input
361                                  var: "chapter" selector: @selector(toggleVar:)];
362
363         [self setupVarMenuItem: o_mi_audiotrack target: (vlc_object_t *)p_input
364                                  var: "audio-es" selector: @selector(toggleVar:)];
365
366         [self setupVarMenuItem: o_mi_videotrack target: (vlc_object_t *)p_input
367                                  var: "video-es" selector: @selector(toggleVar:)];
368
369         [self setupVarMenuItem: o_mi_subtitle target: (vlc_object_t *)p_input
370                                  var: "spu-es" selector: @selector(toggleVar:)];
371
372         /* special case for "Open File" inside the subtitles menu item */
373         if( [o_mi_videotrack isEnabled] == YES )
374             [o_mi_subtitle setEnabled: YES];
375
376         aout_instance_t * p_aout = input_GetAout( p_input );
377         if( p_aout != NULL )
378         {
379             [self setupVarMenuItem: o_mi_channels target: (vlc_object_t *)p_aout
380                                      var: "audio-channels" selector: @selector(toggleVar:)];
381
382             [self setupVarMenuItem: o_mi_device target: (vlc_object_t *)p_aout
383                                      var: "audio-device" selector: @selector(toggleVar:)];
384
385             [self setupVarMenuItem: o_mi_visual target: (vlc_object_t *)p_aout
386                                      var: "visual" selector: @selector(toggleVar:)];
387             vlc_object_release( (vlc_object_t *)p_aout );
388         }
389
390         vout_thread_t * p_vout = input_GetVout( p_input );
391
392         if( p_vout != NULL )
393         {
394             vlc_object_t * p_dec_obj;
395
396             [self setupVarMenuItem: o_mi_aspect_ratio target: (vlc_object_t *)p_vout
397                                      var: "aspect-ratio" selector: @selector(toggleVar:)];
398
399             [self setupVarMenuItem: o_mi_crop target: (vlc_object_t *) p_vout
400                                      var: "crop" selector: @selector(toggleVar:)];
401
402             [self setupVarMenuItem: o_mi_screen target: (vlc_object_t *)p_vout
403                                      var: "video-device" selector: @selector(toggleVar:)];
404
405             [self setupVarMenuItem: o_mi_deinterlace target: (vlc_object_t *)p_vout
406                                      var: "deinterlace" selector: @selector(toggleVar:)];
407
408             [self setupVarMenuItem: o_mi_deinterlace_mode target: (vlc_object_t *)p_vout
409                                      var: "deinterlace-mode" selector: @selector(toggleVar:)];
410
411 #if 1
412             [self setupVarMenuItem: o_mi_ffmpeg_pp target:
413              (vlc_object_t *)p_vout var:"postprocess" selector:
414              @selector(toggleVar:)];
415 #endif
416             vlc_object_release( (vlc_object_t *)p_vout );
417         }
418         vlc_object_release( p_input );
419     }
420 }
421
422 - (void)refreshVoutDeviceMenu:(NSNotification *)o_notification
423 {
424     int x, y = 0;
425     vout_thread_t * p_vout = getVout();
426     if( !p_vout )
427         return;
428
429     /* clean the menu before adding new entries */
430     if( [o_mi_screen hasSubmenu] )
431     {
432         y = [[o_mi_screen submenu] numberOfItems] - 1;
433         msg_Dbg( VLCIntf, "%i items in submenu", y );
434         while( x != y )
435         {
436             msg_Dbg( VLCIntf, "removing item %i of %i", x, y );
437             [[o_mi_screen submenu] removeItemAtIndex: x];
438             x++;
439         }
440     }
441
442     [self setupVarMenuItem: o_mi_screen target: (vlc_object_t *)p_vout
443                              var: "video-device" selector: @selector(toggleVar:)];
444     vlc_object_release( (vlc_object_t *)p_vout );
445 }
446
447 - (void)setSubmenusEnabled:(BOOL)b_enabled
448 {
449     [o_mi_program setEnabled: b_enabled];
450     [o_mi_title setEnabled: b_enabled];
451     [o_mi_chapter setEnabled: b_enabled];
452     [o_mi_audiotrack setEnabled: b_enabled];
453     [o_mi_visual setEnabled: b_enabled];
454     [o_mi_videotrack setEnabled: b_enabled];
455     [o_mi_subtitle setEnabled: b_enabled];
456     [o_mi_channels setEnabled: b_enabled];
457     [o_mi_deinterlace setEnabled: b_enabled];
458     [o_mi_deinterlace_mode setEnabled: b_enabled];
459     [o_mi_ffmpeg_pp setEnabled: b_enabled];
460     [o_mi_device setEnabled: b_enabled];
461     [o_mi_screen setEnabled: b_enabled];
462     [o_mi_aspect_ratio setEnabled: b_enabled];
463     [o_mi_crop setEnabled: b_enabled];
464     [o_mi_teletext setEnabled: b_enabled];
465 }
466
467 #pragma mark -
468 #pragma mark Recent Items
469 - (void)openRecentItem:(id)item
470 {
471     [[VLCMain sharedInstance] application: nil openFile: [item title]];
472 }
473
474 - (IBAction)clearRecentItems:(id)sender
475 {
476     [[NSDocumentController sharedDocumentController]
477      clearRecentDocuments: nil];
478 }
479
480 #pragma mark -
481 #pragma mark Panels
482
483 - (IBAction)intfOpenFile:(id)sender
484 {
485     [[[VLCMain sharedInstance] open] openFile];
486 }
487
488 - (IBAction)intfOpenFileGeneric:(id)sender
489 {
490     [[[VLCMain sharedInstance] open] openFileGeneric];
491 }
492
493 - (IBAction)intfOpenDisc:(id)sender
494 {
495     [[[VLCMain sharedInstance] open] openDisc];
496 }
497
498 - (IBAction)intfOpenNet:(id)sender
499 {
500     [[[VLCMain sharedInstance] open] openNet];
501 }
502
503 - (IBAction)intfOpenCapture:(id)sender
504 {
505     [[[VLCMain sharedInstance] open] openCapture];
506 }
507
508 - (IBAction)showWizard:(id)sender
509 {
510     [[[VLCMain sharedInstance] wizard] resetWizard];
511     [[[VLCMain sharedInstance] wizard] showWizard];
512 }
513
514 - (IBAction)showVideoEffects:(id)sender
515 {
516     if( o_videoeffects == nil )
517         o_videoeffects = [[VLCVideoEffects alloc] init];
518
519     if( !b_nib_videoeffects_loaded )
520         b_nib_videoeffects_loaded = [NSBundle loadNibNamed:@"VideoEffects" owner: NSApp];
521
522     [o_videoeffects toggleWindow:sender];
523 }
524
525 - (IBAction)showTrackSynchronization:(id)sender
526 {
527     if (!o_trackSynchronization)
528         o_trackSynchronization = [[VLCTrackSynchronization alloc] init];
529
530     if (!b_nib_tracksynchro_loaded)
531         b_nib_tracksynchro_loaded = [NSBundle loadNibNamed:@"SyncTracks" owner:NSApp];
532
533     [o_trackSynchronization toggleWindow:sender];
534 }
535
536 - (IBAction)showAudioEffects:(id)sender
537 {
538     if (!o_audioeffects)
539         o_audioeffects = [[VLCAudioEffects alloc] init];
540
541     if (!b_nib_audioeffects_loaded)
542         b_nib_audioeffects_loaded = [NSBundle loadNibNamed:@"AudioEffects" owner:NSApp];
543
544     [o_audioeffects toggleWindow:sender];
545 }
546
547 - (IBAction)showBookmarks:(id)sender
548 {
549     [[[VLCMain sharedInstance] bookmarks] showBookmarks];
550 }
551
552 - (IBAction)viewPreferences:(id)sender
553 {
554     [[[VLCMain sharedInstance] simplePreferences] showSimplePrefs];
555 }
556
557 #pragma mark -
558 #pragma mark Help and Docs
559
560 - (void)initAbout
561 {
562     if(! o_about )
563         o_about = [[VLAboutBox alloc] init];
564
565     if( !b_nib_about_loaded )
566         b_nib_about_loaded = [NSBundle loadNibNamed:@"About" owner: NSApp];
567 }
568
569 - (IBAction)viewAbout:(id)sender
570 {
571     [self initAbout];
572     [o_about showAbout];
573 }
574
575 - (IBAction)showLicense:(id)sender
576 {
577     [self initAbout];
578     [o_about showGPL: sender];
579 }
580
581 - (IBAction)viewHelp:(id)sender
582 {
583     [self initAbout];
584     [o_about showHelp];
585 }
586
587 - (IBAction)openReadMe:(id)sender
588 {
589     NSString * o_path = [[NSBundle mainBundle] pathForResource: @"README.MacOSX" ofType: @"rtf"];
590
591     [[NSWorkspace sharedWorkspace] openFile: o_path withApplication: @"TextEdit"];
592 }
593
594 - (IBAction)openDocumentation:(id)sender
595 {
596     NSURL * o_url = [NSURL URLWithString: @"http://www.videolan.org/doc/"];
597
598     [[NSWorkspace sharedWorkspace] openURL: o_url];
599 }
600
601 - (IBAction)openWebsite:(id)sender
602 {
603     NSURL * o_url = [NSURL URLWithString: @"http://www.videolan.org/"];
604
605     [[NSWorkspace sharedWorkspace] openURL: o_url];
606 }
607
608 - (IBAction)openForum:(id)sender
609 {
610     NSURL * o_url = [NSURL URLWithString: @"http://forum.videolan.org/"];
611
612     [[NSWorkspace sharedWorkspace] openURL: o_url];
613 }
614
615 - (IBAction)openDonate:(id)sender
616 {
617     NSURL * o_url = [NSURL URLWithString: @"http://www.videolan.org/contribute.html#paypal"];
618
619     [[NSWorkspace sharedWorkspace] openURL: o_url];
620 }
621
622 #pragma mark -
623 #pragma mark Errors, warnings and messages
624
625 - (IBAction)viewErrorsAndWarnings:(id)sender
626 {
627     [[[[VLCMain sharedInstance] coreDialogProvider] errorPanel] showPanel];
628 }
629
630 - (IBAction)showInformationPanel:(id)sender
631 {
632     [[[VLCMain sharedInstance] info] initPanel];
633 }
634
635 #pragma mark -
636 #pragma mark convinience stuff for other objects
637 - (void)setPlay
638 {
639     [o_mi_play setTitle: _NS("Play")];
640     [o_dmi_play setTitle: _NS("Play")];
641     [o_vmi_play setTitle: _NS("Play")];
642 }
643
644 - (void)setPause
645 {
646     [o_mi_play setTitle: _NS("Pause")];
647     [o_dmi_play setTitle: _NS("Pause")];
648     [o_vmi_play setTitle: _NS("Pause")];
649 }
650
651 #pragma mark -
652 #pragma mark Dynamic menu creation and validation
653
654 - (void)setupVarMenuItem:(NSMenuItem *)o_mi
655                   target:(vlc_object_t *)p_object
656                      var:(const char *)psz_variable
657                 selector:(SEL)pf_callback
658 {
659     vlc_value_t val, text;
660     int i_type = var_Type( p_object, psz_variable );
661
662     switch( i_type & VLC_VAR_TYPE )
663     {
664         case VLC_VAR_VOID:
665         case VLC_VAR_BOOL:
666         case VLC_VAR_VARIABLE:
667         case VLC_VAR_STRING:
668         case VLC_VAR_INTEGER:
669             break;
670         default:
671             /* Variable doesn't exist or isn't handled */
672             return;
673     }
674
675     /* Make sure we want to display the variable */
676     if( i_type & VLC_VAR_HASCHOICE )
677     {
678         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
679         if( val.i_int == 0 ) return;
680         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
681             return;
682     }
683
684     /* Get the descriptive name of the variable */
685     var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
686     [o_mi setTitle: [[VLCMain sharedInstance] localizedString: text.psz_string ?
687                      text.psz_string : psz_variable ]];
688
689     if( i_type & VLC_VAR_HASCHOICE )
690     {
691         NSMenu *o_menu = [o_mi submenu];
692         
693         [self setupVarMenu: o_menu forMenuItem: o_mi target:p_object
694                        var:psz_variable selector:pf_callback];
695         
696         free( text.psz_string );
697         return;
698     }
699     if( var_Get( p_object, psz_variable, &val ) < 0 )
700     {
701         return;
702     }
703
704     VLCAutoGeneratedMenuContent *o_data;
705     switch( i_type & VLC_VAR_TYPE )
706     {
707         case VLC_VAR_VOID:
708             o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
709                                                                       andValue: val ofType: i_type];
710             [o_mi setRepresentedObject: [o_data autorelease]];
711             break;
712
713         case VLC_VAR_BOOL:
714             o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
715                                                                       andValue: val ofType: i_type];
716             [o_mi setRepresentedObject: [o_data autorelease]];
717             if( !( i_type & VLC_VAR_ISCOMMAND ) )
718                 [o_mi setState: val.b_bool ? TRUE : FALSE ];
719             break;
720
721         default:
722             break;
723     }
724
725     if( ( i_type & VLC_VAR_TYPE ) == VLC_VAR_STRING ) free( val.psz_string );
726     free( text.psz_string );
727 }
728
729
730 - (void)setupVarMenu:(NSMenu *)o_menu
731          forMenuItem: (NSMenuItem *)o_parent
732               target:(vlc_object_t *)p_object
733                  var:(const char *)psz_variable
734             selector:(SEL)pf_callback
735 {
736     vlc_value_t val, val_list, text_list;
737     int i_type, i, i_nb_items;
738
739     /* remove previous items */
740     i_nb_items = [o_menu numberOfItems];
741     for( i = 0; i < i_nb_items; i++ )
742         [o_menu removeItemAtIndex: 0];
743
744     /* Check the type of the object variable */
745     i_type = var_Type( p_object, psz_variable );
746
747     /* Make sure we want to display the variable */
748     if( i_type & VLC_VAR_HASCHOICE )
749     {
750         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
751         if( val.i_int == 0 ) return;
752         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
753             return;
754     }
755     else
756         return;
757
758     switch( i_type & VLC_VAR_TYPE )
759     {
760         case VLC_VAR_VOID:
761         case VLC_VAR_BOOL:
762         case VLC_VAR_VARIABLE:
763         case VLC_VAR_STRING:
764         case VLC_VAR_INTEGER:
765             break;
766         default:
767             /* Variable doesn't exist or isn't handled */
768             return;
769     }
770
771     if( var_Get( p_object, psz_variable, &val ) < 0 )
772     {
773         return;
774     }
775
776     if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST,
777                    &val_list, &text_list ) < 0 )
778     {
779         if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
780         return;
781     }
782
783     /* make (un)sensitive */
784     [o_parent setEnabled: ( val_list.p_list->i_count > 1 )];
785
786     /* Aspect Ratio */
787     if( [[o_parent title] isEqualToString: _NS("Aspect-ratio")] == YES )
788     {
789         NSMenuItem *o_lmi_tmp2;
790         o_lmi_tmp2 = [o_menu addItemWithTitle: _NS("Lock Aspect Ratio") action: @selector(lockVideosAspectRatio:) keyEquivalent: @""];
791         [o_lmi_tmp2 setTarget: self];
792         [o_lmi_tmp2 setEnabled: YES];
793         [o_lmi_tmp2 setState: [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]];
794         [o_parent setEnabled: YES];
795         [o_menu addItem: [NSMenuItem separatorItem]];
796     }
797
798     /* special case for the subtitles items */
799     if( [[o_parent title] isEqualToString: _NS("Subtitles Track")] == YES )
800     {
801         NSMenuItem * o_lmi_tmp;
802         o_lmi_tmp = [o_menu addItemWithTitle: _NS("Open File...") action: @selector(addSubtitleFile:) keyEquivalent: @""];
803         [o_lmi_tmp setTarget: self];
804         [o_lmi_tmp setEnabled: YES];
805         [o_parent setEnabled: YES];
806         [o_menu addItem: [NSMenuItem separatorItem]];
807     }
808
809     for( i = 0; i < val_list.p_list->i_count; i++ )
810     {
811         NSMenuItem * o_lmi;
812         NSString *o_title = @"";
813         VLCAutoGeneratedMenuContent *o_data;
814
815         switch( i_type & VLC_VAR_TYPE )
816         {
817             case VLC_VAR_STRING:
818
819                 o_title = [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string ?
820                            text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
821
822                 o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
823                 o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
824                                                                           andValue: val_list.p_list->p_values[i] ofType: i_type];
825                 [o_lmi setRepresentedObject: [o_data autorelease]];
826                 [o_lmi setTarget: self];
827
828                 if( !strcmp( val.psz_string, val_list.p_list->p_values[i].psz_string ) && !( i_type & VLC_VAR_ISCOMMAND ) )
829                     [o_lmi setState: TRUE ];
830
831                 break;
832
833             case VLC_VAR_INTEGER:
834
835                 o_title = text_list.p_list->p_values[i].psz_string ?
836                 [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string] :
837                 [NSString stringWithFormat: @"%"PRId64,
838                  val_list.p_list->p_values[i].i_int];
839
840                 o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
841                 o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
842                                                                           andValue: val_list.p_list->p_values[i] ofType: i_type];
843                 [o_lmi setRepresentedObject: [o_data autorelease]];
844                 [o_lmi setTarget: self];
845
846                 if( val_list.p_list->p_values[i].i_int == val.i_int && !( i_type & VLC_VAR_ISCOMMAND ) )
847                     [o_lmi setState: TRUE ];
848                 break;
849
850             default:
851                 break;
852         }
853     }
854
855     /* special case for the subtitles sub-menu
856      * In case that we don't have any subs, we don't want a separator item at the end */
857     if( [[o_parent title] isEqualToString: _NS("Subtitles Track")] == YES )
858     {
859         if( [o_menu numberOfItems] == 2 )
860             [o_menu removeItemAtIndex: 1];
861     }
862
863     /* clean up everything */
864     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
865     var_FreeList( &val_list, &text_list );
866 }
867
868 - (IBAction)toggleVar:(id)sender
869 {
870     NSMenuItem *o_mi = (NSMenuItem *)sender;
871     VLCAutoGeneratedMenuContent *o_data = [o_mi representedObject];
872     [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
873                              toTarget: self withObject: o_data];
874
875     return;
876 }
877
878 - (int)toggleVarThread: (id)data
879 {
880     vlc_object_t *p_object;
881     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
882
883     assert([data isKindOfClass:[VLCAutoGeneratedMenuContent class]]);
884     VLCAutoGeneratedMenuContent *menuContent = (VLCAutoGeneratedMenuContent *)data;
885
886     p_object = [menuContent vlcObject];
887
888     if( p_object != NULL )
889     {
890         var_Set( p_object, [menuContent name], [menuContent value] );
891         vlc_object_release( p_object );
892         [o_pool release];
893         return true;
894     }
895     [o_pool release];
896     return VLC_EGENERIC;
897 }
898
899 @end
900
901 @implementation VLCMainMenu (NSMenuValidation)
902
903 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
904 {
905     NSString *o_title = [o_mi title];
906     BOOL bEnabled = TRUE;
907     vlc_value_t val;
908     playlist_t * p_playlist = pl_Get( p_intf );
909     input_thread_t * p_input = playlist_CurrentInput( p_playlist );
910
911     /* Recent Items Menu */
912     if( [o_title isEqualToString: _NS("Clear Menu")] )
913     {
914         NSMenu * o_menu = [o_mi_open_recent submenu];
915         int i_nb_items = [o_menu numberOfItems];
916         NSArray * o_docs = [[NSDocumentController sharedDocumentController]
917                             recentDocumentURLs];
918         UInt32 i_nb_docs = [o_docs count];
919
920         if( i_nb_items > 1 )
921         {
922             while( --i_nb_items )
923             {
924                 [o_menu removeItemAtIndex: 0];
925             }
926         }
927
928         if( i_nb_docs > 0 )
929         {
930             NSURL * o_url;
931             NSString * o_doc;
932
933             [o_menu insertItem: [NSMenuItem separatorItem] atIndex: 0];
934
935             while( TRUE )
936             {
937                 i_nb_docs--;
938
939                 o_url = [o_docs objectAtIndex: i_nb_docs];
940
941                 if( [o_url isFileURL] )
942                     o_doc = [o_url path];
943                 else
944                     o_doc = [o_url absoluteString];
945
946                 [o_menu insertItemWithTitle: o_doc
947                                      action: @selector(openRecentItem:)
948                               keyEquivalent: @"" atIndex: 0];
949
950                 if( i_nb_docs == 0 )
951                     break;
952             }
953         }
954         else
955         {
956             bEnabled = FALSE;
957         }
958     }
959     else if( [o_title isEqualToString: _NS("Faster")] ||
960             [o_title isEqualToString: _NS("Slower")] ||
961             [o_title isEqualToString: _NS("Normal rate")] )
962     {
963         if( p_input != NULL )
964         {
965             bEnabled = var_GetBool( p_input, "can-rate" );
966         }
967         else
968         {
969             bEnabled = FALSE;
970         }
971     }
972     else if( [o_title isEqualToString: _NS("Stop")] )
973     {
974         if( p_input == NULL )
975         {
976             bEnabled = FALSE;
977         }
978         [self setupMenus]; /* Make sure input menu is up to date */
979     }
980     else if( [o_title isEqualToString: _NS("Previous")] ||
981             [o_title isEqualToString: _NS("Next")] )
982     {
983         PL_LOCK;
984         bEnabled = playlist_CurrentSize( p_playlist ) > 1;
985         PL_UNLOCK;
986     }
987     else if( [o_title isEqualToString: _NS("Random")] )
988     {
989         int i_state;
990         var_Get( p_playlist, "random", &val );
991         i_state = val.b_bool ? NSOnState : NSOffState;
992         [o_mi setState: i_state];
993     }
994     else if( [o_title isEqualToString: _NS("Repeat One")] )
995     {
996         int i_state;
997         var_Get( p_playlist, "repeat", &val );
998         i_state = val.b_bool ? NSOnState : NSOffState;
999         [o_mi setState: i_state];
1000     }
1001     else if( [o_title isEqualToString: _NS("Repeat All")] )
1002     {
1003         int i_state;
1004         var_Get( p_playlist, "loop", &val );
1005         i_state = val.b_bool ? NSOnState : NSOffState;
1006         [o_mi setState: i_state];
1007     }
1008     else if( [o_title isEqualToString: _NS("Quit after Playback")] )
1009     {
1010         int i_state;
1011         var_Get( p_playlist, "play-and-exit", &val );
1012         i_state = val.b_bool ? NSOnState : NSOffState;
1013         [o_mi setState: i_state];
1014     }
1015     else if( [o_title isEqualToString: _NS("Step Forward")] ||
1016             [o_title isEqualToString: _NS("Step Backward")] ||
1017             [o_title isEqualToString: _NS("Jump To Time")])
1018     {
1019         if( p_input != NULL )
1020         {
1021             var_Get( p_input, "can-seek", &val);
1022             bEnabled = val.b_bool;
1023         }
1024         else bEnabled = FALSE;
1025     }
1026     else if( [o_title isEqualToString: _NS("Mute")] )
1027     {
1028         [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
1029         [self setupMenus]; /* Make sure audio menu is up to date */
1030     }
1031     else if( [o_title isEqualToString: _NS("Half Size")] ||
1032             [o_title isEqualToString: _NS("Normal Size")] ||
1033             [o_title isEqualToString: _NS("Double Size")] ||
1034             [o_title isEqualToString: _NS("Fit to Screen")] ||
1035             [o_title isEqualToString: _NS("Snapshot")] ||
1036             [o_title isEqualToString: _NS("Fullscreen")] ||
1037             [o_title isEqualToString: _NS("Float on Top")] )
1038     {
1039         id o_window;
1040         NSArray *o_windows = [NSApp orderedWindows];
1041         NSEnumerator *o_enumerator = [o_windows objectEnumerator];
1042         bEnabled = FALSE;
1043
1044         if( p_input != NULL )
1045         {
1046             vout_thread_t *p_vout = input_GetVout( p_input );
1047             if( p_vout != NULL )
1048             {
1049                 if( [o_title isEqualToString: _NS("Float on Top")] )
1050                 {
1051                     var_Get( p_vout, "video-on-top", &val );
1052                     [o_mi setState: val.b_bool ?  NSOnState : NSOffState];
1053                 }
1054
1055                 while( (o_window = [o_enumerator nextObject]))
1056                 {
1057                     if( [[o_window className] isEqualToString: @"VLCVoutWindow"] ||
1058                        [[[VLCMain sharedInstance] embeddedList]
1059                         windowContainsEmbedded: o_window])
1060                     {
1061                         bEnabled = TRUE;
1062                         break;
1063                     }
1064                 }
1065
1066                 vlc_object_release( (vlc_object_t *)p_vout );
1067             }
1068         }
1069         if( [o_title isEqualToString: _NS("Fullscreen")] )
1070         {
1071             var_Get( p_playlist, "fullscreen", &val );
1072             [o_mi setState: val.b_bool];
1073             bEnabled = TRUE;
1074         }
1075         [self setupMenus]; /* Make sure video menu is up to date */
1076     }
1077
1078     /* Special case for telx menu */
1079     if( [o_title isEqualToString: _NS("Normal Size")] )
1080     {
1081         NSMenuItem *item = [[o_mi menu] itemWithTitle:_NS("Teletext")];
1082                 bool b_telx = p_input && var_GetInteger( p_input, "teletext-es" ) >= 0;
1083
1084         [[item submenu] setAutoenablesItems:NO];
1085         for( int k=0; k < [[item submenu] numberOfItems]; k++ )
1086         {
1087             [[[item submenu] itemAtIndex:k] setEnabled: b_telx];
1088         }
1089     }
1090
1091     if( p_input ) vlc_object_release( p_input );
1092
1093     return( bEnabled );
1094 }
1095
1096 @end
1097
1098
1099 /*****************************************************************************
1100  * VLCAutoGeneratedMenuContent implementation
1101  *****************************************************************************
1102  * Object connected to a playlistitem which remembers the data belonging to
1103  * the variable of the autogenerated menu
1104  *****************************************************************************/
1105 @implementation VLCAutoGeneratedMenuContent
1106
1107 -(id) initWithVariableName:(const char *)name ofObject:(vlc_object_t *)object
1108                   andValue:(vlc_value_t)val ofType:(int)type
1109 {
1110     self = [super init];
1111
1112     if( self != nil )
1113     {
1114         _vlc_object = vlc_object_hold( object );
1115         psz_name = strdup( name );
1116         i_type = type;
1117         value = val;
1118         if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING )
1119             value.psz_string = strdup( val.psz_string );
1120     }
1121
1122     return( self );
1123 }
1124
1125 - (void)dealloc
1126 {
1127     vlc_object_release( _vlc_object );
1128     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING )
1129         free( value.psz_string );
1130     free( psz_name );
1131     [super dealloc];
1132 }
1133
1134 - (const char *)name
1135 {
1136     return psz_name;
1137 }
1138
1139 - (vlc_value_t)value
1140 {
1141     return value;
1142 }
1143
1144 - (vlc_object_t *)vlcObject
1145 {
1146     return vlc_object_hold( _vlc_object );
1147 }
1148
1149
1150 - (int)type
1151 {
1152     return i_type;
1153 }
1154
1155 @end