1 /*****************************************************************************
2 *MainMenu.m: MacOS X interface module
3 *****************************************************************************
4 *Copyright (C) 2011-2018 Felix Paul Kühne
7 *Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
9 *This program is free software; you can redistribute it and/or modify
10 *it under the terms of the GNU General Public License as published by
11 *the Free Software Foundation; either version 2 of the License, or
12 *(at your option) any later version.
14 *This program is distributed in the hope that it will be useful,
15 *but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 *GNU General Public License for more details.
19 *You should have received a copy of the GNU General Public License
20 *along with this program; if not, write to the Free Software
21 *Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #import "VLCMainMenu.h"
27 #import <vlc_common.h>
28 #import <vlc_playlist.h>
31 #import "VLCAboutWindowController.h"
32 #import "VLCOpenWindowController.h"
33 #import "VLCAudioEffectsWindowController.h"
34 #import "VLCErrorWindowController.h"
35 #import "VLCTrackSynchronizationWindowController.h"
36 #import "VLCHelpWindowController.h"
37 #import "VLCVideoEffectsWindowController.h"
38 #import "VLCBookmarksWindowController.h"
39 #import "VLCSimplePrefsController.h"
40 #import "VLCPlaylist.h"
41 #import "VLCPlaylistInfo.h"
42 #import "VLCVoutView.h"
43 #import "VLCCoreDialogProvider.h"
44 #import "VLCCoreInteraction.h"
45 #import "VLCMainWindow.h"
46 #import "VLCMainWindowControlsBar.h"
47 #import "VLCExtensionsManager.h"
48 #import "VLCConvertAndSaveWindowController.h"
49 #import "VLCLogWindowController.h"
50 #import "VLCAddonsWindowController.h"
51 #import "VLCTimeSelectionPanelController.h"
52 #import "NSScreen+VLCAdditions.h"
53 #import "VLCRendererMenuController.h"
56 #import <Sparkle/Sparkle.h>
59 @interface VLCMainMenu() <NSMenuDelegate>
61 VLCAboutWindowController *_aboutWindowController;
62 VLCHelpWindowController *_helpWindowController;
63 VLCAddonsWindowController *_addonsController;
64 VLCRendererMenuController *_rendererMenuController;
65 NSTimer *_cancelRendererDiscoveryTimer;
67 NSMenu *_playlistTableColumnsContextMenu;
69 __strong VLCTimeSelectionPanelController *_timeSelectionPanel;
73 @implementation VLCMainMenu
75 #pragma mark - Initialization
79 msg_Dbg(getIntf(), "Deinitializing main menu");
80 [[NSNotificationCenter defaultCenter] removeObserver: self];
82 [self releaseRepresentedObjects:[NSApp mainMenu]];
87 _timeSelectionPanel = [[VLCTimeSelectionPanelController alloc] init];
89 /* check whether the user runs OSX with a RTL language */
90 NSArray* languages = [NSLocale preferredLanguages];
91 NSString* preferredLanguage = [languages firstObject];
93 if ([NSLocale characterDirectionForLanguage:preferredLanguage] == NSLocaleLanguageDirectionRightToLeft) {
94 msg_Dbg(getIntf(), "adapting interface since '%s' is a RTL language", [preferredLanguage UTF8String]);
95 [_rateTextField setAlignment: NSLeftTextAlignment];
98 [self setRateControlsEnabled:NO];
101 [_checkForUpdate setAction:@selector(checkForUpdates:)];
102 [_checkForUpdate setTarget:[SUUpdater sharedUpdater]];
104 [_checkForUpdate setEnabled:NO];
108 VLCStringUtility *stringUtility = [VLCStringUtility sharedInstance];
111 /* Get ExtensionsManager */
112 intf_thread_t *p_intf = getIntf();
116 key = config_GetPsz("key-quit");
117 keyString = [NSString stringWithFormat:@"%s", key];
118 [_quit setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
119 [_quit setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
122 // do not assign play/pause key
124 key = config_GetPsz("key-stop");
125 keyString = [NSString stringWithFormat:@"%s", key];
126 [_stop setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
127 [_stop setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
130 key = config_GetPsz("key-prev");
131 keyString = [NSString stringWithFormat:@"%s", key];
132 [_previous setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
133 [_previous setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
136 key = config_GetPsz("key-next");
137 keyString = [NSString stringWithFormat:@"%s", key];
138 [_next setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
139 [_next setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
142 key = config_GetPsz("key-jump+short");
143 keyString = [NSString stringWithFormat:@"%s", key];
144 [_fwd setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
145 [_fwd setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
148 key = config_GetPsz("key-jump-short");
149 keyString = [NSString stringWithFormat:@"%s", key];
150 [_bwd setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
151 [_bwd setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
154 key = config_GetPsz("key-vol-up");
155 keyString = [NSString stringWithFormat:@"%s", key];
156 [_vol_up setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
157 [_vol_up setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
160 key = config_GetPsz("key-vol-down");
161 keyString = [NSString stringWithFormat:@"%s", key];
162 [_vol_down setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
163 [_vol_down setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
166 key = config_GetPsz("key-vol-mute");
167 keyString = [NSString stringWithFormat:@"%s", key];
168 [_mute setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
169 [_mute setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
172 key = config_GetPsz("key-toggle-fullscreen");
173 keyString = [NSString stringWithFormat:@"%s", key];
174 [_fullscreenItem setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
175 [_fullscreenItem setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
178 key = config_GetPsz("key-snapshot");
179 keyString = [NSString stringWithFormat:@"%s", key];
180 [_snapshot setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
181 [_snapshot setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
184 key = config_GetPsz("key-random");
185 keyString = [NSString stringWithFormat:@"%s", key];
186 [_random setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
187 [_random setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
190 key = config_GetPsz("key-zoom-half");
191 keyString = [NSString stringWithFormat:@"%s", key];
192 [_half_window setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
193 [_half_window setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
196 key = config_GetPsz("key-zoom-original");
197 keyString = [NSString stringWithFormat:@"%s", key];
198 [_normal_window setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
199 [_normal_window setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
202 key = config_GetPsz("key-zoom-double");
203 keyString = [NSString stringWithFormat:@"%s", key];
204 [_double_window setKeyEquivalent: [stringUtility VLCKeyToString: keyString]];
205 [_double_window setKeyEquivalentModifierMask: [stringUtility VLCModifiersToCocoa:keyString]];
208 [self setSubmenusEnabled: FALSE];
210 /* configure playback / controls menu */
211 self.controlsMenu.delegate = self;
212 [_rendererNoneItem setState:NSOnState];
213 _rendererMenuController = [[VLCRendererMenuController alloc] init];
214 _rendererMenuController.rendererNoneItem = _rendererNoneItem;
215 _rendererMenuController.rendererMenu = _rendererMenu;
217 [[NSNotificationCenter defaultCenter] addObserver: self
218 selector: @selector(refreshVoutDeviceMenu:)
219 name: NSApplicationDidChangeScreenParametersNotification
222 [self setupVarMenuItem:_add_intf target: (vlc_object_t *)p_intf
223 var:"intf-add" selector: @selector(toggleVar:)];
225 /* setup extensions menu */
226 /* Let the ExtensionsManager itself build the menu */
227 VLCExtensionsManager *extMgr = [[VLCMain sharedInstance] extensionsManager];
228 [extMgr buildMenu:_extensionsMenu];
229 [_extensions setEnabled: ([_extensionsMenu numberOfItems] > 0)];
231 // FIXME: Implement preference for autoloading extensions on mac
232 if (![extMgr isLoaded] && ![extMgr cannotLoad])
233 [extMgr loadExtensions];
235 /* setup post-proc menu */
236 NSUInteger count = (NSUInteger) [_postprocessingMenu numberOfItems];
238 [_postprocessingMenu removeAllItems];
241 [_postprocessingMenu setAutoenablesItems: YES];
242 [_postprocessingMenu addItemWithTitle: _NS("Disable") action:@selector(togglePostProcessing:) keyEquivalent:@""];
243 mitem = [_postprocessingMenu itemAtIndex: 0];
245 [mitem setEnabled: YES];
246 [mitem setTarget: self];
247 for (NSUInteger x = 1; x < 7; x++) {
248 [_postprocessingMenu addItemWithTitle:[NSString stringWithFormat:_NS("Level %i"), x]
249 action:@selector(togglePostProcessing:)
251 mitem = [_postprocessingMenu itemAtIndex:x];
252 [mitem setEnabled:YES];
254 [mitem setTarget:self];
256 char *psz_config = config_GetPsz("video-filter");
258 if (!strstr(psz_config, "postproc"))
259 [[_postprocessingMenu itemAtIndex:0] setState:NSOnState];
261 [[_postprocessingMenu itemWithTag:config_GetInt("postproc-q")] setState:NSOnState];
264 [[_postprocessingMenu itemAtIndex:0] setState:NSOnState];
265 [_postprocessing setEnabled: NO];
267 [self refreshAudioDeviceList];
269 /* setup subtitles menu */
270 // Persist those variables on the playlist
271 playlist_t *p_playlist = pl_Get(getIntf());
272 var_Create(p_playlist, "freetype-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
273 var_Create(p_playlist, "freetype-background-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
274 var_Create(p_playlist, "freetype-background-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
275 var_Create(p_playlist, "freetype-outline-thickness", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
277 [self setupMenu: _subtitle_textcolorMenu withIntList:"freetype-color" andSelector:@selector(switchSubtitleOption:)];
278 [_subtitle_bgopacity_sld setIntegerValue: config_GetInt("freetype-background-opacity")];
279 [self setupMenu: _subtitle_bgcolorMenu withIntList:"freetype-background-color" andSelector:@selector(switchSubtitleOption:)];
280 [self setupMenu: _subtitle_outlinethicknessMenu withIntList:"freetype-outline-thickness" andSelector:@selector(switchSubtitleOption:)];
282 /* Build size menu based on different scale factors */
284 const char *const name;
287 { N_("Smaller"), 50},
289 { N_("Normal"), 100},
291 { N_("Larger"), 150},
295 for(int i = 0; scaleValues[i].name; i++) {
296 NSMenuItem *menuItem = [_subtitle_sizeMenu addItemWithTitle: _NS(scaleValues[i].name) action:@selector(switchSubtitleSize:) keyEquivalent:@""];
297 [menuItem setTag:scaleValues[i].scaleValue];
298 [menuItem setTarget: self];
302 - (void)setupMenu: (NSMenu*)menu withIntList: (char *)psz_name andSelector:(SEL)selector
304 module_config_t *p_item;
306 [menu removeAllItems];
307 p_item = config_FindConfig(psz_name);
310 msg_Err(getIntf(), "couldn't create menu int list for item '%s' as it does not exist", psz_name);
314 for (int i = 0; i < p_item->list_count; i++) {
316 if (p_item->list_text != NULL)
317 mi = [[NSMenuItem alloc] initWithTitle: _NS(p_item->list_text[i]) action:NULL keyEquivalent: @""];
318 else if (p_item->list.i[i])
319 mi = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"%d", p_item->list.i[i]] action:NULL keyEquivalent: @""];
321 msg_Err(getIntf(), "item %d of pref %s failed to be created", i, psz_name);
326 [mi setAction:selector];
327 [mi setTag:p_item->list.i[i]];
328 [mi setRepresentedObject:toNSStr(psz_name)];
330 if (p_item->value.i == p_item->list.i[i])
331 [mi setState:NSOnState];
338 [_about setTitle: [_NS("About VLC media player") \
339 stringByAppendingString: @"..."]];
340 [_checkForUpdate setTitle: _NS("Check for Update...")];
341 [_prefs setTitle: _NS("Preferences...")];
342 [_extensions setTitle: _NS("Extensions")];
343 [_extensionsMenu setTitle: _NS("Extensions")];
344 [_addonManager setTitle: _NS("Addons Manager")];
345 [_add_intf setTitle: _NS("Add Interface")];
346 [_add_intfMenu setTitle: _NS("Add Interface")];
347 [_services setTitle: _NS("Services")];
348 [_hide setTitle: _NS("Hide VLC")];
349 [_hide_others setTitle: _NS("Hide Others")];
350 [_show_all setTitle: _NS("Show All")];
351 [_quit setTitle: _NS("Quit VLC")];
353 [_fileMenu setTitle: _ANS("1:File")];
354 [_open_generic setTitle: _NS("Advanced Open File...")];
355 [_open_file setTitle: _NS("Open File...")];
356 [_open_disc setTitle: _NS("Open Disc...")];
357 [_open_net setTitle: _NS("Open Network...")];
358 [_open_capture setTitle: _NS("Open Capture Device...")];
359 [_open_recent setTitle: _NS("Open Recent")];
360 [_close_window setTitle: _NS("Close Window")];
361 [_convertandsave setTitle: _NS("Convert / Stream...")];
362 [_save_playlist setTitle: _NS("Save Playlist...")];
363 [_revealInFinder setTitle: _NS("Reveal in Finder")];
365 [_editMenu setTitle: _NS("Edit")];
366 [_cutItem setTitle: _NS("Cut")];
367 [_mcopyItem setTitle: _NS("Copy")];
368 [_pasteItem setTitle: _NS("Paste")];
369 [_clearItem setTitle: _NS("Delete")];
370 [_select_all setTitle: _NS("Select All")];
371 [_findItem setTitle: _NS("Find")];
373 [_viewMenu setTitle: _NS("View")];
374 [_toggleJumpButtons setTitle: _NS("Show Previous & Next Buttons")];
375 [_toggleJumpButtons setState: var_InheritBool(getIntf(), "macosx-show-playback-buttons")];
376 [_togglePlaymodeButtons setTitle: _NS("Show Shuffle & Repeat Buttons")];
377 [_togglePlaymodeButtons setState: var_InheritBool(getIntf(), "macosx-show-playmode-buttons")];
378 [_toggleEffectsButton setTitle: _NS("Show Audio Effects Button")];
379 [_toggleEffectsButton setState: var_InheritBool(getIntf(), "macosx-show-effects-button")];
380 [_toggleSidebar setTitle: _NS("Show Sidebar")];
381 [_playlistTableColumns setTitle: _NS("Playlist Table Columns")];
383 [_controlsMenu setTitle: _NS("Playback")];
384 [_play setTitle: _NS("Play")];
385 [_stop setTitle: _NS("Stop")];
386 [_record setTitle: _NS("Record")];
387 [_rate_view setAutoresizingMask:NSViewWidthSizable];
388 [_rate setView: _rate_view];
389 [_rateLabel setStringValue: _NS("Playback Speed")];
390 [_rate_slowerLabel setStringValue: _NS("Slower")];
391 [_rate_normalLabel setStringValue: _NS("Normal")];
392 [_rate_fasterLabel setStringValue: _NS("Faster")];
393 [_trackSynchronization setTitle: _NS("Track Synchronization")];
394 [_previous setTitle: _NS("Previous")];
395 [_next setTitle: _NS("Next")];
396 [_random setTitle: _NS("Random")];
397 [_repeat setTitle: _NS("Repeat One")];
398 [_loop setTitle: _NS("Repeat All")];
399 [_AtoBloop setTitle: _NS("A→B Loop")];
400 [_quitAfterPB setTitle: _NS("Quit after Playback")];
401 [_fwd setTitle: _NS("Step Forward")];
402 [_bwd setTitle: _NS("Step Backward")];
403 [_jumpToTime setTitle: _NS("Jump to Time")];
404 [_rendererMenuItem setTitle:_NS("Renderer")];
405 [_rendererNoneItem setTitle:_NS("No renderer")];
406 [_program setTitle: _NS("Program")];
407 [_programMenu setTitle: _NS("Program")];
408 [_title setTitle: _NS("Title")];
409 [_titleMenu setTitle: _NS("Title")];
410 [_chapter setTitle: _NS("Chapter")];
411 [_chapterMenu setTitle: _NS("Chapter")];
413 [_audioMenu setTitle: _NS("Audio")];
414 [_vol_up setTitle: _NS("Increase Volume")];
415 [_vol_down setTitle: _NS("Decrease Volume")];
416 [_mute setTitle: _NS("Mute")];
417 [_audiotrack setTitle: _NS("Audio Track")];
418 [_audiotrackMenu setTitle: _NS("Audio Track")];
419 [_channels setTitle: _NS("Stereo audio mode")];
420 [_channelsMenu setTitle: _NS("Stereo audio mode")];
421 [_audioDevice setTitle: _NS("Audio Device")];
422 [_audioDeviceMenu setTitle: _NS("Audio Device")];
423 [_visual setTitle: _NS("Visualizations")];
424 [_visualMenu setTitle: _NS("Visualizations")];
426 [_videoMenu setTitle: _NS("Video")];
427 [_half_window setTitle: _NS("Half Size")];
428 [_normal_window setTitle: _NS("Normal Size")];
429 [_double_window setTitle: _NS("Double Size")];
430 [_fittoscreen setTitle: _NS("Fit to Screen")];
431 [_fullscreenItem setTitle: _NS("Fullscreen")];
432 [_floatontop setTitle: _NS("Float on Top")];
433 [_snapshot setTitle: _NS("Snapshot")];
434 [_videotrack setTitle: _NS("Video Track")];
435 [_videotrackMenu setTitle: _NS("Video Track")];
436 [_aspect_ratio setTitle: _NS("Aspect ratio")];
437 [_aspect_ratioMenu setTitle: _NS("Aspect ratio")];
438 [_crop setTitle: _NS("Crop")];
439 [_cropMenu setTitle: _NS("Crop")];
440 [_screen setTitle: _NS("Fullscreen Video Device")];
441 [_screenMenu setTitle: _NS("Fullscreen Video Device")];
442 [_deinterlace setTitle: _NS("Deinterlace")];
443 [_deinterlaceMenu setTitle: _NS("Deinterlace")];
444 [_deinterlace_mode setTitle: _NS("Deinterlace mode")];
445 [_deinterlace_modeMenu setTitle: _NS("Deinterlace mode")];
446 [_postprocessing setTitle: _NS("Post processing")];
447 [_postprocessingMenu setTitle: _NS("Post processing")];
449 [_subtitlesMenu setTitle:_NS("Subtitles")];
450 [_openSubtitleFile setTitle: _NS("Add Subtitle File...")];
451 [_subtitle_track setTitle: _NS("Subtitles Track")];
452 [_subtitle_tracksMenu setTitle: _NS("Subtitles Track")];
453 [_subtitle_size setTitle: _NS("Text Size")];
454 [_subtitle_textcolor setTitle: _NS("Text Color")];
455 [_subtitle_outlinethickness setTitle: _NS("Outline Thickness")];
457 // Autoresizing with constraints does not work on 10.7,
458 // translate autoresizing mask to constriaints for now
459 [_subtitle_bgopacity_view setAutoresizingMask:NSViewWidthSizable];
460 [_subtitle_bgopacity setView: _subtitle_bgopacity_view];
461 [_subtitle_bgopacityLabel setStringValue: _NS("Background Opacity")];
462 [_subtitle_bgopacityLabel_gray setStringValue: _NS("Background Opacity")];
463 [_subtitle_bgcolor setTitle: _NS("Background Color")];
464 [_teletext setTitle: _NS("Teletext")];
465 [_teletext_transparent setTitle: _NS("Transparent")];
466 [_teletext_index setTitle: _NS("Index")];
467 [_teletext_red setTitle: _NS("Red")];
468 [_teletext_green setTitle: _NS("Green")];
469 [_teletext_yellow setTitle: _NS("Yellow")];
470 [_teletext_blue setTitle: _NS("Blue")];
472 [_windowMenu setTitle: _NS("Window")];
473 [_minimize setTitle: _NS("Minimize")];
474 [_zoom_window setTitle: _NS("Zoom")];
475 [_player setTitle: _NS("Player...")];
476 [_controller setTitle: _NS("Main Window...")];
477 [_audioeffects setTitle: _NS("Audio Effects...")];
478 [_videoeffects setTitle: _NS("Video Effects...")];
479 [_bookmarks setTitle: _NS("Bookmarks...")];
480 [_playlist setTitle: _NS("Playlist...")];
481 [_info setTitle: _NS("Media Information...")];
482 [_messages setTitle: _NS("Messages...")];
483 [_errorsAndWarnings setTitle: _NS("Errors and Warnings...")];
485 [_bring_atf setTitle: _NS("Bring All to Front")];
487 [_helpMenu setTitle: _NS("Help")];
488 [_help setTitle: _NS("VLC media player Help...")];
489 [_license setTitle: _NS("License")];
490 [_documentation setTitle: _NS("Online Documentation...")];
491 [_website setTitle: _NS("VideoLAN Website...")];
492 [_donation setTitle: _NS("Make a donation...")];
493 [_forum setTitle: _NS("Online Forum...")];
496 [_dockMenuplay setTitle: _NS("Play")];
497 [_dockMenustop setTitle: _NS("Stop")];
498 [_dockMenunext setTitle: _NS("Next")];
499 [_dockMenuprevious setTitle: _NS("Previous")];
500 [_dockMenumute setTitle: _NS("Mute")];
503 [_voutMenuplay setTitle: _NS("Play")];
504 [_voutMenustop setTitle: _NS("Stop")];
505 [_voutMenuprev setTitle: _NS("Previous")];
506 [_voutMenunext setTitle: _NS("Next")];
507 [_voutMenuvolup setTitle: _NS("Volume Up")];
508 [_voutMenuvoldown setTitle: _NS("Volume Down")];
509 [_voutMenumute setTitle: _NS("Mute")];
510 [_voutMenufullscreen setTitle: _NS("Fullscreen")];
511 [_voutMenusnapshot setTitle: _NS("Snapshot")];
514 #pragma mark - Termination
516 - (void)releaseRepresentedObjects:(NSMenu *)the_menu
518 NSArray *menuitems_array = [the_menu itemArray];
519 NSUInteger menuItemCount = [menuitems_array count];
520 for (NSUInteger i=0; i < menuItemCount; i++) {
521 NSMenuItem *one_item = [menuitems_array objectAtIndex:i];
522 if ([one_item hasSubmenu])
523 [self releaseRepresentedObjects: [one_item submenu]];
525 [one_item setRepresentedObject:NULL];
529 #pragma mark - Interface update
533 playlist_t *p_playlist = pl_Get(getIntf());
534 input_thread_t *p_input = playlist_CurrentInput(p_playlist);
535 if (p_input != NULL) {
536 [self setupVarMenuItem:_program target: (vlc_object_t *)p_input
537 var:"program" selector: @selector(toggleVar:)];
539 [self setupVarMenuItem:_title target: (vlc_object_t *)p_input
540 var:"title" selector: @selector(toggleVar:)];
542 [self setupVarMenuItem:_chapter target: (vlc_object_t *)p_input
543 var:"chapter" selector: @selector(toggleVar:)];
545 [self setupVarMenuItem:_audiotrack target: (vlc_object_t *)p_input
546 var:"audio-es" selector: @selector(toggleVar:)];
548 [self setupVarMenuItem:_videotrack target: (vlc_object_t *)p_input
549 var:"video-es" selector: @selector(toggleVar:)];
551 [self setupVarMenuItem:_subtitle_track target: (vlc_object_t *)p_input
552 var:"spu-es" selector: @selector(toggleVar:)];
554 audio_output_t *p_aout = playlist_GetAout(p_playlist);
555 if (p_aout != NULL) {
556 [self setupVarMenuItem:_channels target: (vlc_object_t *)p_aout
557 var:"stereo-mode" selector: @selector(toggleVar:)];
559 [self setupVarMenuItem:_visual target: (vlc_object_t *)p_aout
560 var:"visual" selector: @selector(toggleVar:)];
561 vlc_object_release(p_aout);
564 vout_thread_t *p_vout = getVoutForActiveWindow();
566 if (p_vout != NULL) {
567 [self setupVarMenuItem:_aspect_ratio target: (vlc_object_t *)p_vout
568 var:"aspect-ratio" selector: @selector(toggleVar:)];
570 [self setupVarMenuItem:_crop target: (vlc_object_t *) p_vout
571 var:"crop" selector: @selector(toggleVar:)];
573 [self setupVarMenuItem:_deinterlace target: (vlc_object_t *)p_vout
574 var:"deinterlace" selector: @selector(toggleVar:)];
576 [self setupVarMenuItem:_deinterlace_mode target: (vlc_object_t *)p_vout
577 var:"deinterlace-mode" selector: @selector(toggleVar:)];
579 vlc_object_release(p_vout);
581 [self refreshVoutDeviceMenu:nil];
583 [_postprocessing setEnabled:YES];
584 vlc_object_release(p_input);
586 [_postprocessing setEnabled:NO];
590 - (void)refreshVoutDeviceMenu:(NSNotification *)notification
592 NSUInteger count = (NSUInteger) [_screenMenu numberOfItems];
593 NSMenu *submenu = _screenMenu;
595 [submenu removeAllItems];
597 NSArray *screens = [NSScreen screens];
599 count = [screens count];
600 [_screen setEnabled: YES];
601 [submenu addItemWithTitle: _NS("Default") action:@selector(toggleFullscreenDevice:) keyEquivalent:@""];
602 mitem = [submenu itemAtIndex: 0];
604 [mitem setEnabled: YES];
605 [mitem setTarget: self];
607 for (NSUInteger i = 0; i < count; i++) {
608 s_rect = [[screens objectAtIndex:i] frame];
609 [submenu addItemWithTitle: [NSString stringWithFormat: @"%@ %li (%ix%i)", _NS("Screen"), i+1,
610 (int)s_rect.size.width, (int)s_rect.size.height] action:@selector(toggleFullscreenDevice:) keyEquivalent:@""];
611 mitem = [submenu itemAtIndex:i+1];
612 [mitem setTag: (int)[[screens objectAtIndex:i] displayID]];
613 [mitem setEnabled: YES];
614 [mitem setTarget: self];
616 [[submenu itemWithTag: var_InheritInteger(getIntf(), "macosx-vdev")] setState: NSOnState];
619 - (void)setSubmenusEnabled:(BOOL)b_enabled
621 [_program setEnabled: b_enabled];
622 [_title setEnabled: b_enabled];
623 [_chapter setEnabled: b_enabled];
624 [_audiotrack setEnabled: b_enabled];
625 [_visual setEnabled: b_enabled];
626 [_videotrack setEnabled: b_enabled];
627 [_subtitle_track setEnabled: b_enabled];
628 [_channels setEnabled: b_enabled];
629 [_deinterlace setEnabled: b_enabled];
630 [_deinterlace_mode setEnabled: b_enabled];
631 [_screen setEnabled: b_enabled];
632 [_aspect_ratio setEnabled: b_enabled];
633 [_crop setEnabled: b_enabled];
636 - (void)setSubtitleMenuEnabled:(BOOL)b_enabled
638 [_openSubtitleFile setEnabled: b_enabled];
640 [_subtitle_bgopacityLabel_gray setHidden: YES];
641 [_subtitle_bgopacityLabel setHidden: NO];
643 [_subtitle_bgopacityLabel_gray setHidden: NO];
644 [_subtitle_bgopacityLabel setHidden: YES];
646 [_subtitle_bgopacity_sld setEnabled: b_enabled];
647 [_teletext setEnabled: b_enabled];
650 - (void)setRateControlsEnabled:(BOOL)b_enabled
652 [_rate_sld setEnabled: b_enabled];
653 [_rate_sld setIntValue: [[VLCCoreInteraction sharedInstance] playbackRate]];
654 int i = [[VLCCoreInteraction sharedInstance] playbackRate];
655 double speed = pow(2, (double)i / 17);
656 [_rateTextField setStringValue: [NSString stringWithFormat:@"%.2fx", speed]];
658 NSColor *color = b_enabled ? [NSColor controlTextColor] : [NSColor disabledControlTextColor];
660 [_rateLabel setTextColor:color];
661 [_rate_slowerLabel setTextColor:color];
662 [_rate_normalLabel setTextColor:color];
663 [_rate_fasterLabel setTextColor:color];
664 [_rateTextField setTextColor:color];
666 [self setSubtitleMenuEnabled: b_enabled];
671 - (IBAction)toggleEffectsButton:(id)sender
673 BOOL b_value = !var_InheritBool(getIntf(), "macosx-show-effects-button");
674 config_PutInt("macosx-show-effects-button", b_value);
675 [(VLCMainWindowControlsBar *)[[[VLCMain sharedInstance] mainWindow] controlsBar] toggleEffectsButton];
676 [_toggleEffectsButton setState: b_value];
679 - (IBAction)toggleJumpButtons:(id)sender
681 BOOL b_value = !var_InheritBool(getIntf(), "macosx-show-playback-buttons");
682 config_PutInt("macosx-show-playback-buttons", b_value);
684 [(VLCMainWindowControlsBar *)[[[VLCMain sharedInstance] mainWindow] controlsBar] toggleJumpButtons];
685 [[[VLCMain sharedInstance] voutProvider] updateWindowsUsingBlock:^(VLCVideoWindowCommon *window) {
686 [[window controlsBar] toggleForwardBackwardMode: b_value];
689 [_toggleJumpButtons setState: b_value];
692 - (IBAction)togglePlaymodeButtons:(id)sender
694 BOOL b_value = !var_InheritBool(getIntf(), "macosx-show-playmode-buttons");
695 config_PutInt("macosx-show-playmode-buttons", b_value);
696 [(VLCMainWindowControlsBar *)[[[VLCMain sharedInstance] mainWindow] controlsBar] togglePlaymodeButtons];
697 [_togglePlaymodeButtons setState: b_value];
700 - (IBAction)toggleSidebar:(id)sender
702 [[[VLCMain sharedInstance] mainWindow] toggleLeftSubSplitView];
705 - (void)updateSidebarMenuItem:(BOOL)show;
707 [_toggleSidebar setState:show];
710 #pragma mark - Playback
712 - (IBAction)play:(id)sender
714 [[VLCCoreInteraction sharedInstance] playOrPause];
717 - (IBAction)stop:(id)sender
719 [[VLCCoreInteraction sharedInstance] stop];
722 - (IBAction)prev:(id)sender
724 [[VLCCoreInteraction sharedInstance] previous];
727 - (IBAction)next:(id)sender
729 [[VLCCoreInteraction sharedInstance] next];
732 - (IBAction)random:(id)sender
734 [[VLCCoreInteraction sharedInstance] shuffle];
737 - (IBAction)repeat:(id)sender
740 intf_thread_t *p_intf = getIntf();
741 playlist_t *p_playlist = pl_Get(p_intf);
743 var_Get(p_playlist, "repeat", &val);
745 [[VLCCoreInteraction sharedInstance] repeatOne];
747 [[VLCCoreInteraction sharedInstance] repeatOff];
750 - (IBAction)loop:(id)sender
753 intf_thread_t *p_intf = getIntf();
754 playlist_t *p_playlist = pl_Get(p_intf);
756 var_Get(p_playlist, "loop", &val);
758 [[VLCCoreInteraction sharedInstance] repeatAll];
760 [[VLCCoreInteraction sharedInstance] repeatOff];
763 - (IBAction)forward:(id)sender
765 [[VLCCoreInteraction sharedInstance] forward];
768 - (IBAction)backward:(id)sender
770 [[VLCCoreInteraction sharedInstance] backward];
773 - (IBAction)volumeUp:(id)sender
775 [[VLCCoreInteraction sharedInstance] volumeUp];
778 - (IBAction)volumeDown:(id)sender
780 [[VLCCoreInteraction sharedInstance] volumeDown];
783 - (IBAction)mute:(id)sender
785 [[VLCCoreInteraction sharedInstance] toggleMute];
788 - (void)lockVideosAspectRatio:(id)sender
790 [[VLCCoreInteraction sharedInstance] setAspectRatioIsLocked: ![sender state]];
791 [sender setState: [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]];
794 - (IBAction)quitAfterPlayback:(id)sender
796 playlist_t *p_playlist = pl_Get(getIntf());
797 bool b_value = !var_CreateGetBool(p_playlist, "play-and-exit");
798 var_SetBool(p_playlist, "play-and-exit", b_value);
799 config_PutInt("play-and-exit", b_value);
802 - (IBAction)toggleRecord:(id)sender
804 [[VLCCoreInteraction sharedInstance] toggleRecord];
807 - (void)updateRecordState:(BOOL)b_value
809 [_record setState:b_value];
812 - (IBAction)setPlaybackRate:(id)sender
814 [[VLCCoreInteraction sharedInstance] setPlaybackRate: [_rate_sld intValue]];
815 int i = [[VLCCoreInteraction sharedInstance] playbackRate];
816 double speed = pow(2, (double)i / 17);
817 [_rateTextField setStringValue: [NSString stringWithFormat:@"%.2fx", speed]];
820 - (void)updatePlaybackRate
822 int i = [[VLCCoreInteraction sharedInstance] playbackRate];
823 double speed = pow(2, (double)i / 17);
824 [_rateTextField setStringValue: [NSString stringWithFormat:@"%.2fx", speed]];
825 [_rate_sld setIntValue: i];
828 - (IBAction)toggleAtoBloop:(id)sender
830 [[VLCCoreInteraction sharedInstance] setAtoB];
833 - (IBAction)goToSpecificTime:(id)sender
835 input_thread_t *p_input = pl_CurrentInput(getIntf());
837 /* we can obviously only do that if an input is available */
838 vlc_tick_t length = var_GetInteger(p_input, "length");
839 [_timeSelectionPanel setMaxValue:(int)SEC_FROM_VLC_TICK(length)];
840 vlc_tick_t pos = var_GetInteger(p_input, "time");
841 [_timeSelectionPanel setJumpTimeValue: (int)SEC_FROM_VLC_TICK(pos)];
842 [_timeSelectionPanel runModalForWindow:[NSApp mainWindow]
843 completionHandler:^(NSInteger returnCode, int64_t returnTime) {
845 if (returnCode != NSModalResponseOK)
848 input_thread_t *p_input = pl_CurrentInput(getIntf());
850 input_SetTime(p_input, vlc_tick_from_sec(returnTime),
851 var_GetBool(p_input, "input-fast-seek"));
852 vlc_object_release(p_input);
856 vlc_object_release(p_input);
860 - (IBAction)selectRenderer:(id)sender
862 [_rendererMenuController selectRenderer:sender];
865 #pragma mark - audio menu
867 - (void)refreshAudioDeviceList
872 [_audioDeviceMenu removeAllItems];
874 audio_output_t *p_aout = getAout();
878 int n = aout_DevicesList(p_aout, &ids, &names);
880 vlc_object_release(p_aout);
884 currentDevice = aout_DeviceGet(p_aout);
887 for (NSUInteger x = 0; x < n; x++) {
888 _tmp = [_audioDeviceMenu addItemWithTitle:toNSStr(names[x]) action:@selector(toggleAudioDevice:) keyEquivalent:@""];
889 [_tmp setTarget:self];
890 [_tmp setTag:[[NSString stringWithFormat:@"%s", ids[x]] intValue]];
892 vlc_object_release(p_aout);
894 [[_audioDeviceMenu itemWithTag:[[NSString stringWithFormat:@"%s", currentDevice] intValue]] setState:NSOnState];
898 for (NSUInteger x = 0; x < n; x++) {
905 [_audioDeviceMenu setAutoenablesItems:YES];
906 [_audioDevice setEnabled:YES];
909 - (void)toggleAudioDevice:(id)sender
911 audio_output_t *p_aout = getAout();
917 if ([sender tag] > 0)
918 returnValue = aout_DeviceSet(p_aout, [[NSString stringWithFormat:@"%li", [sender tag]] UTF8String]);
920 returnValue = aout_DeviceSet(p_aout, NULL);
922 if (returnValue != 0)
923 msg_Warn(getIntf(), "failed to set audio device %li", [sender tag]);
925 vlc_object_release(p_aout);
926 [self refreshAudioDeviceList];
929 #pragma mark - video menu
931 - (IBAction)toggleFullscreen:(id)sender
933 [[VLCCoreInteraction sharedInstance] toggleFullscreen];
936 - (IBAction)resizeVideoWindow:(id)sender
938 input_thread_t *p_input = pl_CurrentInput(getIntf());
940 vout_thread_t *p_vout = getVoutForActiveWindow();
942 if (sender == _half_window)
943 var_SetFloat(p_vout, "zoom", 0.5);
944 else if (sender == _normal_window)
945 var_SetFloat(p_vout, "zoom", 1.0);
946 else if (sender == _double_window)
947 var_SetFloat(p_vout, "zoom", 2.0);
950 [[NSApp keyWindow] performZoom:sender];
952 vlc_object_release(p_vout);
954 vlc_object_release(p_input);
958 - (IBAction)floatOnTop:(id)sender
960 input_thread_t *p_input = pl_CurrentInput(getIntf());
962 vout_thread_t *p_vout = getVoutForActiveWindow();
964 BOOL b_fs = var_ToggleBool(p_vout, "video-on-top");
965 var_SetBool(pl_Get(getIntf()), "video-on-top", b_fs);
967 vlc_object_release(p_vout);
969 vlc_object_release(p_input);
973 - (IBAction)createVideoSnapshot:(id)sender
975 input_thread_t *p_input = pl_CurrentInput(getIntf());
977 vout_thread_t *p_vout = getVoutForActiveWindow();
979 var_TriggerCallback(p_vout, "video-snapshot");
980 vlc_object_release(p_vout);
982 vlc_object_release(p_input);
986 - (void)_disablePostProcessing
988 [[VLCCoreInteraction sharedInstance] setVideoFilter:"postproc" on:false];
991 - (void)_enablePostProcessing
993 [[VLCCoreInteraction sharedInstance] setVideoFilter:"postproc" on:true];
996 - (void)togglePostProcessing:(id)sender
998 NSInteger count = [_postprocessingMenu numberOfItems];
999 for (NSUInteger x = 0; x < count; x++)
1000 [[_postprocessingMenu itemAtIndex:x] setState:NSOffState];
1002 if ([sender tag] == -1) {
1003 [self _disablePostProcessing];
1004 [sender setState:NSOnState];
1006 [self _enablePostProcessing];
1007 [sender setState:NSOnState];
1009 [[VLCCoreInteraction sharedInstance] setVideoFilterProperty:"postproc-q" forFilter:"postproc" withValue:(vlc_value_t){ .i_int = [sender tag] }];
1013 - (void)toggleFullscreenDevice:(id)sender
1015 config_PutInt("macosx-vdev", [sender tag]);
1016 [self refreshVoutDeviceMenu: nil];
1019 #pragma mark - Subtitles Menu
1021 - (IBAction)addSubtitleFile:(id)sender
1023 NSInteger i_returnValue = 0;
1024 input_thread_t *p_input = pl_CurrentInput(getIntf());
1028 input_item_t *p_item = input_GetItem(p_input);
1030 vlc_object_release(p_input);
1034 char *path = input_item_GetURI(p_item);
1039 NSOpenPanel *openPanel = [NSOpenPanel openPanel];
1040 [openPanel setCanChooseFiles: YES];
1041 [openPanel setCanChooseDirectories: NO];
1042 [openPanel setAllowsMultipleSelection: YES];
1044 [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]];
1046 NSURL *url = [NSURL URLWithString:[toNSStr(path) stringByExpandingTildeInPath]];
1047 url = [url URLByDeletingLastPathComponent];
1048 [openPanel setDirectoryURL: url];
1050 vlc_object_release(p_input);
1052 i_returnValue = [openPanel runModal];
1054 if (i_returnValue == NSModalResponseOK)
1055 [[VLCCoreInteraction sharedInstance] addSubtitlesToCurrentInput:[openPanel URLs]];
1058 - (void)switchSubtitleSize:(id)sender
1060 NSInteger intValue = [sender tag];
1061 var_SetInteger(pl_Get(getIntf()), "sub-text-scale", intValue);
1065 - (void)switchSubtitleOption:(id)sender
1067 NSInteger intValue = [sender tag];
1068 NSString *representedObject = [sender representedObject];
1070 var_SetInteger(pl_Get(getIntf()), [representedObject UTF8String], intValue);
1072 NSMenu *menu = [sender menu];
1073 NSUInteger count = (NSUInteger) [menu numberOfItems];
1074 for (NSUInteger x = 0; x < count; x++)
1075 [[menu itemAtIndex:x] setState:NSOffState];
1076 [[menu itemWithTag:intValue] setState:NSOnState];
1079 - (IBAction)switchSubtitleBackgroundOpacity:(id)sender
1081 var_SetInteger(pl_Get(getIntf()), "freetype-background-opacity", [sender intValue]);
1084 - (IBAction)telxTransparent:(id)sender
1086 vlc_object_t *p_vbi;
1087 p_vbi = (vlc_object_t *) vlc_object_find_name(pl_Get(getIntf()), "zvbi");
1089 var_SetBool(p_vbi, "vbi-opaque", [sender state]);
1090 [sender setState: ![sender state]];
1091 vlc_object_release(p_vbi);
1095 - (IBAction)telxNavLink:(id)sender
1097 vlc_object_t *p_vbi;
1100 if ([[sender title] isEqualToString: _NS("Index")])
1102 else if ([[sender title] isEqualToString: _NS("Red")])
1104 else if ([[sender title] isEqualToString: _NS("Green")])
1106 else if ([[sender title] isEqualToString: _NS("Yellow")])
1108 else if ([[sender title] isEqualToString: _NS("Blue")])
1110 if (i_page == 0) return;
1112 p_vbi = (vlc_object_t *) vlc_object_find_name(pl_Get(getIntf()), "zvbi");
1114 var_SetInteger(p_vbi, "vbi-page", i_page);
1115 vlc_object_release(p_vbi);
1119 #pragma mark - Panels
1121 - (IBAction)intfOpenFile:(id)sender
1123 [[[VLCMain sharedInstance] open] openFileWithAction:^(NSArray *files) {
1124 [[[VLCMain sharedInstance] playlist] addPlaylistItems:files];
1128 - (IBAction)intfOpenFileGeneric:(id)sender
1130 [[[VLCMain sharedInstance] open] openFileGeneric];
1133 - (IBAction)intfOpenDisc:(id)sender
1135 [[[VLCMain sharedInstance] open] openDisc];
1138 - (IBAction)intfOpenNet:(id)sender
1140 [[[VLCMain sharedInstance] open] openNet];
1143 - (IBAction)intfOpenCapture:(id)sender
1145 [[[VLCMain sharedInstance] open] openCapture];
1148 - (IBAction)savePlaylist:(id)sender
1150 playlist_t *p_playlist = pl_Get(getIntf());
1152 NSSavePanel *savePanel = [NSSavePanel savePanel];
1153 NSString * name = [NSString stringWithFormat: @"%@", _NS("Untitled")];
1155 static dispatch_once_t once;
1156 dispatch_once(&once, ^{
1157 [[NSBundle mainBundle] loadNibNamed:@"PlaylistAccessoryView" owner:self topLevelObjects:nil];
1160 [_playlistSaveAccessoryText setStringValue: _NS("File Format:")];
1161 [[_playlistSaveAccessoryPopup itemAtIndex:0] setTitle: _NS("Extended M3U")];
1162 [[_playlistSaveAccessoryPopup itemAtIndex:1] setTitle: _NS("XML Shareable Playlist Format (XSPF)")];
1163 [[_playlistSaveAccessoryPopup itemAtIndex:2] setTitle: _NS("HTML playlist")];
1165 [savePanel setTitle: _NS("Save Playlist")];
1166 [savePanel setPrompt: _NS("Save")];
1167 [savePanel setAccessoryView: _playlistSaveAccessoryView];
1168 [savePanel setNameFieldStringValue: name];
1170 if ([savePanel runModal] == NSFileHandlingPanelOKButton) {
1171 NSString *filename = [[savePanel URL] path];
1173 if ([_playlistSaveAccessoryPopup indexOfSelectedItem] == 0) {
1174 NSString *actualFilename;
1176 range.location = [filename length] - [@".m3u" length];
1177 range.length = [@".m3u" length];
1179 if ([filename compare:@".m3u" options: NSCaseInsensitiveSearch range: range] != NSOrderedSame)
1180 actualFilename = [NSString stringWithFormat: @"%@.m3u", filename];
1182 actualFilename = filename;
1184 playlist_Export(p_playlist,
1185 [actualFilename fileSystemRepresentation],
1186 true, "export-m3u");
1187 } else if ([_playlistSaveAccessoryPopup indexOfSelectedItem] == 1) {
1188 NSString *actualFilename;
1190 range.location = [filename length] - [@".xspf" length];
1191 range.length = [@".xspf" length];
1193 if ([filename compare:@".xspf" options: NSCaseInsensitiveSearch range: range] != NSOrderedSame)
1194 actualFilename = [NSString stringWithFormat: @"%@.xspf", filename];
1196 actualFilename = filename;
1198 playlist_Export(p_playlist,
1199 [actualFilename fileSystemRepresentation],
1200 true, "export-xspf");
1202 NSString *actualFilename;
1204 range.location = [filename length] - [@".html" length];
1205 range.length = [@".html" length];
1207 if ([filename compare:@".html" options: NSCaseInsensitiveSearch range: range] != NSOrderedSame)
1208 actualFilename = [NSString stringWithFormat: @"%@.html", filename];
1210 actualFilename = filename;
1212 playlist_Export(p_playlist,
1213 [actualFilename fileSystemRepresentation],
1214 true, "export-html");
1219 - (IBAction)showConvertAndSave:(id)sender
1221 [[[VLCMain sharedInstance] convertAndSaveWindow] showWindow:self];
1224 - (IBAction)showVideoEffects:(id)sender
1226 [[[VLCMain sharedInstance] videoEffectsPanel] toggleWindow:sender];
1229 - (IBAction)showTrackSynchronization:(id)sender
1231 [[[VLCMain sharedInstance] trackSyncPanel] toggleWindow:sender];
1234 - (IBAction)showAudioEffects:(id)sender
1236 [[[VLCMain sharedInstance] audioEffectsPanel] toggleWindow:sender];
1239 - (IBAction)showBookmarks:(id)sender
1241 [[[VLCMain sharedInstance] bookmarks] toggleWindow:sender];
1244 - (IBAction)showPreferences:(id)sender
1246 NSInteger i_level = [[[VLCMain sharedInstance] voutProvider] currentStatusWindowLevel];
1247 [[[VLCMain sharedInstance] simplePreferences] showSimplePrefsWithLevel:i_level];
1250 - (IBAction)openAddonManager:(id)sender
1252 if (!_addonsController)
1253 _addonsController = [[VLCAddonsWindowController alloc] init];
1255 [_addonsController showWindow:self];
1258 - (IBAction)showErrorsAndWarnings:(id)sender
1260 [[[[VLCMain sharedInstance] coreDialogProvider] errorPanel] showWindow:self];
1263 - (IBAction)showMessagesPanel:(id)showMessagesPanel
1265 [[[VLCMain sharedInstance] debugMsgPanel] showWindow:self];
1268 - (IBAction)showMainWindow:(id)sender
1270 [[[VLCMain sharedInstance] mainWindow] makeKeyAndOrderFront:sender];
1273 - (IBAction)showPlaylist:(id)sender
1275 [[[VLCMain sharedInstance] mainWindow] changePlaylistState: psUserMenuEvent];
1278 #pragma mark - Help and Docs
1280 - (IBAction)showAbout:(id)sender
1282 if (!_aboutWindowController)
1283 _aboutWindowController = [[VLCAboutWindowController alloc] init];
1285 [_aboutWindowController showAbout];
1288 - (IBAction)showLicense:(id)sender
1290 if (!_aboutWindowController)
1291 _aboutWindowController = [[VLCAboutWindowController alloc] init];
1293 [_aboutWindowController showGPL];
1296 - (IBAction)showHelp:(id)sender
1298 if (!_helpWindowController)
1299 _helpWindowController = [[VLCHelpWindowController alloc] init];
1301 [_helpWindowController showHelp];
1304 - (IBAction)openDocumentation:(id)sender
1306 NSURL *url = [NSURL URLWithString: @"http://www.videolan.org/doc/"];
1308 [[NSWorkspace sharedWorkspace] openURL: url];
1311 - (IBAction)openWebsite:(id)sender
1313 NSURL *url = [NSURL URLWithString: @"http://www.videolan.org/"];
1315 [[NSWorkspace sharedWorkspace] openURL: url];
1318 - (IBAction)openForum:(id)sender
1320 NSURL *url = [NSURL URLWithString: @"http://forum.videolan.org/"];
1322 [[NSWorkspace sharedWorkspace] openURL: url];
1325 - (IBAction)openDonate:(id)sender
1327 NSURL *url = [NSURL URLWithString: @"http://www.videolan.org/contribute.html#paypal"];
1329 [[NSWorkspace sharedWorkspace] openURL: url];
1332 - (IBAction)showInformationPanel:(id)sender
1334 [[[VLCMain sharedInstance] currentMediaInfoPanel] toggleWindow:sender];
1337 #pragma mark - convinience stuff for other objects
1341 [_play setTitle: _NS("Play")];
1342 [_dockMenuplay setTitle: _NS("Play")];
1343 [_voutMenuplay setTitle: _NS("Play")];
1348 [_play setTitle: _NS("Pause")];
1349 [_dockMenuplay setTitle: _NS("Pause")];
1350 [_voutMenuplay setTitle: _NS("Pause")];
1353 - (void)setRepeatOne
1355 [_repeat setState: NSOnState];
1356 [_loop setState: NSOffState];
1359 - (void)setRepeatAll
1361 [_repeat setState: NSOffState];
1362 [_loop setState: NSOnState];
1365 - (void)setRepeatOff
1367 [_repeat setState: NSOffState];
1368 [_loop setState: NSOffState];
1374 playlist_t *p_playlist = pl_Get(getIntf());
1375 b_value = var_GetBool(p_playlist, "random");
1377 [_random setState: b_value];
1380 #pragma mark - Dynamic menu creation and validation
1382 - (void)setupVarMenuItem:(NSMenuItem *)mi
1383 target:(vlc_object_t *)p_object
1384 var:(const char *)psz_variable
1385 selector:(SEL)pf_callback
1389 int i_type = var_Type(p_object, psz_variable);
1391 switch(i_type & VLC_VAR_TYPE) {
1394 case VLC_VAR_STRING:
1395 case VLC_VAR_INTEGER:
1398 /* Variable doesn't exist or isn't handled */
1399 msg_Warn(p_object, "variable %s doesn't exist or isn't handled", psz_variable);
1403 /* Get the descriptive name of the variable */
1404 var_Change(p_object, psz_variable, VLC_VAR_GETTEXT, &text);
1405 [mi setTitle: _NS(text ? text : psz_variable)];
1407 if (i_type & VLC_VAR_HASCHOICE) {
1408 NSMenu *menu = [mi submenu];
1410 [self setupVarMenu:menu forMenuItem:mi target:p_object
1411 var:psz_variable selector:pf_callback];
1417 if (var_Get(p_object, psz_variable, &val) < 0)
1420 VLCAutoGeneratedMenuContent *data;
1421 switch(i_type & VLC_VAR_TYPE) {
1423 data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
1424 andValue: val ofType: i_type];
1425 [mi setRepresentedObject:data];
1429 data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
1430 andValue: val ofType: i_type];
1431 [mi setRepresentedObject:data];
1432 if (!(i_type & VLC_VAR_ISCOMMAND))
1433 [mi setState: val.b_bool ? TRUE : FALSE ];
1440 if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING) free(val.psz_string);
1445 - (void)setupVarMenu:(NSMenu *)menu
1446 forMenuItem: (NSMenuItem *)parent
1447 target:(vlc_object_t *)p_object
1448 var:(const char *)psz_variable
1449 selector:(SEL)pf_callback
1452 vlc_value_t *val_list;
1457 /* remove previous items */
1458 [menu removeAllItems];
1460 /* we disable everything here, and enable it again when needed, below */
1461 [parent setEnabled:NO];
1464 if ([[parent title] isEqualToString: _NS("Aspect ratio")] == YES) {
1465 NSMenuItem *lmi_tmp2;
1466 lmi_tmp2 = [menu addItemWithTitle: _NS("Lock Aspect Ratio") action: @selector(lockVideosAspectRatio:) keyEquivalent: @""];
1467 [lmi_tmp2 setTarget: self];
1468 [lmi_tmp2 setEnabled: YES];
1469 [lmi_tmp2 setState: [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]];
1470 [parent setEnabled: YES];
1471 [menu addItem: [NSMenuItem separatorItem]];
1474 /* Check the type of the object variable */
1475 i_type = var_Type(p_object, psz_variable);
1477 /* Make sure we want to display the variable */
1478 if (i_type & VLC_VAR_HASCHOICE) {
1481 var_Change(p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &count);
1488 switch(i_type & VLC_VAR_TYPE) {
1491 case VLC_VAR_STRING:
1492 case VLC_VAR_INTEGER:
1495 /* Variable doesn't exist or isn't handled */
1499 if (var_Get(p_object, psz_variable, &val) < 0) {
1503 if (var_Change(p_object, psz_variable, VLC_VAR_GETCHOICES,
1504 &count, &val_list, &text_list) < 0) {
1505 if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING) free(val.psz_string);
1509 /* make (un)sensitive */
1510 [parent setEnabled: (count > 1)];
1512 for (i = 0; i < count; i++) {
1514 NSString *title = @"";
1515 VLCAutoGeneratedMenuContent *data;
1517 switch(i_type & VLC_VAR_TYPE) {
1518 case VLC_VAR_STRING:
1520 title = _NS(text_list[i] ? text_list[i] : val_list[i].psz_string);
1522 lmi = [menu addItemWithTitle: title action: pf_callback keyEquivalent: @""];
1523 data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
1524 andValue: val_list[i] ofType: i_type];
1525 [lmi setRepresentedObject:data];
1526 [lmi setTarget: self];
1528 if (!strcmp(val.psz_string, val_list[i].psz_string) && !(i_type & VLC_VAR_ISCOMMAND))
1529 [lmi setState: TRUE ];
1532 free(val_list[i].psz_string);
1535 case VLC_VAR_INTEGER:
1537 title = text_list[i] ?
1538 _NS(text_list[i]) : [NSString stringWithFormat: @"%"PRId64, val_list[i].i_int];
1540 lmi = [menu addItemWithTitle: title action: pf_callback keyEquivalent: @""];
1541 data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
1542 andValue: val_list[i] ofType: i_type];
1543 [lmi setRepresentedObject:data];
1544 [lmi setTarget: self];
1546 if (val_list[i].i_int == val.i_int && !(i_type & VLC_VAR_ISCOMMAND))
1547 [lmi setState: TRUE ];
1557 /* clean up everything */
1558 if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING) free(val.psz_string);
1563 - (void)toggleVar:(id)sender
1565 NSMenuItem *mi = (NSMenuItem *)sender;
1566 VLCAutoGeneratedMenuContent *data = [mi representedObject];
1567 [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
1568 toTarget: self withObject: data];
1573 - (int)toggleVarThread: (id)data
1576 vlc_object_t *p_object;
1578 assert([data isKindOfClass:[VLCAutoGeneratedMenuContent class]]);
1579 VLCAutoGeneratedMenuContent *menuContent = (VLCAutoGeneratedMenuContent *)data;
1581 p_object = [menuContent vlcObject];
1583 if (p_object != NULL) {
1584 var_Set(p_object, [menuContent name], [menuContent value]);
1585 vlc_object_release(p_object);
1588 return VLC_EGENERIC;
1592 #pragma mark - menu delegation
1594 - (void)menuWillOpen:(NSMenu *)menu
1596 [_cancelRendererDiscoveryTimer invalidate];
1597 [_rendererMenuController startRendererDiscoveries];
1600 - (void)menuDidClose:(NSMenu *)menu
1602 _cancelRendererDiscoveryTimer = [NSTimer scheduledTimerWithTimeInterval:20.
1604 selector:@selector(cancelRendererDiscovery)
1609 - (void)cancelRendererDiscovery
1611 [_rendererMenuController stopRendererDiscoveries];
1616 @implementation VLCMainMenu (NSMenuValidation)
1618 - (BOOL)validateMenuItem:(NSMenuItem *)mi
1622 playlist_t *p_playlist = pl_Get(getIntf());
1623 input_thread_t *p_input = playlist_CurrentInput(p_playlist);
1625 if (mi == _stop || mi == _voutMenustop || mi == _dockMenustop) {
1628 [self setupMenus]; /* Make sure input menu is up to date */
1629 } else if (mi == _previous ||
1630 mi == _voutMenuprev ||
1631 mi == _dockMenuprevious ||
1633 mi == _voutMenunext ||
1637 enabled = playlist_CurrentSize(p_playlist) > 1;
1639 } else if (mi == _record) {
1642 enabled = var_GetBool(p_input, "can-record");
1643 } else if (mi == _random) {
1645 var_Get(p_playlist, "random", &val);
1646 i_state = val.b_bool ? NSOnState : NSOffState;
1647 [mi setState: i_state];
1648 } else if (mi == _repeat) {
1650 var_Get(p_playlist, "repeat", &val);
1651 i_state = val.b_bool ? NSOnState : NSOffState;
1652 [mi setState: i_state];
1653 } else if (mi == _loop) {
1655 var_Get(p_playlist, "loop", &val);
1656 i_state = val.b_bool ? NSOnState : NSOffState;
1657 [mi setState: i_state];
1658 } else if (mi == _quitAfterPB) {
1660 bool b_value = var_InheritBool(p_playlist, "play-and-exit");
1661 i_state = b_value ? NSOnState : NSOffState;
1662 [mi setState: i_state];
1663 } else if (mi == _fwd || mi == _bwd || mi == _jumpToTime) {
1664 if (p_input != NULL) {
1665 var_Get(p_input, "can-seek", &val);
1666 enabled = val.b_bool;
1670 } else if (mi == _mute || mi == _dockMenumute || mi == _voutMenumute) {
1671 [mi setState: [[VLCCoreInteraction sharedInstance] mute] ? NSOnState : NSOffState];
1672 [self setupMenus]; /* Make sure audio menu is up to date */
1673 [self refreshAudioDeviceList];
1674 } else if (mi == _half_window ||
1675 mi == _normal_window ||
1676 mi == _double_window ||
1677 mi == _fittoscreen ||
1679 mi == _voutMenusnapshot ||
1680 mi == _fullscreenItem ||
1681 mi == _voutMenufullscreen ||
1686 if (p_input != NULL) {
1687 vout_thread_t *p_vout = getVoutForActiveWindow();
1688 if (p_vout != NULL) {
1689 if (mi == _floatontop)
1690 [mi setState: var_GetBool(p_vout, "video-on-top")];
1692 if (mi == _fullscreenItem || mi == _voutMenufullscreen)
1693 [mi setState: var_GetBool(p_vout, "fullscreen")];
1696 vlc_object_release(p_vout);
1700 [self setupMenus]; /* Make sure video menu is up to date */
1702 } else if (mi == _openSubtitleFile) {
1703 enabled = [mi isEnabled];
1704 [self setupMenus]; /* Make sure subtitles menu is up to date */
1706 NSMenuItem *_parent = [mi parentItem];
1707 if (_parent == _subtitle_size || mi == _subtitle_size ||
1708 _parent == _subtitle_textcolor || mi == _subtitle_textcolor ||
1709 _parent == _subtitle_bgcolor || mi == _subtitle_bgcolor ||
1710 _parent == _subtitle_bgopacity || mi == _subtitle_bgopacity ||
1711 _parent == _subtitle_outlinethickness || mi == _subtitle_outlinethickness ||
1712 _parent == _teletext || mi == _teletext
1714 enabled = _openSubtitleFile.isEnabled;
1719 vlc_object_release(p_input);
1727 /*****************************************************************************
1728 *VLCAutoGeneratedMenuContent implementation
1729 *****************************************************************************
1730 *Object connected to a playlistitem which remembers the data belonging to
1731 *the variable of the autogenerated menu
1732 *****************************************************************************/
1734 @interface VLCAutoGeneratedMenuContent ()
1737 vlc_object_t *vlc_object;
1742 @implementation VLCAutoGeneratedMenuContent
1744 -(id) initWithVariableName:(const char *)name ofObject:(vlc_object_t *)object
1745 andValue:(vlc_value_t)val ofType:(int)type
1747 self = [super init];
1750 vlc_object = vlc_object_hold(object);
1751 psz_name = strdup(name);
1754 if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING)
1755 value.psz_string = strdup(val.psz_string);
1764 vlc_object_release(vlc_object);
1765 if ((i_type & VLC_VAR_TYPE) == VLC_VAR_STRING)
1766 free(value.psz_string);
1770 - (const char *)name
1775 - (vlc_value_t)value
1780 - (vlc_object_t *)vlcObject
1782 return vlc_object_hold(vlc_object);