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