macosx/main menu: cosmetics
[vlc.git] / modules / gui / macosx / menus / VLCMainMenu.m
1 /*****************************************************************************
2  *MainMenu.m: MacOS X interface module
3  *****************************************************************************
4  *Copyright (C) 2011-2019 Felix Paul Kühne
5  *
6  *Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
7  *
8  *This program is free software; you can redistribute it and/or modify
9  *it under the terms of the GNU General Public License as published by
10  *the Free Software Foundation; either version 2 of the License, or
11  *(at your option) any later version.
12  *
13  *This program is distributed in the hope that it will be useful,
14  *but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *GNU General Public License for more details.
17  *
18  *You should have received a copy of the GNU General Public License
19  *along with this program; if not, write to the Free Software
20  *Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #import "VLCMainMenu.h"
24 #import "main/VLCMain.h"
25
26 #import "coreinteraction/VLCVideoFilterHelper.h"
27
28 #import "extensions/NSScreen+VLCAdditions.h"
29 #import "library/VLCLibraryWindow.h"
30
31 #import "menus/renderers/VLCRendererMenuController.h"
32
33 #import "panels/VLCAudioEffectsWindowController.h"
34 #import "panels/VLCTrackSynchronizationWindowController.h"
35 #import "panels/VLCVideoEffectsWindowController.h"
36 #import "panels/VLCBookmarksWindowController.h"
37 #import "panels/dialogs/VLCCoreDialogProvider.h"
38 #import "panels/VLCInformationWindowController.h"
39 #import "panels/VLCTimeSelectionPanelController.h"
40
41 #import "playlist/VLCPlaylistController.h"
42 #import "playlist/VLCPlayerController.h"
43 #import "preferences/VLCSimplePrefsController.h"
44
45 #import "windows/VLCAboutWindowController.h"
46 #import "windows/VLCOpenWindowController.h"
47 #import "windows/VLCErrorWindowController.h"
48 #import "windows/VLCHelpWindowController.h"
49 #import "windows/mainwindow/VLCMainWindowControlsBar.h"
50 #import "windows/extensions/VLCExtensionsManager.h"
51 #import "windows/video/VLCVoutView.h"
52 #import "windows/convertandsave/VLCConvertAndSaveWindowController.h"
53 #import "windows/logging/VLCLogWindowController.h"
54 #import "windows/addons/VLCAddonsWindowController.h"
55
56 #ifdef HAVE_SPARKLE
57 #import <Sparkle/Sparkle.h>
58 #endif
59
60 @interface VLCAutoGeneratedMenuContent : NSObject
61 {
62     char *psz_name;
63     vlc_object_t *vlc_object;
64     vlc_value_t value;
65     int i_type;
66 }
67 - (id)initWithVariableName:(const char *)name
68                   ofObject:(vlc_object_t *)object
69                   andValue:(vlc_value_t)value
70                     ofType:(int)type;
71 - (const char *)name;
72 - (vlc_value_t)value;
73 - (vlc_object_t *)vlcObject;
74 - (int)type;
75
76 @end
77
78 @interface VLCMainMenu() <NSMenuDelegate>
79 {
80     VLCAboutWindowController *_aboutWindowController;
81     VLCHelpWindowController  *_helpWindowController;
82     VLCAddonsWindowController *_addonsController;
83     VLCRendererMenuController *_rendererMenuController;
84     VLCPlaylistController *_playlistController;
85     VLCPlayerController *_playerController;
86     NSTimer *_cancelRendererDiscoveryTimer;
87
88     NSMenu *_playlistTableColumnsContextMenu;
89
90     __strong VLCTimeSelectionPanelController *_timeSelectionPanel;
91 }
92 @end
93
94 @implementation VLCMainMenu
95
96 #pragma mark - Initialization
97
98 - (void)dealloc
99 {
100     msg_Dbg(getIntf(), "Deinitializing main menu");
101     [[NSNotificationCenter defaultCenter] removeObserver: self];
102
103     [self releaseRepresentedObjects:[NSApp mainMenu]];
104 }
105
106 - (void)awakeFromNib
107 {
108     _timeSelectionPanel = [[VLCTimeSelectionPanelController alloc] init];
109     _playlistController = [[VLCMain sharedInstance] playlistController];
110     _playerController = _playlistController.playerController;
111
112     /* check whether the user runs OSX with a RTL language */
113     NSArray *languages = [NSLocale preferredLanguages];
114     NSString *preferredLanguage = [languages firstObject];
115
116     if ([NSLocale characterDirectionForLanguage:preferredLanguage] == NSLocaleLanguageDirectionRightToLeft) {
117         msg_Dbg(getIntf(), "adapting interface since '%s' is a RTL language", [preferredLanguage UTF8String]);
118         [_rateTextField setAlignment:NSLeftTextAlignment];
119     }
120
121     [self setRateControlsEnabled:NO];
122
123 #ifdef HAVE_SPARKLE
124     [_checkForUpdate setAction:@selector(checkForUpdates:)];
125     [_checkForUpdate setTarget:[SUUpdater sharedUpdater]];
126 #else
127     [_checkForUpdate setEnabled:NO];
128 #endif
129
130     [self initStrings];
131     [self setupKeyboardShortcuts];
132
133     /* configure playback / controls menu */
134     self.controlsMenu.delegate = self;
135     [_rendererNoneItem setState:NSOnState];
136     _rendererMenuController = [[VLCRendererMenuController alloc] init];
137     _rendererMenuController.rendererNoneItem = _rendererNoneItem;
138     _rendererMenuController.rendererMenu = _rendererMenu;
139
140     [self mediaItemChanged:nil];
141     [self updateTitleAndChapterMenus:nil];
142     [self updateProgramMenu:nil];
143
144     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
145     [notificationCenter addObserver:self
146                            selector:@selector(refreshVoutDeviceMenu:)
147                                name:NSApplicationDidChangeScreenParametersNotification
148                              object:nil];
149     [notificationCenter addObserver:self
150                            selector:@selector(updatePlaybackRate)
151                                name:VLCPlayerRateChanged
152                              object:nil];
153     [notificationCenter addObserver:self
154                            selector:@selector(updateRecordState)
155                                name:VLCPlayerRecordingChanged
156                              object:nil];
157     [notificationCenter addObserver:self
158                            selector:@selector(playbackStateChanged:)
159                                name:VLCPlayerStateChanged
160                              object:nil];
161     [notificationCenter addObserver:self
162                            selector:@selector(playModeChanged:)
163                                name:VLCPlaybackRepeatChanged
164                              object:nil];
165     [notificationCenter addObserver:self
166                            selector:@selector(playOrderChanged:)
167                                name:VLCPlaybackOrderChanged
168                              object:nil];
169     [notificationCenter addObserver:self
170                            selector:@selector(updateTrackHandlingMenus:)
171                                name:VLCPlayerTrackListChanged
172                              object:nil];
173     [notificationCenter addObserver:self
174                            selector:@selector(updateTitleAndChapterMenus:)
175                                name:VLCPlayerTitleListChanged
176                              object:nil];
177     [notificationCenter addObserver:self
178                            selector:@selector(updateTitleAndChapterMenus:)
179                                name:VLCPlayerTitleSelectionChanged
180                              object:nil];
181     [notificationCenter addObserver:self
182                            selector:@selector(updateTitleAndChapterMenus:)
183                                name:VLCPlayerChapterSelectionChanged
184                              object:nil];
185     [notificationCenter addObserver:self
186                            selector:@selector(updateProgramMenu:)
187                                name:VLCPlayerProgramListChanged
188                              object:nil];
189     [notificationCenter addObserver:self
190                            selector:@selector(updateProgramMenu:)
191                                name:VLCPlayerProgramSelectionChanged
192                              object:nil];
193     [notificationCenter addObserver:self
194                            selector:@selector(mediaItemChanged:)
195                                name:VLCPlaylistCurrentItemChanged
196                              object:nil];
197
198     [self setupVarMenuItem:_add_intf
199                     target:VLC_OBJECT(getIntf())
200                        var:"intf-add"
201                   selector:@selector(toggleVar:)];
202
203     /* setup extensions menu */
204     /* Let the ExtensionsManager itself build the menu */
205     VLCExtensionsManager *extMgr = [[VLCMain sharedInstance] extensionsManager];
206     [extMgr buildMenu:_extensionsMenu];
207     [_extensions setEnabled:([_extensionsMenu numberOfItems] > 0)];
208
209     // FIXME: Implement preference for autoloading extensions on mac
210     // FIXME: this is definitely the wrong place to do this.
211     if (![extMgr isLoaded] && ![extMgr cannotLoad])
212         [extMgr loadExtensions];
213
214     /* setup post-proc menu */
215     [_postprocessingMenu removeAllItems];
216     [_postprocessingMenu setAutoenablesItems: YES];
217     [_postprocessingMenu addItemWithTitle: _NS("Disable") action:@selector(togglePostProcessing:) keyEquivalent:@""];
218     NSMenuItem *mitem = [_postprocessingMenu itemAtIndex: 0];
219     [mitem setTag: -1];
220     [mitem setEnabled: YES];
221     [mitem setTarget: self];
222     for (NSUInteger x = 1; x < 7; x++) {
223         [_postprocessingMenu addItemWithTitle:[NSString stringWithFormat:_NS("Level %i"), x]
224                                        action:@selector(togglePostProcessing:)
225                                 keyEquivalent:@""];
226         mitem = [_postprocessingMenu itemAtIndex:x];
227         [mitem setEnabled:YES];
228         [mitem setTag:x];
229         [mitem setTarget:self];
230     }
231     char *psz_config = config_GetPsz("video-filter");
232     if (psz_config) {
233         if (!strstr(psz_config, "postproc"))
234             [[_postprocessingMenu itemAtIndex:0] setState:NSOnState];
235         else
236             [[_postprocessingMenu itemWithTag:config_GetInt("postproc-q")] setState:NSOnState];
237         free(psz_config);
238     } else
239         [[_postprocessingMenu itemAtIndex:0] setState:NSOnState];
240     [_postprocessing setEnabled: NO];
241
242     [self refreshAudioDeviceList];
243
244 #if 0
245 #warning fix advanced subtitles styles (see #22095)
246     /* setup subtitles menu */
247     // Persist those variables on the playlist
248     playlist_t *p_playlist = pl_Get(getIntf());
249     var_Create(p_playlist, "freetype-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
250     var_Create(p_playlist, "freetype-background-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
251     var_Create(p_playlist, "freetype-background-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
252     var_Create(p_playlist, "freetype-outline-thickness", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
253
254     [self setupMenu: _subtitle_textcolorMenu withIntList:"freetype-color" andSelector:@selector(switchSubtitleOption:)];
255     [_subtitle_bgopacity_sld setIntegerValue: config_GetInt("freetype-background-opacity")];
256     [self setupMenu: _subtitle_bgcolorMenu withIntList:"freetype-background-color" andSelector:@selector(switchSubtitleOption:)];
257     [self setupMenu: _subtitle_outlinethicknessMenu withIntList:"freetype-outline-thickness" andSelector:@selector(switchSubtitleOption:)];
258 #endif
259
260     /* Build size menu based on different scale factors */
261     struct {
262         const char *const name;
263         int scaleValue;
264     } scaleValues[] = {
265         { N_("Smaller"), 50},
266         { N_("Small"),   75},
267         { N_("Normal"), 100},
268         { N_("Large"),  125},
269         { N_("Larger"), 150},
270         { NULL, 0 }
271     };
272
273     for (int i = 0; scaleValues[i].name; i++) {
274         NSMenuItem *menuItem = [_subtitle_sizeMenu addItemWithTitle: _NS(scaleValues[i].name) action:@selector(switchSubtitleSize:) keyEquivalent:@""];
275         [menuItem setTag:scaleValues[i].scaleValue];
276         [menuItem setTarget: self];
277     }
278 }
279
280 - (void)setupMenu:(NSMenu *)menu withIntList:(char *)psz_name andSelector:(SEL)selector
281 {
282     module_config_t *p_item;
283
284     [menu removeAllItems];
285     p_item = config_FindConfig(psz_name);
286
287     if (!p_item) {
288         msg_Err(getIntf(), "couldn't create menu int list for item '%s' as it does not exist", psz_name);
289         return;
290     }
291
292     for (int i = 0; i < p_item->list_count; i++) {
293         NSMenuItem *mi;
294         if (p_item->list_text != NULL)
295             mi = [[NSMenuItem alloc] initWithTitle: _NS(p_item->list_text[i]) action:NULL keyEquivalent: @""];
296         else if (p_item->list.i[i])
297             mi = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"%d", p_item->list.i[i]] action:NULL keyEquivalent: @""];
298         else {
299             msg_Err(getIntf(), "item %d of pref %s failed to be created", i, psz_name);
300             continue;
301         }
302
303         [mi setTarget:self];
304         [mi setAction:selector];
305         [mi setTag:p_item->list.i[i]];
306         [mi setRepresentedObject:toNSStr(psz_name)];
307         [menu addItem:mi];
308         if (p_item->value.i == p_item->list.i[i])
309             [mi setState:NSOnState];
310     }
311 }
312
313 - (void)initStrings
314 {
315     /* main menu */
316     [_about setTitle: [_NS("About VLC media player") stringByAppendingString: @"..."]];
317     [_checkForUpdate setTitle: _NS("Check for Update...")];
318     [_prefs setTitle: _NS("Preferences...")];
319     [_extensions setTitle: _NS("Extensions")];
320     [_extensionsMenu setTitle: _NS("Extensions")];
321     [_addonManager setTitle: _NS("Addons Manager")];
322     [_add_intf setTitle: _NS("Add Interface")];
323     [_add_intfMenu setTitle: _NS("Add Interface")];
324     [_services setTitle: _NS("Services")];
325     [_hide setTitle: _NS("Hide VLC")];
326     [_hide_others setTitle: _NS("Hide Others")];
327     [_show_all setTitle: _NS("Show All")];
328     [_quit setTitle: _NS("Quit VLC")];
329
330     /* this special case is needed to due to archiac legacy translations of the File menu
331      * on the Mac to the German translation which resulted in 'Ablage' instead of 'Datei'.
332      * This remains until the present day and does not affect the Windows world. */
333     [_fileMenu setTitle: _ANS("1:File")];
334     [_open_generic setTitle: _NS("Advanced Open File...")];
335     [_open_file setTitle: _NS("Open File...")];
336     [_open_disc setTitle: _NS("Open Disc...")];
337     [_open_net setTitle: _NS("Open Network...")];
338     [_open_capture setTitle: _NS("Open Capture Device...")];
339     [_open_recent setTitle: _NS("Open Recent")];
340     [_close_window setTitle: _NS("Close Window")];
341     [_convertandsave setTitle: _NS("Convert / Stream...")];
342     [_save_playlist setTitle: _NS("Save Playlist...")];
343     [_revealInFinder setTitle: _NS("Reveal in Finder")];
344
345     [_editMenu setTitle: _NS("Edit")];
346     [_cutItem setTitle: _NS("Cut")];
347     [_mcopyItem setTitle: _NS("Copy")];
348     [_pasteItem setTitle: _NS("Paste")];
349     [_clearItem setTitle: _NS("Delete")];
350     [_select_all setTitle: _NS("Select All")];
351     [_findItem setTitle: _NS("Find")];
352
353     [_viewMenu setTitle: _NS("View")];
354     [_toggleJumpButtons setTitle: _NS("Show Previous & Next Buttons")];
355     [_toggleJumpButtons setState: var_InheritBool(getIntf(), "macosx-show-playback-buttons")];
356     [_togglePlaymodeButtons setTitle: _NS("Show Shuffle & Repeat Buttons")];
357     [_togglePlaymodeButtons setState: var_InheritBool(getIntf(), "macosx-show-playmode-buttons")];
358     [_toggleEffectsButton setTitle: _NS("Show Audio Effects Button")];
359     [_toggleEffectsButton setState: var_InheritBool(getIntf(), "macosx-show-effects-button")];
360     [_toggleSidebar setTitle: _NS("Show Sidebar")];
361     [_playlistTableColumns setTitle: _NS("Playlist Table Columns")];
362
363     [_controlsMenu setTitle: _NS("Playback")];
364     [_play setTitle: _NS("Play")];
365     [_stop setTitle: _NS("Stop")];
366     [_record setTitle: _NS("Record")];
367     [_rate_view setAutoresizingMask:NSViewWidthSizable];
368     [_rate setView: _rate_view];
369     [_rateLabel setStringValue: _NS("Playback Speed")];
370     [_rate_slowerLabel setStringValue: _NS("Slower")];
371     [_rate_normalLabel setStringValue: _NS("Normal")];
372     [_rate_fasterLabel setStringValue: _NS("Faster")];
373     [_trackSynchronization setTitle: _NS("Track Synchronization")];
374     [_previous setTitle: _NS("Previous")];
375     [_next setTitle: _NS("Next")];
376     [_random setTitle: _NS("Random")];
377     [_repeat setTitle: _NS("Repeat One")];
378     [_loop setTitle: _NS("Repeat All")];
379     [_AtoBloop setTitle: _NS("A→B Loop")];
380     [_quitAfterPB setTitle: _NS("Quit after Playback")];
381     [_fwd setTitle: _NS("Step Forward")];
382     [_bwd setTitle: _NS("Step Backward")];
383     [_jumpToTime setTitle: _NS("Jump to Time")];
384     [_rendererMenuItem setTitle:_NS("Renderer")];
385     [_rendererNoneItem setTitle:_NS("No renderer")];
386     [_program setTitle: _NS("Program")];
387     [_programMenu setTitle: _NS("Program")];
388     [_title setTitle: _NS("Title")];
389     [_titleMenu setTitle: _NS("Title")];
390     [_chapter setTitle: _NS("Chapter")];
391     [_chapterMenu setTitle: _NS("Chapter")];
392
393     [_audioMenu setTitle: _NS("Audio")];
394     [_vol_up setTitle: _NS("Increase Volume")];
395     [_vol_down setTitle: _NS("Decrease Volume")];
396     [_mute setTitle: _NS("Mute")];
397     [_audiotrack setTitle: _NS("Audio Track")];
398     [_audiotrackMenu setTitle: _NS("Audio Track")];
399     [_channels setTitle: _NS("Stereo audio mode")];
400     [_channelsMenu setTitle: _NS("Stereo audio mode")];
401     [_audioDevice setTitle: _NS("Audio Device")];
402     [_audioDeviceMenu setTitle: _NS("Audio Device")];
403     [_visual setTitle: _NS("Visualizations")];
404     [_visualMenu setTitle: _NS("Visualizations")];
405
406     [_videoMenu setTitle: _NS("Video")];
407     [_half_window setTitle: _NS("Half Size")];
408     [_normal_window setTitle: _NS("Normal Size")];
409     [_double_window setTitle: _NS("Double Size")];
410     [_fittoscreen setTitle: _NS("Fit to Screen")];
411     [_fullscreenItem setTitle: _NS("Fullscreen")];
412     [_floatontop setTitle: _NS("Float on Top")];
413     [_snapshot setTitle: _NS("Snapshot")];
414     [_videotrack setTitle: _NS("Video Track")];
415     [_videotrackMenu setTitle: _NS("Video Track")];
416     [_aspect_ratio setTitle: _NS("Aspect ratio")];
417     [_aspect_ratioMenu setTitle: _NS("Aspect ratio")];
418     [_crop setTitle: _NS("Crop")];
419     [_cropMenu setTitle: _NS("Crop")];
420     [_screen setTitle: _NS("Fullscreen Video Device")];
421     [_screenMenu setTitle: _NS("Fullscreen Video Device")];
422     [_deinterlace setTitle: _NS("Deinterlace")];
423     [_deinterlaceMenu setTitle: _NS("Deinterlace")];
424     [_deinterlace_mode setTitle: _NS("Deinterlace mode")];
425     [_deinterlace_modeMenu setTitle: _NS("Deinterlace mode")];
426     [_postprocessing setTitle: _NS("Post processing")];
427     [_postprocessingMenu setTitle: _NS("Post processing")];
428
429     [_subtitlesMenu setTitle:_NS("Subtitles")];
430     [_openSubtitleFile setTitle: _NS("Add Subtitle File...")];
431     [_subtitle_track setTitle: _NS("Subtitles Track")];
432     [_subtitle_tracksMenu setTitle: _NS("Subtitles Track")];
433     [_subtitle_size setTitle: _NS("Text Size")];
434     [_subtitle_textcolor setTitle: _NS("Text Color")];
435     [_subtitle_outlinethickness setTitle: _NS("Outline Thickness")];
436
437     // Autoresizing with constraints does not work on 10.7,
438     // translate autoresizing mask to constriaints for now
439     [_subtitle_bgopacity_view setAutoresizingMask:NSViewWidthSizable];
440     [_subtitle_bgopacity setView: _subtitle_bgopacity_view];
441     [_subtitle_bgopacityLabel setStringValue: _NS("Background Opacity")];
442     [_subtitle_bgopacityLabel_gray setStringValue: _NS("Background Opacity")];
443     [_subtitle_bgcolor setTitle: _NS("Background Color")];
444     [_teletext setTitle: _NS("Teletext")];
445     [_teletext_transparent setTitle: _NS("Transparent")];
446     [_teletext_index setTitle: _NS("Index")];
447     [_teletext_red setTitle: _NS("Red")];
448     [_teletext_green setTitle: _NS("Green")];
449     [_teletext_yellow setTitle: _NS("Yellow")];
450     [_teletext_blue setTitle: _NS("Blue")];
451
452     [_windowMenu setTitle: _NS("Window")];
453     [_minimize setTitle: _NS("Minimize")];
454     [_zoom_window setTitle: _NS("Zoom")];
455     [_player setTitle: _NS("Player...")];
456     [_controller setTitle: _NS("Main Window...")];
457     [_audioeffects setTitle: _NS("Audio Effects...")];
458     [_videoeffects setTitle: _NS("Video Effects...")];
459     [_bookmarks setTitle: _NS("Bookmarks...")];
460     [_playlist setTitle: _NS("Playlist...")];
461     [_info setTitle: _NS("Media Information...")];
462     [_messages setTitle: _NS("Messages...")];
463     [_errorsAndWarnings setTitle: _NS("Errors and Warnings...")];
464
465     [_bring_atf setTitle: _NS("Bring All to Front")];
466
467     [_helpMenu setTitle: _NS("Help")];
468     [_help setTitle: _NS("VLC media player Help...")];
469     [_license setTitle: _NS("License")];
470     [_documentation setTitle: _NS("Online Documentation...")];
471     [_website setTitle: _NS("VideoLAN Website...")];
472     [_donation setTitle: _NS("Make a donation...")];
473     [_forum setTitle: _NS("Online Forum...")];
474
475     /* dock menu */
476     [_dockMenuplay setTitle: _NS("Play")];
477     [_dockMenustop setTitle: _NS("Stop")];
478     [_dockMenunext setTitle: _NS("Next")];
479     [_dockMenuprevious setTitle: _NS("Previous")];
480     [_dockMenumute setTitle: _NS("Mute")];
481
482     /* vout menu */
483     [_voutMenuplay setTitle: _NS("Play")];
484     [_voutMenustop setTitle: _NS("Stop")];
485     [_voutMenuprev setTitle: _NS("Previous")];
486     [_voutMenunext setTitle: _NS("Next")];
487     [_voutMenuvolup setTitle: _NS("Volume Up")];
488     [_voutMenuvoldown setTitle: _NS("Volume Down")];
489     [_voutMenumute setTitle: _NS("Mute")];
490     [_voutMenufullscreen setTitle: _NS("Fullscreen")];
491     [_voutMenusnapshot setTitle: _NS("Snapshot")];
492 }
493
494 - (void)setupKeyboardShortcuts
495 {
496     char *key;
497
498     key = config_GetPsz("key-quit");
499     [_quit setKeyEquivalent: VLCKeyToString(key)];
500     [_quit setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
501     FREENULL(key);
502
503     // do not assign play/pause key
504
505     key = config_GetPsz("key-stop");
506     [_stop setKeyEquivalent: VLCKeyToString(key)];
507     [_stop setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
508     FREENULL(key);
509
510     key = config_GetPsz("key-prev");
511     [_previous setKeyEquivalent: VLCKeyToString(key)];
512     [_previous setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
513     FREENULL(key);
514
515     key = config_GetPsz("key-next");
516     [_next setKeyEquivalent: VLCKeyToString(key)];
517     [_next setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
518     FREENULL(key);
519
520     key = config_GetPsz("key-jump+short");
521     [_fwd setKeyEquivalent: VLCKeyToString(key)];
522     [_fwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
523     FREENULL(key);
524
525     key = config_GetPsz("key-jump-short");
526     [_bwd setKeyEquivalent: VLCKeyToString(key)];
527     [_bwd setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
528     FREENULL(key);
529
530     key = config_GetPsz("key-vol-up");
531     [_vol_up setKeyEquivalent: VLCKeyToString(key)];
532     [_vol_up setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
533     FREENULL(key);
534
535     key = config_GetPsz("key-vol-down");
536     [_vol_down setKeyEquivalent: VLCKeyToString(key)];
537     [_vol_down setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
538     FREENULL(key);
539
540     key = config_GetPsz("key-vol-mute");
541     [_mute setKeyEquivalent: VLCKeyToString(key)];
542     [_mute setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
543     FREENULL(key);
544
545     key = config_GetPsz("key-toggle-fullscreen");
546     [_fullscreenItem setKeyEquivalent: VLCKeyToString(key)];
547     [_fullscreenItem setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
548     FREENULL(key);
549
550     key = config_GetPsz("key-snapshot");
551     [_snapshot setKeyEquivalent: VLCKeyToString(key)];
552     [_snapshot setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
553     FREENULL(key);
554
555     key = config_GetPsz("key-random");
556     [_random setKeyEquivalent: VLCKeyToString(key)];
557     [_random setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
558     FREENULL(key);
559
560     key = config_GetPsz("key-zoom-half");
561     [_half_window setKeyEquivalent: VLCKeyToString(key)];
562     [_half_window setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
563     FREENULL(key);
564
565     key = config_GetPsz("key-zoom-original");
566     [_normal_window setKeyEquivalent: VLCKeyToString(key)];
567     [_normal_window setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
568     FREENULL(key);
569
570     key = config_GetPsz("key-zoom-double");
571     [_double_window setKeyEquivalent: VLCKeyToString(key)];
572     [_double_window setKeyEquivalentModifierMask: VLCModifiersToCocoa(key)];
573     FREENULL(key);
574 }
575
576 #pragma mark - Termination
577
578 - (void)releaseRepresentedObjects:(NSMenu *)the_menu
579 {
580     NSArray *menuitems_array = [the_menu itemArray];
581     NSUInteger menuItemCount = [menuitems_array count];
582     for (NSUInteger i=0; i < menuItemCount; i++) {
583         NSMenuItem *one_item = [menuitems_array objectAtIndex:i];
584         if ([one_item hasSubmenu])
585             [self releaseRepresentedObjects: [one_item submenu]];
586
587         [one_item setRepresentedObject:NULL];
588     }
589 }
590
591 #pragma mark - Interface update
592
593 - (void)mediaItemChanged:(NSNotification *)aNotification
594 {
595     [self updateTrackHandlingMenus:aNotification];
596
597     input_item_t *p_mediaItem = _playerController.currentMedia;
598
599     if (p_mediaItem != NULL) {
600         audio_output_t *p_aout = [_playerController mainAudioOutput];
601         if (p_aout != NULL) {
602             [self setupVarMenuItem:_channels target:VLC_OBJECT(p_aout)
603                                var:"stereo-mode" selector:@selector(toggleVar:)];
604
605             [self setupVarMenuItem:_visual target:VLC_OBJECT(p_aout)
606                                var:"visual" selector:@selector(toggleVar:)];
607             aout_Release(p_aout);
608         }
609
610         vout_thread_t *p_vout = [_playerController videoOutputThreadForKeyWindow];
611         if (p_vout != NULL) {
612             [self setupVarMenuItem:_aspect_ratio target:VLC_OBJECT(p_vout)
613                                var:"aspect-ratio" selector: @selector(toggleVar:)];
614
615             [self setupVarMenuItem:_crop target:VLC_OBJECT(p_vout)
616                                var:"crop" selector: @selector(toggleVar:)];
617
618             [self setupVarMenuItem:_deinterlace target:VLC_OBJECT(p_vout)
619                                var:"deinterlace" selector: @selector(toggleVar:)];
620
621             [self setupVarMenuItem:_deinterlace_mode target:VLC_OBJECT(p_vout)
622                                var:"deinterlace-mode" selector: @selector(toggleVar:)];
623
624             vout_Release(p_vout);
625
626             [self refreshVoutDeviceMenu:nil];
627         }
628         [_postprocessing setEnabled:YES];
629         [self setSubmenusEnabled:YES];
630         input_item_Release(p_mediaItem);
631     } else {
632         [_postprocessing setEnabled:NO];
633         [self setSubmenusEnabled:NO];
634     }
635 }
636
637 - (void)refreshVoutDeviceMenu:(NSNotification *)notification
638 {
639     NSMenu *submenu = _screenMenu;
640     [submenu removeAllItems];
641
642     NSArray *screens = [NSScreen screens];
643     NSMenuItem *menuItem;
644     NSUInteger numberOfScreens = [screens count];
645     [_screen setEnabled: YES];
646     [submenu addItemWithTitle: _NS("Default") action:@selector(toggleFullscreenDevice:) keyEquivalent:@""];
647     menuItem = [submenu itemAtIndex: 0];
648     [menuItem setTag: 0];
649     [menuItem setEnabled: YES];
650     [menuItem setTarget: self];
651     NSRect s_rect;
652     for (NSUInteger i = 0; i < numberOfScreens; i++) {
653         s_rect = [[screens objectAtIndex:i] frame];
654         [submenu addItemWithTitle:[NSString stringWithFormat: @"%@ %li (%ix%i)", _NS("Screen"), i+1, (int)s_rect.size.width, (int)s_rect.size.height]
655                            action:@selector(toggleFullscreenDevice:)
656                     keyEquivalent:@""];
657         menuItem = [submenu itemAtIndex:i+1];
658         [menuItem setTag:(int)[[screens objectAtIndex:i] displayID]];
659         [menuItem setEnabled: YES];
660         [menuItem setTarget: self];
661     }
662     [[submenu itemWithTag: var_InheritInteger(getIntf(), "macosx-vdev")] setState: NSOnState];
663 }
664
665 - (void)setSubmenusEnabled:(BOOL)b_enabled
666 {
667     [_visual setEnabled: b_enabled];
668     [_channels setEnabled: b_enabled];
669     [_deinterlace setEnabled: b_enabled];
670     [_deinterlace_mode setEnabled: b_enabled];
671     [_screen setEnabled: b_enabled];
672     [_aspect_ratio setEnabled: b_enabled];
673     [_crop setEnabled: b_enabled];
674     [self setSubtitleMenuEnabled: b_enabled];
675 }
676
677 - (void)setSubtitleMenuEnabled:(BOOL)b_enabled
678 {
679     [_openSubtitleFile setEnabled: b_enabled];
680     if (b_enabled) {
681         [_subtitle_bgopacityLabel_gray setHidden: YES];
682         [_subtitle_bgopacityLabel setHidden: NO];
683     } else {
684         [_subtitle_bgopacityLabel_gray setHidden: NO];
685         [_subtitle_bgopacityLabel setHidden: YES];
686     }
687     [_subtitle_bgopacity_sld setEnabled: b_enabled];
688     [_teletext setEnabled:_playerController.teletextMenuAvailable];
689 }
690
691 - (void)setRateControlsEnabled:(BOOL)b_enabled
692 {
693     [_rate_sld setEnabled: b_enabled];
694     [self updatePlaybackRate];
695
696     NSColor *color = b_enabled ? [NSColor controlTextColor] : [NSColor disabledControlTextColor];
697
698     [_rateLabel setTextColor:color];
699     [_rate_slowerLabel setTextColor:color];
700     [_rate_normalLabel setTextColor:color];
701     [_rate_fasterLabel setTextColor:color];
702     [_rateTextField setTextColor:color];
703 }
704
705 #pragma mark - View
706
707 - (IBAction)toggleEffectsButton:(id)sender
708 {
709     BOOL b_value = !var_InheritBool(getIntf(), "macosx-show-effects-button");
710     config_PutInt("macosx-show-effects-button", b_value);
711     [(VLCMainWindowControlsBar *)[[[VLCMain sharedInstance] libraryWindow] controlsBar] toggleEffectsButton];
712     [_toggleEffectsButton setState: b_value];
713 }
714
715 - (IBAction)toggleJumpButtons:(id)sender
716 {
717     BOOL b_value = !var_InheritBool(getIntf(), "macosx-show-playback-buttons");
718     config_PutInt("macosx-show-playback-buttons", b_value);
719
720     [(VLCMainWindowControlsBar *)[[[VLCMain sharedInstance] libraryWindow] controlsBar] toggleJumpButtons];
721     [[[VLCMain sharedInstance] voutProvider] updateWindowsUsingBlock:^(VLCVideoWindowCommon *window) {
722         [[window controlsBar] toggleForwardBackwardMode: b_value];
723     }];
724
725     [_toggleJumpButtons setState: b_value];
726 }
727
728 - (IBAction)togglePlaymodeButtons:(id)sender
729 {
730     BOOL b_value = !var_InheritBool(getIntf(), "macosx-show-playmode-buttons");
731     config_PutInt("macosx-show-playmode-buttons", b_value);
732     [(VLCMainWindowControlsBar *)[[[VLCMain sharedInstance] libraryWindow] controlsBar] togglePlaymodeButtons];
733     [_togglePlaymodeButtons setState: b_value];
734 }
735
736 - (IBAction)toggleSidebar:(id)sender
737 {
738     // FIXME: remove this method as it is no longer needed
739 }
740
741 - (void)updateSidebarMenuItem:(BOOL)show;
742 {
743     [_toggleSidebar setState:show];
744 }
745
746 #pragma mark - Playback
747
748 - (IBAction)play:(id)sender
749 {
750     [_playerController togglePlayPause];
751 }
752
753 - (IBAction)stop:(id)sender
754 {
755     [_playerController stop];
756 }
757
758 - (IBAction)prev:(id)sender
759 {
760     [_playlistController playPreviousItem];
761 }
762
763 - (IBAction)next:(id)sender
764 {
765     [_playlistController playNextItem];
766 }
767
768 - (IBAction)random:(id)sender
769 {
770     if (_playlistController.playbackOrder == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM) {
771         _playlistController.playbackOrder = VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL;
772     } else {
773         _playlistController.playbackOrder = VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM;
774     }
775 }
776
777 - (IBAction)repeat:(id)sender
778 {
779     if (_playlistController.playbackRepeat == VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT) {
780         _playlistController.playbackRepeat = VLC_PLAYLIST_PLAYBACK_REPEAT_NONE;
781     } else {
782         _playlistController.playbackRepeat = VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT;
783     }
784 }
785
786 - (IBAction)loop:(id)sender
787 {
788     if (_playlistController.playbackRepeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL) {
789         _playlistController.playbackRepeat = VLC_PLAYLIST_PLAYBACK_REPEAT_NONE;
790     } else {
791         _playlistController.playbackRepeat = VLC_PLAYLIST_PLAYBACK_REPEAT_ALL;
792     }
793 }
794
795 - (IBAction)forward:(id)sender
796 {
797     [_playerController jumpForwardShort];
798 }
799
800 - (IBAction)backward:(id)sender
801 {
802     [_playerController jumpBackwardShort];
803 }
804
805 - (IBAction)volumeUp:(id)sender
806 {
807     [_playerController incrementVolume];
808 }
809
810 - (IBAction)volumeDown:(id)sender
811 {
812     [_playerController decrementVolume];
813 }
814
815 - (IBAction)mute:(id)sender
816 {
817     [_playerController toggleMute];
818 }
819
820 - (void)lockVideosAspectRatio:(id)sender
821 {
822     // FIXME: re-write the following using VLCPlayerController
823     [_playerController setAspectRatioIsLocked: ![sender state]];
824     [sender setState: [_playerController aspectRatioIsLocked]];
825 }
826
827 - (IBAction)quitAfterPlayback:(id)sender
828 {
829     if (_playerController.actionAfterStop != VLC_PLAYER_MEDIA_STOPPED_EXIT) {
830         _playerController.actionAfterStop = VLC_PLAYER_MEDIA_STOPPED_EXIT;
831     } else {
832         _playerController.actionAfterStop = VLC_PLAYER_MEDIA_STOPPED_CONTINUE;
833     }
834 }
835
836 - (IBAction)toggleRecord:(id)sender
837 {
838     [_playerController toggleRecord];
839 }
840
841 - (void)updateRecordState
842 {
843     [_record setState:_playerController.enableRecording];
844 }
845
846 - (IBAction)setPlaybackRate:(id)sender
847 {
848     double speed =  pow(2, (double)[_rate_sld intValue] / 17);
849     _playerController.playbackRate = speed;
850     [_rateTextField setStringValue: [NSString stringWithFormat:@"%.2fx", speed]];
851 }
852
853 - (void)updatePlaybackRate
854 {
855     double playbackRate = _playerController.playbackRate;
856     double value = 17 * log(playbackRate) / log(2.);
857     int intValue = (int) ((value > 0) ? value + .5 : value - .5);
858
859     if (intValue < -34)
860         intValue = -34;
861     else if (intValue > 34)
862         intValue = 34;
863
864     [_rateTextField setStringValue: [NSString stringWithFormat:@"%.2fx", playbackRate]];
865     [_rate_sld setIntValue: intValue];
866 }
867
868 - (IBAction)toggleAtoBloop:(id)sender
869 {
870     [_playerController setABLoop];
871 }
872
873 - (IBAction)goToSpecificTime:(id)sender
874 {
875     vlc_tick_t length = _playerController.length;
876     [_timeSelectionPanel setMaxTime:(int)SEC_FROM_VLC_TICK(length)];
877     vlc_tick_t time = _playerController.time;
878     [_timeSelectionPanel setPosition:(int)SEC_FROM_VLC_TICK(time)];
879     [_timeSelectionPanel runModalForWindow:[NSApp mainWindow]
880                          completionHandler:^(NSInteger returnCode, int64_t returnTime) {
881                              if (returnCode != NSModalResponseOK)
882                                  return;
883                              [self->_playerController setTimePrecise:vlc_tick_from_sec(returnTime)];
884                          }];
885 }
886
887 - (IBAction)selectRenderer:(id)sender
888 {
889     [_rendererMenuController selectRenderer:sender];
890 }
891
892 #pragma mark - track handling
893 - (void)updateTrackHandlingMenus:(NSNotification *)aNotification
894 {
895     NSArray *tracks = _playerController.audioTracks;
896     NSUInteger numberOfTracks = tracks.count;
897     [self rebuildTracksMenu:_audiotrackMenu withMetadata:tracks count:numberOfTracks category:AUDIO_ES];
898     _audiotrack.enabled = numberOfTracks > 0 ? YES : NO;
899
900     tracks = _playerController.videoTracks;
901     numberOfTracks = tracks.count;
902     [self rebuildTracksMenu:_videotrackMenu withMetadata:tracks count:numberOfTracks category:VIDEO_ES];
903     _videotrack.enabled = numberOfTracks > 0 ? YES : NO;
904
905     tracks = _playerController.subtitleTracks;
906     numberOfTracks = tracks.count;
907     [self rebuildTracksMenu:_subtitle_tracksMenu withMetadata:tracks count:numberOfTracks category:SPU_ES];
908     _subtitle_track.enabled = numberOfTracks > 0 ? YES : NO;
909 }
910
911 - (void)rebuildTracksMenu:(NSMenu *)menu
912              withMetadata:(NSArray *)metadataArray
913                     count:(size_t)count
914                  category:(enum es_format_category_e)category
915 {
916     [menu removeAllItems];
917
918     NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:_NS("Disable")
919                                                       action:@selector(unselectTrackCategory:)
920                                                keyEquivalent:@""];
921     [menuItem setTarget:self];
922     [menuItem setTag:category];
923     [menuItem setEnabled:YES];
924     [menu addItem:menuItem];
925
926     for (NSUInteger x = 0; x < count; x++) {
927         VLCTrackMetaData *metaDataItem = metadataArray[x];
928         menuItem = [[NSMenuItem alloc] initWithTitle:metaDataItem.name
929                                               action:@selector(selectTrack:)
930                                        keyEquivalent:@""];
931         [menuItem setTarget:self];
932         [menuItem setRepresentedObject:metaDataItem];
933         [menuItem setEnabled:YES];
934         [menuItem setState:metaDataItem.selected ? NSOnState : NSOffState];
935         [menu addItem:menuItem];
936     }
937 }
938
939 - (void)selectTrack:(NSMenuItem *)sender
940 {
941     [_playerController selectTrack:[sender representedObject]];
942 }
943
944 - (void)unselectTrackCategory:(NSMenuItem *)sender
945 {
946     [_playerController unselectTracksFromCategory:(enum es_format_category_e)sender.tag];
947 }
948
949 #pragma mark - title and chapter handling
950 - (void)updateTitleAndChapterMenus:(NSNotification *)aNotification
951 {
952     [_titleMenu removeAllItems];
953     [_chapterMenu removeAllItems];
954
955     size_t count = [_playerController numberOfTitlesOfCurrentMedia];
956     size_t selectedIndex = [_playerController selectedTitleIndex];
957     for (size_t x = 0; x < count; x++) {
958         const struct vlc_player_title *p_title = [_playerController titleAtIndexForCurrentMedia:x];
959         if (p_title == NULL) {
960             break;
961         }
962         NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:toNSStr(p_title->name)
963                                                           action:@selector(selectTitle:)
964                                                    keyEquivalent:@""];
965         [menuItem setTarget:self];
966         [menuItem setTag:x];
967         [menuItem setEnabled:YES];
968         [menuItem setState: x == selectedIndex ? NSOnState : NSOffState];
969         [_titleMenu addItem:menuItem];
970     }
971     _title.enabled = count > 0 ? YES : NO;
972
973     count = [_playerController numberOfChaptersForCurrentTitle];
974     selectedIndex = [_playerController selectedChapterIndex];
975     for (size_t x = 0; x < count; x++) {
976         const struct vlc_player_chapter *p_chapter = [_playerController chapterAtIndexForCurrentTitle:x];
977         if (p_chapter == NULL) {
978             break;
979         }
980         NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:toNSStr(p_chapter->name)
981                                                           action:@selector(selectChapter:)
982                                                    keyEquivalent:@""];
983         [menuItem setTarget:self];
984         [menuItem setTag:x];
985         [menuItem setEnabled:YES];
986         [menuItem setState: x == selectedIndex ? NSOnState : NSOffState];
987         [_chapterMenu addItem:menuItem];
988     }
989     _chapter.enabled = count > 0 ? YES : NO;
990 }
991
992 - (void)selectTitle:(NSMenuItem *)sender
993 {
994     _playerController.selectedTitleIndex = [sender tag];
995 }
996
997 - (void)selectChapter:(NSMenuItem *)sender
998 {
999     _playerController.selectedChapterIndex = [sender tag];
1000 }
1001
1002 #pragma mark - program handling
1003 - (void)updateProgramMenu:(NSNotification *)notification
1004 {
1005     [_programMenu removeAllItems];
1006
1007     size_t count = [_playerController numberOfPrograms];
1008     for (size_t x = 0; x < count; x++) {
1009         VLCProgramMetaData *program = [_playerController programAtIndex:x];
1010         if (program == nil) {
1011             break;
1012         }
1013         NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:program.name
1014                                                           action:@selector(selectProgram:)
1015                                                    keyEquivalent:@""];
1016         [menuItem setTarget:self];
1017         [menuItem setRepresentedObject:program];
1018         [menuItem setEnabled:YES];
1019         [menuItem setState:program.selected ? NSOnState : NSOffState];
1020         [_programMenu addItem:menuItem];
1021     }
1022     _program.enabled = count > 0 ? YES : NO;
1023 }
1024
1025 - (void)selectProgram:(NSMenuItem *)sender
1026 {
1027     [_playerController selectProgram:[sender representedObject]];
1028 }
1029
1030 #pragma mark - audio menu
1031
1032 - (void)refreshAudioDeviceList
1033 {
1034     char **ids, **names;
1035     char *currentDevice;
1036
1037     [_audioDeviceMenu removeAllItems];
1038
1039     audio_output_t *p_aout = [_playerController mainAudioOutput];
1040     if (!p_aout)
1041         return;
1042
1043     int numberOfAudioDevices = aout_DevicesList(p_aout, &ids, &names);
1044     if (numberOfAudioDevices == -1) {
1045         aout_Release(p_aout);
1046         return;
1047     }
1048
1049     currentDevice = aout_DeviceGet(p_aout);
1050     NSMenuItem *_tmp;
1051
1052     for (NSUInteger x = 0; x < numberOfAudioDevices; x++) {
1053         _tmp = [_audioDeviceMenu addItemWithTitle:toNSStr(names[x]) action:@selector(toggleAudioDevice:) keyEquivalent:@""];
1054         [_tmp setTarget:self];
1055         [_tmp setTag:[[NSString stringWithFormat:@"%s", ids[x]] intValue]];
1056     }
1057     aout_Release(p_aout);
1058
1059     [[_audioDeviceMenu itemWithTag:[[NSString stringWithFormat:@"%s", currentDevice] intValue]] setState:NSOnState];
1060
1061     free(currentDevice);
1062
1063     for (NSUInteger x = 0; x < numberOfAudioDevices; x++) {
1064         free(ids[x]);
1065         free(names[x]);
1066     }
1067     free(ids);
1068     free(names);
1069
1070     [_audioDeviceMenu setAutoenablesItems:YES];
1071     [_audioDevice setEnabled:YES];
1072 }
1073
1074 - (void)toggleAudioDevice:(id)sender
1075 {
1076     audio_output_t *p_aout = [_playerController mainAudioOutput];
1077     if (!p_aout)
1078         return;
1079
1080     int returnValue = 0;
1081
1082     if ([sender tag] > 0)
1083         returnValue = aout_DeviceSet(p_aout, [[NSString stringWithFormat:@"%li", [sender tag]] UTF8String]);
1084     else
1085         returnValue = aout_DeviceSet(p_aout, NULL);
1086
1087     if (returnValue != 0)
1088         msg_Warn(getIntf(), "failed to set audio device %li", [sender tag]);
1089
1090     aout_Release(p_aout);
1091     [self refreshAudioDeviceList];
1092 }
1093
1094 #pragma mark - video menu
1095
1096 - (IBAction)toggleFullscreen:(id)sender
1097 {
1098     [_playerController toggleFullscreen];
1099 }
1100
1101 - (IBAction)resizeVideoWindow:(id)sender
1102 {
1103     vout_thread_t *p_vout = [_playerController videoOutputThreadForKeyWindow];
1104     if (p_vout) {
1105         if (sender == _half_window)
1106             var_SetFloat(p_vout, "zoom", 0.5);
1107         else if (sender == _normal_window)
1108             var_SetFloat(p_vout, "zoom", 1.0);
1109         else if (sender == _double_window)
1110             var_SetFloat(p_vout, "zoom", 2.0);
1111         else
1112         {
1113             [[NSApp keyWindow] performZoom:sender];
1114         }
1115         vout_Release(p_vout);
1116     }
1117 }
1118
1119 - (IBAction)floatOnTop:(id)sender
1120 {
1121     vout_thread_t *p_vout = [_playerController videoOutputThreadForKeyWindow];
1122     if (p_vout) {
1123         var_ToggleBool(p_vout, "video-on-top");
1124         vout_Release(p_vout);
1125     }
1126 }
1127
1128 - (IBAction)createVideoSnapshot:(id)sender
1129 {
1130     [_playerController takeSnapshot];
1131 }
1132
1133 - (void)_disablePostProcessing
1134 {
1135     // FIXME re-write using VLCPlayerController
1136     [VLCVideoFilterHelper setVideoFilter:"postproc" on:false];
1137 }
1138
1139 - (void)_enablePostProcessing
1140 {
1141     // FIXME re-write using VLCPlayerController
1142     [VLCVideoFilterHelper setVideoFilter:"postproc" on:true];
1143 }
1144
1145 - (void)togglePostProcessing:(id)sender
1146 {
1147     // FIXME re-write using VLCPlayerController
1148     NSInteger count = [_postprocessingMenu numberOfItems];
1149     for (NSUInteger x = 0; x < count; x++)
1150         [[_postprocessingMenu itemAtIndex:x] setState:NSOffState];
1151
1152     if ([sender tag] == -1) {
1153         [self _disablePostProcessing];
1154         [sender setState:NSOnState];
1155     } else {
1156         [self _enablePostProcessing];
1157         [sender setState:NSOnState];
1158
1159         [VLCVideoFilterHelper setVideoFilterProperty:"postproc-q" forFilter:"postproc" withValue:(vlc_value_t){ .i_int = [sender tag] }];
1160     }
1161 }
1162
1163 - (void)toggleFullscreenDevice:(id)sender
1164 {
1165     config_PutInt("macosx-vdev", [sender tag]);
1166     [self refreshVoutDeviceMenu: nil];
1167 }
1168
1169 #pragma mark - Subtitles Menu
1170
1171 - (IBAction)addSubtitleFile:(id)sender
1172 {
1173     NSInteger i_returnValue = 0;
1174
1175     NSOpenPanel *openPanel = [NSOpenPanel openPanel];
1176     [openPanel setCanChooseFiles: YES];
1177     [openPanel setCanChooseDirectories: NO];
1178     [openPanel setAllowsMultipleSelection: YES];
1179
1180     [openPanel setAllowedFileTypes: [NSArray arrayWithObjects:@"cdg",@"idx",@"srt",@"sub",@"utf",@"ass",@"ssa",@"aqt",@"jss",@"psb",@"rt",@"smi",@"txt",@"smil",@"stl",@"usf",@"dks",@"pjs",@"mpl2",@"mks",@"vtt",@"ttml",@"dfxp",nil]];
1181
1182     NSURL *url = _playerController.URLOfCurrentMediaItem;
1183     url = [url URLByDeletingLastPathComponent];
1184     [openPanel setDirectoryURL: url];
1185
1186     i_returnValue = [openPanel runModal];
1187
1188     if (i_returnValue == NSModalResponseOK) {
1189         NSArray *URLs = [openPanel URLs];
1190         NSUInteger count = [URLs count];
1191         for (int i = 0; i < count ; i++) {
1192             NSURL *url = URLs[i];
1193             [_playerController addAssociatedMediaToCurrentFromURL:url
1194                                                        ofCategory:SPU_ES
1195                                                  shallSelectTrack:YES
1196                                                   shallDisplayOSD:YES
1197                                              shallVerifyExtension:NO];
1198         }
1199     }
1200 }
1201
1202 - (void)switchSubtitleSize:(id)sender
1203 {
1204     _playerController.subtitleTextScalingFactor = (unsigned int)[sender tag];
1205 }
1206
1207 - (void)switchSubtitleOption:(id)sender
1208 {
1209     NSInteger intValue = [sender tag];
1210     NSString *representedObject = [sender representedObject];
1211
1212     var_SetInteger(VLC_OBJECT(getIntf()), [representedObject UTF8String], intValue);
1213
1214     NSMenu *menu = [sender menu];
1215     NSUInteger count = (NSUInteger) [menu numberOfItems];
1216     for (NSUInteger x = 0; x < count; x++)
1217         [[menu itemAtIndex:x] setState:NSOffState];
1218     [[menu itemWithTag:intValue] setState:NSOnState];
1219 }
1220
1221 - (IBAction)switchSubtitleBackgroundOpacity:(id)sender
1222 {
1223     var_SetInteger(VLC_OBJECT(getIntf()), "freetype-background-opacity", [sender intValue]);
1224 }
1225
1226 - (IBAction)telxTransparent:(id)sender
1227 {
1228     _playerController.teletextTransparent = !_playerController.teletextTransparent;
1229 }
1230
1231 - (IBAction)telxNavLink:(id)sender
1232 {
1233     unsigned int page = 0;
1234
1235     if ([[sender title] isEqualToString: _NS("Index")])
1236         page = VLC_PLAYER_TELETEXT_KEY_INDEX;
1237     else if ([[sender title] isEqualToString: _NS("Red")])
1238         page = VLC_PLAYER_TELETEXT_KEY_RED;
1239     else if ([[sender title] isEqualToString: _NS("Green")])
1240         page = VLC_PLAYER_TELETEXT_KEY_GREEN;
1241     else if ([[sender title] isEqualToString: _NS("Yellow")])
1242         page = VLC_PLAYER_TELETEXT_KEY_YELLOW;
1243     else if ([[sender title] isEqualToString: _NS("Blue")])
1244         page = VLC_PLAYER_TELETEXT_KEY_BLUE;
1245
1246     _playerController.teletextPage = page;
1247 }
1248
1249 #pragma mark - Panels
1250
1251 - (IBAction)intfOpenFile:(id)sender
1252 {
1253     [[[VLCMain sharedInstance] open] openFileWithAction:^(NSArray *files) {
1254         [self->_playlistController addPlaylistItems:files];
1255     }];
1256 }
1257
1258 - (IBAction)intfOpenFileGeneric:(id)sender
1259 {
1260     [[[VLCMain sharedInstance] open] openFileGeneric];
1261 }
1262
1263 - (IBAction)intfOpenDisc:(id)sender
1264 {
1265     [[[VLCMain sharedInstance] open] openDisc];
1266 }
1267
1268 - (IBAction)intfOpenNet:(id)sender
1269 {
1270     [[[VLCMain sharedInstance] open] openNet];
1271 }
1272
1273 - (IBAction)intfOpenCapture:(id)sender
1274 {
1275     [[[VLCMain sharedInstance] open] openCapture];
1276 }
1277
1278 - (IBAction)savePlaylist:(id)sender
1279 {
1280     static dispatch_once_t once;
1281     dispatch_once(&once, ^{
1282         [[NSBundle mainBundle] loadNibNamed:@"PlaylistAccessoryView" owner:self topLevelObjects:nil];
1283     });
1284
1285     [_playlistSaveAccessoryText setStringValue: _NS("File Format:")];
1286     [_playlistSaveAccessoryPopup removeAllItems];
1287
1288     NSArray *availableExportModules = _playlistController.availablePlaylistExportModules;
1289     NSUInteger count = availableExportModules.count;
1290     NSMutableArray *allowedFileTypes = [NSMutableArray arrayWithCapacity:count];
1291     for (NSUInteger x = 0; x < count; x++) {
1292         VLCPlaylistExportModuleDescription *exportModule = availableExportModules[x];
1293         [_playlistSaveAccessoryPopup addItemWithTitle:exportModule.humanReadableName];
1294         [allowedFileTypes addObject:exportModule.fileExtension];
1295     }
1296
1297     NSSavePanel *savePanel = [NSSavePanel savePanel];
1298     [savePanel setTitle: _NS("Save Playlist")];
1299     [savePanel setPrompt: _NS("Save")];
1300     [savePanel setAccessoryView: _playlistSaveAccessoryView];
1301     [savePanel setNameFieldStringValue: _NS("Untitled")];
1302     [savePanel setAllowedFileTypes:allowedFileTypes];
1303     [savePanel setCanSelectHiddenExtension:YES];
1304
1305     if ([savePanel runModal] == NSFileHandlingPanelOKButton) {
1306         NSString *filename = [[savePanel URL] path];
1307         VLCPlaylistExportModuleDescription *exportModule = availableExportModules[[_playlistSaveAccessoryPopup indexOfSelectedItem]];
1308
1309         if ([[filename pathExtension] caseInsensitiveCompare:exportModule.fileExtension] != NSOrderedSame) {
1310             filename = [filename stringByAppendingPathExtension:exportModule.fileExtension];
1311         }
1312
1313         [_playlistController exportPlaylistToPath:filename exportModule:exportModule];
1314     }
1315 }
1316
1317 - (IBAction)showConvertAndSave:(id)sender
1318 {
1319     [[[VLCMain sharedInstance] convertAndSaveWindow] showWindow:self];
1320 }
1321
1322 - (IBAction)showVideoEffects:(id)sender
1323 {
1324     [[[VLCMain sharedInstance] videoEffectsPanel] toggleWindow:sender];
1325 }
1326
1327 - (IBAction)showTrackSynchronization:(id)sender
1328 {
1329     [[[VLCMain sharedInstance] trackSyncPanel] toggleWindow:sender];
1330 }
1331
1332 - (IBAction)showAudioEffects:(id)sender
1333 {
1334     [[[VLCMain sharedInstance] audioEffectsPanel] toggleWindow:sender];
1335 }
1336
1337 - (IBAction)showBookmarks:(id)sender
1338 {
1339     [[[VLCMain sharedInstance] bookmarks] toggleWindow:sender];
1340 }
1341
1342 - (IBAction)showPreferences:(id)sender
1343 {
1344     VLCMain *mainInstance = [VLCMain sharedInstance];
1345     NSInteger i_level = [[mainInstance voutProvider] currentStatusWindowLevel];
1346     [[mainInstance simplePreferences] showSimplePrefsWithLevel:i_level];
1347 }
1348
1349 - (IBAction)openAddonManager:(id)sender
1350 {
1351     if (!_addonsController)
1352         _addonsController = [[VLCAddonsWindowController alloc] init];
1353
1354     [_addonsController showWindow:self];
1355 }
1356
1357 - (IBAction)showErrorsAndWarnings:(id)sender
1358 {
1359     [[[[VLCMain sharedInstance] coreDialogProvider] errorPanel] showWindow:self];
1360 }
1361
1362 - (IBAction)showMessagesPanel:(id)showMessagesPanel
1363 {
1364     [[[VLCMain sharedInstance] debugMsgPanel] showWindow:self];
1365 }
1366
1367 - (IBAction)showMainWindow:(id)sender
1368 {
1369     [[[VLCMain sharedInstance] libraryWindow] makeKeyAndOrderFront:sender];
1370 }
1371
1372 - (IBAction)showPlaylist:(id)sender
1373 {
1374     [[[[VLCMain sharedInstance] libraryWindowController] window] makeKeyAndOrderFront:sender];
1375 }
1376
1377 #pragma mark - Help and Docs
1378
1379 - (IBAction)showAbout:(id)sender
1380 {
1381     if (!_aboutWindowController)
1382         _aboutWindowController = [[VLCAboutWindowController alloc] init];
1383
1384     [_aboutWindowController showAbout];
1385 }
1386
1387 - (IBAction)showLicense:(id)sender
1388 {
1389     if (!_aboutWindowController)
1390         _aboutWindowController = [[VLCAboutWindowController alloc] init];
1391
1392     [_aboutWindowController showGPL];
1393 }
1394
1395 - (IBAction)showHelp:(id)sender
1396 {
1397     if (!_helpWindowController)
1398         _helpWindowController = [[VLCHelpWindowController alloc] init];
1399
1400     [_helpWindowController showHelp];
1401 }
1402
1403 - (IBAction)openDocumentation:(id)sender
1404 {
1405     NSURL *url = [NSURL URLWithString: @"http://www.videolan.org/doc/"];
1406
1407     [[NSWorkspace sharedWorkspace] openURL: url];
1408 }
1409
1410 - (IBAction)openWebsite:(id)sender
1411 {
1412     NSURL *url = [NSURL URLWithString: @"http://www.videolan.org/"];
1413
1414     [[NSWorkspace sharedWorkspace] openURL: url];
1415 }
1416
1417 - (IBAction)openForum:(id)sender
1418 {
1419     NSURL *url = [NSURL URLWithString: @"http://forum.videolan.org/"];
1420
1421     [[NSWorkspace sharedWorkspace] openURL: url];
1422 }
1423
1424 - (IBAction)openDonate:(id)sender
1425 {
1426     NSURL *url = [NSURL URLWithString: @"http://www.videolan.org/contribute.html#paypal"];
1427
1428     [[NSWorkspace sharedWorkspace] openURL: url];
1429 }
1430
1431 - (IBAction)showInformationPanel:(id)sender
1432 {
1433     [[[VLCMain sharedInstance] currentMediaInfoPanel] toggleWindow:sender];
1434 }
1435
1436 #pragma mark - playback state
1437
1438 - (void)playbackStateChanged:(NSNotification *)aNotification
1439 {
1440     enum vlc_player_state playerState = [_playlistController playerController].playerState;
1441     if (playerState == VLC_PLAYER_STATE_PLAYING) {
1442         [self setPause];
1443     } else {
1444         [self setPlay];
1445     }
1446 }
1447
1448 - (void)playModeChanged:(NSNotification *)aNotification
1449 {
1450     enum vlc_playlist_playback_repeat repeatState = _playlistController.playbackRepeat;
1451     switch (repeatState) {
1452         case VLC_PLAYLIST_PLAYBACK_REPEAT_ALL:
1453             [self setRepeatAll];
1454             break;
1455
1456         case VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT:
1457             [self setRepeatOne];
1458             break;
1459
1460         default:
1461             [self setRepeatOff];
1462             break;
1463     }
1464 }
1465
1466 - (void)playOrderChanged:(NSNotification *)aNotification
1467 {
1468     [_random setState:_playlistController.playbackOrder == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM];
1469 }
1470
1471 - (void)setPlay
1472 {
1473     [_play setTitle: _NS("Play")];
1474     [_dockMenuplay setTitle: _NS("Play")];
1475     [_voutMenuplay setTitle: _NS("Play")];
1476 }
1477
1478 - (void)setPause
1479 {
1480     [_play setTitle: _NS("Pause")];
1481     [_dockMenuplay setTitle: _NS("Pause")];
1482     [_voutMenuplay setTitle: _NS("Pause")];
1483 }
1484
1485 - (void)setRepeatOne
1486 {
1487     [_repeat setState: NSOnState];
1488     [_loop setState: NSOffState];
1489 }
1490
1491 - (void)setRepeatAll
1492 {
1493     [_repeat setState: NSOffState];
1494     [_loop setState: NSOnState];
1495 }
1496
1497 - (void)setRepeatOff
1498 {
1499     [_repeat setState: NSOffState];
1500     [_loop setState: NSOffState];
1501 }
1502
1503 #pragma mark - Dynamic menu creation and validation
1504
1505 - (void)setupVarMenuItem:(NSMenuItem *)menuItem
1506                   target:(vlc_object_t *)p_object
1507                      var:(const char *)psz_variable
1508                 selector:(SEL)pf_callback
1509 {
1510     vlc_value_t val;
1511     char *text;
1512     int i_type = var_Type(p_object, psz_variable);
1513
1514     switch(i_type & VLC_VAR_TYPE) {
1515         case VLC_VAR_VOID:
1516         case VLC_VAR_BOOL:
1517         case VLC_VAR_STRING:
1518         case VLC_VAR_INTEGER:
1519             break;
1520         default:
1521             /* Variable doesn't exist or isn't handled */
1522             msg_Warn(p_object, "variable %s doesn't exist or isn't handled", psz_variable);
1523             return;
1524     }
1525
1526     /* Get the descriptive name of the variable */
1527     var_Change(p_object, psz_variable, VLC_VAR_GETTEXT, &text);
1528     [menuItem setTitle: _NS(text ? text : psz_variable)];
1529
1530     if (i_type & VLC_VAR_HASCHOICE) {
1531         NSMenu *menu = [menuItem submenu];
1532
1533         [self setupVarMenu:menu
1534                forMenuItem:menuItem
1535                     target:p_object
1536                        var:psz_variable
1537                   selector:pf_callback];
1538
1539         free(text);
1540         return;
1541     }
1542
1543     if (var_Get(p_object, psz_variable, &val) < 0)
1544         return;
1545
1546     VLCAutoGeneratedMenuContent *data;
1547     switch(i_type & VLC_VAR_TYPE) {
1548         case VLC_VAR_VOID:
1549             data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName:psz_variable
1550                                                                     ofObject:p_object
1551                                                                     andValue:val
1552                                                                       ofType:i_type];
1553             [menuItem setRepresentedObject:data];
1554             break;
1555
1556         case VLC_VAR_BOOL:
1557             data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName:psz_variable
1558                                                                     ofObject:p_object
1559                                                                     andValue:val
1560                                                                       ofType:i_type];
1561             [menuItem setRepresentedObject:data];
1562             if (!(i_type & VLC_VAR_ISCOMMAND))
1563                 [menuItem setState:val.b_bool ? NSOnState : NSOffState];
1564             break;
1565
1566         default:
1567             break;
1568     }
1569
1570     if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING)
1571         free(val.psz_string);
1572     free(text);
1573 }
1574
1575
1576 - (void)setupVarMenu:(NSMenu *)menu
1577          forMenuItem:(NSMenuItem *)parent
1578               target:(vlc_object_t *)p_object
1579                  var:(const char *)psz_variable
1580             selector:(SEL)pf_callback
1581 {
1582     vlc_value_t val;
1583     vlc_value_t *val_list;
1584     char **text_list;
1585     size_t count, i;
1586     int i_type;
1587
1588     /* remove previous items */
1589     [menu removeAllItems];
1590
1591     /* we disable everything here, and enable it again when needed, below */
1592     [parent setEnabled:NO];
1593
1594     /* Aspect Ratio */
1595     if ([[parent title] isEqualToString: _NS("Aspect ratio")] == YES) {
1596         NSMenuItem *lmi_tmp2;
1597         lmi_tmp2 = [menu addItemWithTitle: _NS("Lock Aspect Ratio") action: @selector(lockVideosAspectRatio:) keyEquivalent: @""];
1598         [lmi_tmp2 setTarget: self];
1599         [lmi_tmp2 setEnabled: YES];
1600         [lmi_tmp2 setState: [_playerController aspectRatioIsLocked]];
1601         [parent setEnabled: YES];
1602         [menu addItem: [NSMenuItem separatorItem]];
1603     }
1604
1605     /* Check the type of the object variable */
1606     i_type = var_Type(p_object, psz_variable);
1607
1608     /* Make sure we want to display the variable */
1609     if (i_type & VLC_VAR_HASCHOICE) {
1610         size_t count;
1611
1612         var_Change(p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &count);
1613         if (count <= 1)
1614             return;
1615     }
1616     else
1617         return;
1618
1619     switch(i_type & VLC_VAR_TYPE) {
1620         case VLC_VAR_VOID:
1621         case VLC_VAR_BOOL:
1622         case VLC_VAR_STRING:
1623         case VLC_VAR_INTEGER:
1624             break;
1625         default:
1626             /* Variable doesn't exist or isn't handled */
1627             return;
1628     }
1629
1630     if (var_Get(p_object, psz_variable, &val) < 0) {
1631         return;
1632     }
1633
1634     if (var_Change(p_object, psz_variable, VLC_VAR_GETCHOICES,
1635                    &count, &val_list, &text_list) < 0) {
1636         if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING) free(val.psz_string);
1637         return;
1638     }
1639
1640     /* make (un)sensitive */
1641     [parent setEnabled:(count > 1)];
1642
1643     for (i = 0; i < count; i++) {
1644         NSMenuItem *lmi;
1645         NSString *title = @"";
1646         VLCAutoGeneratedMenuContent *data;
1647
1648         switch(i_type & VLC_VAR_TYPE) {
1649             case VLC_VAR_STRING:
1650
1651                 title = _NS(text_list[i] ? text_list[i] : val_list[i].psz_string);
1652
1653                 lmi = [menu addItemWithTitle:title action:pf_callback keyEquivalent:@""];
1654                 data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName:psz_variable
1655                                                                         ofObject:p_object
1656                                                                         andValue:val_list[i]
1657                                                                           ofType:i_type];
1658                 [lmi setRepresentedObject:data];
1659                 [lmi setTarget:self];
1660
1661                 if (!strcmp(val.psz_string, val_list[i].psz_string) && !(i_type & VLC_VAR_ISCOMMAND))
1662                     [lmi setState:NSOnState];
1663
1664                 free(text_list[i]);
1665                 free(val_list[i].psz_string);
1666                 break;
1667
1668             case VLC_VAR_INTEGER:
1669
1670                 title = text_list[i] ?
1671                 _NS(text_list[i]) : [NSString stringWithFormat:@"%"PRId64, val_list[i].i_int];
1672
1673                 lmi = [menu addItemWithTitle: title action: pf_callback keyEquivalent: @""];
1674                 data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName:psz_variable
1675                                                                         ofObject:p_object
1676                                                                         andValue:val_list[i]
1677                                                                           ofType:i_type];
1678                 [lmi setRepresentedObject:data];
1679                 [lmi setTarget:self];
1680
1681                 if (val_list[i].i_int == val.i_int && !(i_type & VLC_VAR_ISCOMMAND))
1682                     [lmi setState:NSOnState];
1683
1684                 free(text_list[i]);
1685                 break;
1686
1687             default:
1688                 break;
1689         }
1690     }
1691
1692     /* clean up everything */
1693     if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING) free(val.psz_string);
1694     free(text_list);
1695     free(val_list);
1696 }
1697
1698 - (void)toggleVar:(id)sender
1699 {
1700     NSMenuItem *mi = (NSMenuItem *)sender;
1701     VLCAutoGeneratedMenuContent *data = [mi representedObject];
1702     [NSThread detachNewThreadSelector:@selector(toggleVarThread:)
1703                              toTarget:self
1704                            withObject:data];
1705
1706     return;
1707 }
1708
1709 - (void)toggleVarThread:(id)data
1710 {
1711     @autoreleasepool {
1712         vlc_object_t *p_object;
1713
1714         assert([data isKindOfClass:[VLCAutoGeneratedMenuContent class]]);
1715         VLCAutoGeneratedMenuContent *menuContent = (VLCAutoGeneratedMenuContent *)data;
1716
1717         p_object = [menuContent vlcObject];
1718         var_Set(p_object, [menuContent name], [menuContent value]);
1719     }
1720 }
1721
1722 #pragma mark - menu delegation
1723
1724 - (void)menuWillOpen:(NSMenu *)menu
1725 {
1726     [_cancelRendererDiscoveryTimer invalidate];
1727     [_rendererMenuController startRendererDiscoveries];
1728 }
1729
1730 - (void)menuDidClose:(NSMenu *)menu
1731 {
1732     _cancelRendererDiscoveryTimer = [NSTimer scheduledTimerWithTimeInterval:20.
1733                                                                      target:self
1734                                                                    selector:@selector(cancelRendererDiscovery)
1735                                                                    userInfo:nil
1736                                                                     repeats:NO];
1737 }
1738
1739 - (void)cancelRendererDiscovery
1740 {
1741     [_rendererMenuController stopRendererDiscoveries];
1742 }
1743
1744 @end
1745
1746 @implementation VLCMainMenu (NSMenuValidation)
1747
1748 - (BOOL)validateMenuItem:(NSMenuItem *)mi
1749 {
1750     BOOL enabled = YES;
1751     input_item_t *inputItem = _playlistController.currentlyPlayingInputItem;
1752
1753     if (mi == _stop || mi == _voutMenustop || mi == _dockMenustop) {
1754         if (!inputItem)
1755             enabled = NO;
1756     } else if (mi == _previous          ||
1757                mi == _voutMenuprev      ||
1758                mi == _dockMenuprevious) {
1759         enabled = _playlistController.hasPreviousPlaylistItem;
1760     } else if (
1761                mi == _next              ||
1762                mi == _voutMenunext      ||
1763                mi == _dockMenunext) {
1764         enabled = _playlistController.hasNextPlaylistItem;
1765     } else if (mi == _record) {
1766         enabled = _playerController.recordable;
1767     } else if (mi == _random) {
1768         enum vlc_playlist_playback_order playbackOrder = [_playlistController playbackOrder];
1769         [mi setState: playbackOrder == VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM ? NSOnState : NSOffState];
1770     } else if (mi == _repeat) {
1771         enum vlc_playlist_playback_repeat playbackRepeat = [_playlistController playbackRepeat];
1772         [mi setState: playbackRepeat == VLC_PLAYLIST_PLAYBACK_REPEAT_CURRENT ? NSOnState : NSOffState];
1773     } else if (mi == _loop) {
1774         enum vlc_playlist_playback_repeat playbackRepeat = [_playlistController playbackRepeat];
1775         [mi setState: playbackRepeat == VLC_PLAYLIST_PLAYBACK_REPEAT_ALL ? NSOnState : NSOffState];
1776     } else if (mi == _quitAfterPB) {
1777         BOOL state = _playerController.actionAfterStop == VLC_PLAYER_MEDIA_STOPPED_EXIT;
1778         [mi setState: state ? NSOnState : NSOffState];
1779     } else if (mi == _fwd || mi == _bwd || mi == _jumpToTime) {
1780         enabled = _playerController.seekable;
1781     } else if (mi == _mute || mi == _dockMenumute || mi == _voutMenumute) {
1782         [mi setState: _playerController.mute ? NSOnState : NSOffState];
1783         [self refreshAudioDeviceList];
1784     } else if (mi == _half_window           ||
1785                mi == _normal_window         ||
1786                mi == _double_window         ||
1787                mi == _fittoscreen           ||
1788                mi == _snapshot              ||
1789                mi == _voutMenusnapshot      ||
1790                mi == _fullscreenItem        ||
1791                mi == _voutMenufullscreen    ||
1792                mi == _floatontop
1793                ) {
1794
1795         vout_thread_t *p_vout = [_playerController videoOutputThreadForKeyWindow];
1796         if (p_vout != NULL) {
1797             if (mi == _floatontop)
1798                 [mi setState: var_GetBool(p_vout, "video-on-top")];
1799
1800             if (mi == _fullscreenItem || mi == _voutMenufullscreen)
1801                 [mi setState: _playerController.fullscreen];
1802
1803             enabled = YES;
1804             vout_Release(p_vout);
1805         }
1806
1807     } else if (mi == _openSubtitleFile) {
1808         enabled = YES;
1809     } else {
1810         NSMenuItem *_parent = [mi parentItem];
1811         if (_parent == _subtitle_size || mi == _subtitle_size           ||
1812             _parent == _subtitle_textcolor || mi == _subtitle_textcolor ||
1813             _parent == _subtitle_bgcolor || mi == _subtitle_bgcolor     ||
1814             _parent == _subtitle_bgopacity || mi == _subtitle_bgopacity ||
1815             _parent == _subtitle_outlinethickness || mi == _subtitle_outlinethickness
1816             ) {
1817             enabled = _openSubtitleFile.isEnabled;
1818         } else if (_parent == _teletext || mi == _teletext) {
1819             enabled = _playerController.teletextMenuAvailable;
1820         }
1821     }
1822
1823     if (inputItem) {
1824         input_item_Release(inputItem);
1825     }
1826
1827     return enabled;
1828 }
1829
1830 @end
1831
1832 /*****************************************************************************
1833  *VLCAutoGeneratedMenuContent implementation
1834  *****************************************************************************
1835  *Object connected to a playlistitem which remembers the data belonging to
1836  *the variable of the autogenerated menu
1837  *****************************************************************************/
1838
1839 @implementation VLCAutoGeneratedMenuContent
1840
1841 -(id)initWithVariableName:(const char *)name
1842                  ofObject:(vlc_object_t *)object
1843                  andValue:(vlc_value_t)val
1844                    ofType:(int)type
1845 {
1846     self = [super init];
1847
1848     if (self != nil) {
1849         vlc_object = vlc_object_hold(object);
1850         psz_name = strdup(name);
1851         i_type = type;
1852         value = val;
1853         if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING)
1854             value.psz_string = strdup(val.psz_string);
1855     }
1856
1857     return(self);
1858 }
1859
1860 - (void)dealloc
1861 {
1862     if (vlc_object)
1863         vlc_object_release(vlc_object);
1864     if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING)
1865         free(value.psz_string);
1866     free(psz_name);
1867 }
1868
1869 - (const char *)name
1870 {
1871     return psz_name;
1872 }
1873
1874 - (vlc_value_t)value
1875 {
1876     return value;
1877 }
1878
1879 - (vlc_object_t *)vlcObject
1880 {
1881     return vlc_object;
1882 }
1883
1884 - (int)type
1885 {
1886     return i_type;
1887 }
1888
1889 @end