/***************************************************************************** * VLCSimplePrefsController.m: Simple Preferences for Mac OS X ***************************************************************************** * Copyright (C) 2008-2018 VLC authors and VideoLAN * $Id$ * * Authors: Felix Paul Kühne * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #import "CompatibilityFixes.h" #import "VLCSimplePrefsController.h" #import "prefs.h" #import #import #import #import #import #import #import "misc.h" #import "VLCMain.h" #import "VLCMain+OldPrefs.h" #import "AppleRemote.h" #import "VLCCoreInteraction.h" #import "NSScreen+VLCAdditions.h" #ifdef HAVE_SPARKLE #import //for o_intf_last_updateLabel #endif static struct { const char iso[6]; const char name[34]; BOOL isRightToLeft; } const language_map[] = { { "auto", N_("Auto"), NO }, { "en", "American English", NO }, { "ar", "عربي", YES }, { "an", "Aragonés", NO }, { "as_IN", "অসমীয়া", NO }, { "ast", "Asturianu", NO }, { "be", "беларуская мова", NO }, { "brx", "बर'/बड़", NO }, { "bn", "বাংলা", NO }, { "pt_BR", "Português Brasileiro", NO }, { "en_GB", "British English", NO }, { "my", "မြန်မာစာ", NO }, { "el", "Νέα Ελληνικά", NO }, { "bg", "български език", NO }, { "ca", "Català", NO }, { "zh_TW", "正體中文", NO }, { "co", "Corsu", NO }, { "cs", "Čeština", NO }, { "cy", "Cymraeg", NO }, { "da", "Dansk", NO }, { "nl", "Nederlands", NO }, { "fi", "Suomi", NO }, { "eo", "Esperanto", NO }, { "et", "eesti keel", NO }, { "eu", "Euskara", NO }, { "fr", "Français", NO }, { "ga", "Gaeilge", NO }, { "gd", "Gàidhlig", NO }, { "gl", "Galego", NO }, { "gu", "ગુજરાતી", NO }, { "de", "Deutsch", NO }, { "he", "עברית", YES }, { "hr", "hrvatski", NO }, { "kn", "ಕನ್ನಡ", NO }, { "lv", "Latviešu valoda", NO }, { "hu", "Magyar", NO }, { "mr", "मराठी", NO }, { "is", "íslenska", NO }, { "id", "Bahasa Indonesia", NO }, { "it", "Italiano", NO }, { "ie", "Interlingue", NO }, { "ja", "日本語", NO }, { "ko", "한국어", NO }, { "lt", "lietuvių", NO }, { "lo", "ລາວ", NO }, { "mk", "македонски", NO }, { "ms", "Melayu", NO }, { "nb", "Bokmål", NO }, { "nn", "Nynorsk", NO }, { "kk", "Қазақ тілі", NO }, { "km", "ភាសាខ្មែរ", NO }, { "ne", "नेपाली", NO }, { "oc", "Occitan", NO }, { "or_IN", "ଓଡ଼ିଆ", NO }, { "pl", "Polski", NO }, { "pt_PT", "Português", NO }, { "pa", "ਪੰਜਾਬੀ", NO }, { "ro", "Română", NO }, { "ru", "Русский", NO }, { "zh_CN", "简体中文", NO }, { "sm", "Gagana Sāmoa", NO }, { "si", "සිංහල", NO }, { "sr", "српски", NO }, { "sk", "Slovensky", NO }, { "sl", "slovenščina", NO }, { "es", "Español", NO }, { "es_MX", "Español Mexicano", NO }, { "sv", "Svenska", NO }, { "sw", "كِسوَحِيلِ", YES }, { "th", "ภาษาไทย", NO }, { "tr", "Türkçe", NO }, { "uk", "украї́нська мо́ва", NO }, { "vi", "tiếng Việt", NO }, { "wa", "Walon", NO } }; static NSString* VLCSPrefsToolbarIdentifier = @"Our Simple Preferences Toolbar Identifier"; static NSString* VLCIntfSettingToolbarIdentifier = @"Intf Settings Item Identifier"; static NSString* VLCAudioSettingToolbarIdentifier = @"Audio Settings Item Identifier"; static NSString* VLCVideoSettingToolbarIdentifier = @"Video Settings Item Identifier"; static NSString* VLCOSDSettingToolbarIdentifier = @"Subtitles Settings Item Identifier"; static NSString* VLCInputSettingToolbarIdentifier = @"Input Settings Item Identifier"; static NSString* VLCHotkeysSettingToolbarIdentifier = @"Hotkeys Settings Item Identifier"; @interface VLCSimplePrefsController() { BOOL _audioSettingChanged; BOOL _intfSettingChanged; BOOL _videoSettingChanged; BOOL _osdSettingChanged; BOOL _inputSettingChanged; BOOL _hotkeyChanged; NSOpenPanel *_selectFolderPanel; NSArray *_hotkeyDescriptions; NSArray *_hotkeyNames; NSArray *_hotkeysNonUseableKeys; NSMutableArray *_hotkeySettings; NSString *_keyInTransition; intf_thread_t *p_intf; } @end @implementation VLCSimplePrefsController #pragma mark Initialisation - (id)init { self = [super initWithWindowNibName:@"SimplePreferences"]; if (self) { p_intf = getIntf(); } return self; } - (void)windowDidLoad { [self initStrings]; #ifdef HAVE_SPARKLE [_intf_updateCheckbox bind:@"value" toObject:[SUUpdater sharedUpdater] withKeyPath:@"automaticallyChecksForUpdates" options:nil]; #else [_intf_updateCheckbox setState:NSOffState]; [_intf_updateCheckbox setEnabled:NO]; #endif /* setup the toolbar */ NSToolbar * toolbar = [[NSToolbar alloc] initWithIdentifier: VLCSPrefsToolbarIdentifier]; [toolbar setAllowsUserCustomization: NO]; [toolbar setAutosavesConfiguration: NO]; [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel]; [toolbar setSizeMode: NSToolbarSizeModeRegular]; [toolbar setDelegate: self]; [self.window setToolbar:toolbar]; [self.window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary]; [self.window setHidesOnDeactivate:YES]; [_hotkeys_listbox setTarget:self]; [_hotkeys_listbox setDoubleAction:@selector(hotkeyTableDoubleClick:)]; /* setup useful stuff */ _hotkeysNonUseableKeys = [NSArray arrayWithObjects:@"Command-c", @"Command-x", @"Command-v", @"Command-a", @"Command-," , @"Command-h", @"Command-Alt-h", @"Command-Shift-o", @"Command-o", @"Command-d", @"Command-n", @"Command-s", @"Command-l", @"Command-r", @"Command-3", @"Command-m", @"Command-w", @"Command-Shift-w", @"Command-Shift-c", @"Command-Shift-p", @"Command-i", @"Command-e", @"Command-Shift-e", @"Command-b", @"Command-Shift-m", @"Command-Ctrl-m", @"Command-?", @"Command-Alt-?", @"Command-Shift-f", nil]; // Workaround for Mac OS X Lion, which does not apply the same constraints when set in IB NSView *clipView = _contentView.superview; NSDictionary *views = @{ @"view": _contentView }; NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|[view]|" options:0 metrics:nil views:views]; [clipView addConstraints:constraints]; } #define CreateToolbarItem(name, desc, img, sel) \ toolbarItem = create_toolbar_item(itemIdent, name, desc, img, self, @selector(sel)); static inline NSToolbarItem * create_toolbar_item(NSString *itemIdent, NSString *name, NSString *desc, NSString *img, id target, SEL selector) { NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier: itemIdent]; [toolbarItem setLabel:name]; [toolbarItem setPaletteLabel:desc]; [toolbarItem setToolTip:desc]; [toolbarItem setImage:[NSImage imageNamed:img]]; [toolbarItem setTarget:target]; [toolbarItem setAction:selector]; [toolbarItem setEnabled:YES]; [toolbarItem setAutovalidates:YES]; return toolbarItem; } - (NSToolbarItem *) toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdent willBeInsertedIntoToolbar:(BOOL)willBeInserted { NSToolbarItem *toolbarItem = nil; if ([itemIdent isEqual: VLCIntfSettingToolbarIdentifier]) { CreateToolbarItem(_NS("Interface"), _NS("Interface Settings"), @"VLCInterfaceCone", showInterfaceSettings); } else if ([itemIdent isEqual: VLCAudioSettingToolbarIdentifier]) { CreateToolbarItem(_NS("Audio"), _NS("Audio Settings"), @"VLCAudioCone", showAudioSettings); } else if ([itemIdent isEqual: VLCVideoSettingToolbarIdentifier]) { CreateToolbarItem(_NS("Video"), _NS("Video Settings"), @"VLCVideoCone", showVideoSettings); } else if ([itemIdent isEqual: VLCOSDSettingToolbarIdentifier]) { CreateToolbarItem(_NS(SUBPIC_TITLE), _NS("Subtitle & On Screen Display Settings"), @"VLCSubtitleCone", showOSDSettings); } else if ([itemIdent isEqual: VLCInputSettingToolbarIdentifier]) { CreateToolbarItem(_NS(INPUT_TITLE), _NS("Input & Codec Settings"), @"VLCInputCone", showInputSettings); } else if ([itemIdent isEqual: VLCHotkeysSettingToolbarIdentifier]) { CreateToolbarItem(_NS("Hotkeys"), _NS("Hotkeys settings"), @"VLCHotkeysCone", showHotkeySettings); } return toolbarItem; } - (NSArray *)toolbarDefaultItemIdentifiers: (NSToolbar *)toolbar { return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier, VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier, NSToolbarFlexibleSpaceItemIdentifier, nil]; } - (NSArray *)toolbarAllowedItemIdentifiers: (NSToolbar *)toolbar { return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier, VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier, NSToolbarFlexibleSpaceItemIdentifier, nil]; } - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar { return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier, VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier, nil]; } - (void)initStrings { /* audio */ [_audio_effectsBox setTitle: _NS("Audio Effects")]; [_audio_enableCheckbox setTitle: _NS("Enable audio")]; [_audio_generalBox setTitle: _NS("General Audio")]; [_audio_langLabel setStringValue: _NS("Preferred Audio language")]; [_audio_lastCheckbox setTitle: _NS("Enable Last.fm submissions")]; [_audio_lastpwdLabel setStringValue: _NS("Password")]; [_audio_lastuserLabel setStringValue: _NS("Username")]; [_audio_visualLabel setStringValue: _NS("Visualization")]; [_audio_autosavevol_yesButtonCell setTitle: _NS("Keep audio level between sessions")]; [_audio_autosavevol_noButtonCell setTitle: _NS("Always reset audio start level to:")]; /* hotkeys */ [_hotkeys_changeButton setTitle: _NS("Change")]; [_hotkeys_change_win setTitle: _NS("Change Hotkey")]; [_hotkeys_change_cancelButton setTitle: _NS("Cancel")]; [_hotkeys_change_okButton setTitle: _NS("OK")]; [_hotkeys_clearButton setTitle: _NS("Clear")]; [_hotkeysLabel setStringValue: _NS("Select an action to change the associated hotkey:")]; [[[_hotkeys_listbox tableColumnWithIdentifier: @"action"] headerCell] setStringValue: _NS("Action")]; [[[_hotkeys_listbox tableColumnWithIdentifier: @"shortcut"] headerCell] setStringValue: _NS("Shortcut")]; /* input */ [_input_recordBox setTitle: _NS("Record directory or filename")]; [_input_recordButton setTitle: _NS("Browse...")]; [_input_recordButton setToolTip: _NS("Directory or filename where the records will be stored")]; [_input_aviLabel setStringValue: _NS("Repair AVI Files")]; [_input_cachelevelLabel setStringValue: _NS("Default Caching Level")]; [_input_cachingBox setTitle: _NS("Caching")]; [_input_cachelevel_customLabel setStringValue: _NS("Use the complete preferences to configure custom caching values for each access module.")]; [_input_muxBox setTitle: _NS("Codecs / Muxers")]; [_input_netBox setTitle: _NS("Network")]; [_input_hardwareAccelerationCheckbox setTitle: _NS("Hardware decoding")]; [_input_postprocLabel setStringValue: _NS("Post-Processing Quality")]; [_input_skipLoopLabel setStringValue: _NS("Skip the loop filter for H.264 decoding")]; [_input_urlhandlerButton setTitle: _NS("Edit default application settings for network protocols")]; [_input_skipFramesCheckbox setTitle: _NS("Skip frames")]; /* url handler */ [_urlhandler_titleLabel setStringValue: _NS("Open network streams using the following protocols")]; [_urlhandler_subtitleLabel setStringValue: _NS("Note that these are system-wide settings.")]; [_urlhandler_saveButton setTitle: _NS("Save")]; [_urlhandler_cancelButton setTitle: _NS("Cancel")]; /* interface */ [_intf_generalSettingsBox setTitle:_NS("General settings")]; [_intf_languageLabel setStringValue: _NS("Language")]; [_intf_styleLabel setStringValue: _NS("Interface style")]; [_intf_style_darkButtonCell setTitle: _NS("Dark")]; [_intf_style_brightButtonCell setTitle: _NS("Bright")]; [_intf_playbackControlBox setTitle:_NS("Playback control")]; [_intf_continueplaybackLabel setStringValue:_NS("Continue playback")]; [_intf_appleremoteCheckbox setTitle: _NS("Control playback with the Apple Remote")]; [_intf_mediakeysCheckbox setTitle: _NS("Control playback with media keys")]; [_intf_appleremote_sysvolCheckbox setTitle: _NS("Control system volume with the Apple Remote")]; [_intf_statusIconCheckbox setTitle: _NS("Display VLC status menu icon")]; [_intf_playbackBehaviourBox setTitle:_NS("Playback behaviour")]; [_intf_enableNotificationsCheckbox setTitle: _NS("Enable notifications on playlist item change")]; [_intf_pauseitunesLabel setStringValue:_NS("Control external music players")]; [_intf_networkBox setTitle: _NS("Privacy / Network Interaction")]; [_intf_artCheckbox setTitle: _NS("Allow metadata network access")]; [_intf_updateCheckbox setTitle: _NS("Automatically check for updates")]; [_intf_last_updateLabel setStringValue: @""]; [_intf_luahttpBox setTitle:_NS("HTTP web interface")]; [_intf_enableluahttpCheckbox setTitle: _NS("Enable HTTP web interface")]; [_intf_luahttppwdLabel setStringValue:_NS("Password")]; /* Subtitles and OSD */ [_osd_encodingLabel setStringValue: _NS("Default Encoding")]; [_osd_fontBox setTitle: _NS("Display Settings")]; [_osd_fontButton setTitle: _NS("Choose...")]; [_osd_font_colorLabel setStringValue: _NS("Font color")]; [_osd_font_sizeLabel setStringValue: _NS("Font size")]; [_osd_fontLabel setStringValue: _NS("Font")]; [_osd_langBox setTitle: _NS("Subtitle languages")]; [_osd_langLabel setStringValue: _NS("Preferred subtitle language")]; [_osd_osdBox setTitle: _NS("On Screen Display")]; [_osd_osdCheckbox setTitle: _NS("Enable OSD")]; [_osd_opacityLabel setStringValue: _NS("Opacity")]; [_osd_forceboldCheckbox setTitle: _NS("Force bold")]; [_osd_outline_colorLabel setStringValue: _NS("Outline color")]; [_osd_outline_thicknessLabel setStringValue: _NS("Outline thickness")]; /* video */ [_video_enableCheckbox setTitle: _NS("Enable video")]; [_video_displayBox setTitle: _NS("Display")]; [_video_embeddedCheckbox setTitle: _NS("Show video within the main window")]; [_video_pauseWhenMinimizedCheckbox setTitle:_NS("Pause the video playback when minimized")]; [_video_onTopCheckbox setTitle: _NS("Float on Top")]; [_video_videodecoCheckbox setTitle: _NS("Window decorations")]; [_video_fullscreenBox setTitle:_NS("Fullscreen settings")]; [_video_startInFullscreenCheckbox setTitle:_NS("Start in fullscreen")]; [_video_blackScreenCheckbox setTitle: _NS("Black screens in Fullscreen mode")]; [_video_nativeFullscreenCheckbox setTitle: _NS("Use the native fullscreen mode")]; [_video_deviceLabel setStringValue: _NS("Fullscreen Video Device")]; [_video_snapBox setTitle: _NS("Video snapshots")]; [_video_snap_folderButton setTitle: _NS("Browse...")]; [_video_snap_folderLabel setStringValue: _NS("Folder")]; [_video_snap_formatLabel setStringValue: _NS("Format")]; [_video_snap_prefixLabel setStringValue: _NS("Prefix")]; [_video_snap_seqnumCheckbox setTitle: _NS("Sequential numbering")]; [_video_deinterlaceLabel setStringValue: _NS("Deinterlace")]; [_video_deinterlace_modeLabel setStringValue: _NS("Deinterlace mode")]; [_video_videoBox setTitle: _NS("Video")]; /* generic stuff */ [_showAllButton setTitle: _NS("Show All")]; [_cancelButton setTitle: _NS("Cancel")]; [_resetButton setTitle: _NS("Reset All")]; [_saveButton setTitle: _NS("Save")]; [self.window setTitle: _NS("Preferences")]; } /* TODO: move this part to core */ #define config_GetLabel(a,b) __config_GetLabel(VLC_OBJECT(a),b) static inline const char * __config_GetLabel(vlc_object_t *p_this, const char *psz_name) { module_config_t *p_config = config_FindConfig(psz_name); /* sanity checks */ if (!p_config) { msg_Err(p_this, "option %s does not exist", psz_name); return NULL; } if (p_config->psz_longtext) return p_config->psz_longtext; else if (p_config->psz_text) return p_config->psz_text; else msg_Warn(p_this, "option %s does not include any help", psz_name); return NULL; } #pragma mark - #pragma mark Setup controls - (void)setupButton: (NSPopUpButton *)object forStringList: (const char *)name { module_config_t *p_item; [object removeAllItems]; p_item = config_FindConfig(name); /* serious problem, if no item found */ assert(p_item); char **values, **texts; ssize_t count = config_GetPszChoices(VLC_OBJECT(getIntf()), name, &values, &texts); if (count < 0) { msg_Err(p_intf, "Cannot get choices for %s", name); return; } for (ssize_t i = 0; i < count && texts; i++) { if (texts[i] == NULL || values[i] == NULL) continue; if (strcmp(texts[i], "") != 0) { NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""]; [mi setRepresentedObject: toNSStr(values[i])]; [[object menu] addItem:mi]; if (p_item->value.psz && !strcmp(p_item->value.psz, values[i])) [object selectItem: [object lastItem]]; } else { [[object menu] addItem: [NSMenuItem separatorItem]]; } free(texts[i]); free(values[i]); } free(texts); free(values); if (p_item->psz_longtext) [object setToolTip: _NS(p_item->psz_longtext)]; } // just for clarification that this is a module list - (void)setupButton: (NSPopUpButton *)object forModuleList: (const char *)name { [self setupButton: object forStringList: name]; } - (void)setupButton: (NSPopUpButton *)object forIntList: (const char *)name { module_config_t *p_item; [object removeAllItems]; p_item = config_FindConfig(name); /* serious problem, if no item found */ assert(p_item); int64_t *values; char **texts; ssize_t count = config_GetIntChoices(VLC_OBJECT(getIntf()), name, &values, &texts); for (ssize_t i = 0; i < count; i++) { NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""]; [mi setRepresentedObject:[NSNumber numberWithInt:values[i]]]; [[object menu] addItem:mi]; if (p_item->value.i == values[i]) [object selectItem:[object lastItem]]; free(texts[i]); } free(texts); if (p_item->psz_longtext) [object setToolTip: _NS(p_item->psz_longtext)]; } - (void)setupButton: (NSButton *)object forBoolValue: (const char *)name { [object setState: config_GetInt(p_intf, name)]; [object setToolTip: _NS(config_GetLabel(p_intf, name))]; } - (void)setupField:(NSTextField *)object forOption:(const char *)psz_option { char *psz_tmp = config_GetPsz(p_intf, psz_option); [object setStringValue: toNSStr(psz_tmp)]; [object setToolTip: _NS(config_GetLabel(p_intf, psz_option))]; free(psz_tmp); } - (BOOL)hasModule:(NSString *)moduleName inConfig:(NSString *)config { char *value = config_GetPsz(p_intf, [config UTF8String]); NSString *modules = toNSStr(value); free(value); return [[modules componentsSeparatedByString:@":"] containsObject:moduleName]; } - (void)changeModule:(NSString *)moduleName inConfig:(NSString *)config enable:(BOOL)enable { char *value = config_GetPsz(p_intf, [config UTF8String]); NSString *modules = toNSStr(value); free(value); NSMutableArray *components = [[modules componentsSeparatedByString:@":"] mutableCopy]; if (enable) { if (![components containsObject:moduleName]) { [components addObject:moduleName]; } } else { [components removeObject:moduleName]; } // trim empty entries [components removeObject:@""]; config_PutPsz(p_intf, [config UTF8String], [[components componentsJoinedByString:@":"] UTF8String]); } - (void)resetControls { module_config_t *p_item; int i, y = 0; char *psz_tmp; /********************** * interface settings * **********************/ NSUInteger sel = 0; const char *pref = NULL; pref = [[[NSUserDefaults standardUserDefaults] objectForKey:@"language"] UTF8String]; for (int x = 0; x < ARRAY_SIZE(language_map); x++) { [_intf_languagePopup addItemWithTitle:toNSStr(language_map[x].name)]; if (pref) { if (!strcmp(language_map[x].iso, pref)) sel = x; } } [_intf_languagePopup selectItemAtIndex:sel]; [self setupButton:_intf_continueplaybackPopup forIntList: "macosx-continue-playback"]; if (!var_InheritBool(p_intf, "macosx-recentitems")) { [_intf_continueplaybackPopup setEnabled: NO]; [_intf_continueplaybackPopup setToolTip: _NS("Media files cannot be resumed because keeping recent media items is disabled.")]; } else { [_intf_continueplaybackPopup setEnabled: YES]; } [self setupButton:_intf_appleremoteCheckbox forBoolValue: "macosx-appleremote"]; [self setupButton:_intf_appleremote_sysvolCheckbox forBoolValue: "macosx-appleremote-sysvol"]; [self setupButton:_intf_statusIconCheckbox forBoolValue: "macosx-statusicon"]; [self setupButton:_intf_mediakeysCheckbox forBoolValue: "macosx-mediakeys"]; [self setupButton:_video_nativeFullscreenCheckbox forBoolValue: "macosx-nativefullscreenmode"]; [self setupButton:_video_embeddedCheckbox forBoolValue: "embedded-video"]; [self setupButton:_intf_pauseitunesPopup forIntList: "macosx-control-itunes"]; [self setupButton:_intf_artCheckbox forBoolValue: "metadata-network-access"]; #ifdef HAVE_SPARKLE if ([[SUUpdater sharedUpdater] lastUpdateCheckDate] != NULL) [_intf_last_updateLabel setStringValue: [NSString stringWithFormat: _NS("Last check on: %@"), [[[SUUpdater sharedUpdater] lastUpdateCheckDate] descriptionWithLocale: [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]]]; else [_intf_last_updateLabel setStringValue: _NS("No check was performed yet.")]; #endif BOOL growlEnabled = [self hasModule:@"growl" inConfig:@"control"]; [_intf_enableNotificationsCheckbox setState: growlEnabled ? NSOnState : NSOffState]; if (config_GetInt(p_intf, "macosx-interfacestyle")) { [_intf_style_darkButtonCell setState: YES]; [_intf_style_brightButtonCell setState: NO]; } else { [_intf_style_darkButtonCell setState: NO]; [_intf_style_brightButtonCell setState: YES]; } BOOL httpEnabled = [self hasModule:@"http" inConfig:@"extraintf"]; [_intf_enableluahttpCheckbox setState: httpEnabled ? NSOnState : NSOffState]; _intf_luahttppwdTextField.enabled = httpEnabled; [self setupField:_intf_luahttppwdTextField forOption: "http-password"]; /****************** * audio settings * ******************/ [self setupButton:_audio_enableCheckbox forBoolValue: "audio"]; if (config_GetInt(p_intf, "volume-save")) { [_audio_autosavevol_yesButtonCell setState: NSOnState]; [_audio_autosavevol_noButtonCell setState: NSOffState]; [_audio_volTextField setEnabled: NO]; [_audio_volSlider setEnabled: NO]; [_audio_volSlider setIntValue: 100]; [_audio_volTextField setIntValue: 100]; } else { [_audio_autosavevol_yesButtonCell setState: NSOffState]; [_audio_autosavevol_noButtonCell setState: NSOnState]; [_audio_volTextField setEnabled: YES]; [_audio_volSlider setEnabled: YES]; i = var_InheritInteger(p_intf, "auhal-volume"); i = i * 200. / AOUT_VOLUME_MAX; [_audio_volSlider setIntValue: i]; [_audio_volTextField setIntValue: i]; } [self setupField:_audio_langTextField forOption: "audio-language"]; [self setupButton:_audio_visualPopup forModuleList: "audio-visual"]; /* Last.FM is optional */ if (module_exists("audioscrobbler")) { [self setupField:_audio_lastuserTextField forOption:"lastfm-username"]; [self setupField:_audio_lastpwdSecureTextField forOption:"lastfm-password"]; if (config_ExistIntf(VLC_OBJECT(p_intf), "audioscrobbler")) { [_audio_lastCheckbox setState: NSOnState]; [_audio_lastuserTextField setEnabled: YES]; [_audio_lastpwdSecureTextField setEnabled: YES]; } else { [_audio_lastCheckbox setState: NSOffState]; [_audio_lastuserTextField setEnabled: NO]; [_audio_lastpwdSecureTextField setEnabled: NO]; } } else [_audio_lastCheckbox setEnabled: NO]; /****************** * video settings * ******************/ [self setupButton:_video_enableCheckbox forBoolValue: "video"]; [self setupButton:_video_startInFullscreenCheckbox forBoolValue: "fullscreen"]; [self setupButton:_video_onTopCheckbox forBoolValue: "video-on-top"]; [self setupButton:_video_blackScreenCheckbox forBoolValue: "macosx-black"]; [self setupButton:_video_videodecoCheckbox forBoolValue: "video-deco"]; [self setupButton:_video_pauseWhenMinimizedCheckbox forBoolValue: "macosx-pause-minimized"]; [_video_devicePopup removeAllItems]; i = 0; y = [[NSScreen screens] count]; [_video_devicePopup addItemWithTitle: _NS("Default")]; [[_video_devicePopup lastItem] setTag: 0]; while (i < y) { NSRect s_rect = [[[NSScreen screens] objectAtIndex:i] frame]; [_video_devicePopup addItemWithTitle: [NSString stringWithFormat: @"%@ %i (%ix%i)", _NS("Screen"), i+1, (int)s_rect.size.width, (int)s_rect.size.height]]; [[_video_devicePopup lastItem] setTag: (int)[[[NSScreen screens] objectAtIndex:i] displayID]]; i++; } [_video_devicePopup selectItemAtIndex: 0]; [_video_devicePopup selectItemWithTag: config_GetInt(p_intf, "macosx-vdev")]; [self setupField:_video_snap_folderTextField forOption:"snapshot-path"]; [self setupField:_video_snap_prefixTextField forOption:"snapshot-prefix"]; [self setupButton:_video_snap_seqnumCheckbox forBoolValue: "snapshot-sequential"]; [self setupButton:_video_snap_formatPopup forStringList: "snapshot-format"]; [self setupButton:_video_deinterlacePopup forIntList: "deinterlace"]; [self setupButton:_video_deinterlace_modePopup forStringList: "deinterlace-mode"]; // set lion fullscreen mode restrictions [self enableLionFullscreenMode: [_video_nativeFullscreenCheckbox state]]; /*************************** * input & codecs settings * ***************************/ [self setupField:_input_recordTextField forOption:"input-record-path"]; [self setupButton:_input_hardwareAccelerationCheckbox forBoolValue: "videotoolbox"]; [_input_postprocTextField setIntValue: config_GetInt(p_intf, "postproc-q")]; [_input_postprocTextField setToolTip: _NS(config_GetLabel(p_intf, "postproc-q"))]; [self setupButton:_input_skipFramesCheckbox forBoolValue: "skip-frames"]; [self setupButton:_input_aviPopup forIntList: "avi-index"]; [self setupButton:_input_skipLoopPopup forIntList: "avcodec-skiploopfilter"]; [_input_cachelevelPopup removeAllItems]; NSMenuItem *item = [[_input_cachelevelPopup menu] addItemWithTitle:_NS("Custom") action:nil keyEquivalent:@""]; [item setTag: 0]; item = [[_input_cachelevelPopup menu] addItemWithTitle:_NS("Lowest Latency") action:nil keyEquivalent:@""]; [item setTag: 100]; item = [[_input_cachelevelPopup menu] addItemWithTitle:_NS("Low Latency") action:nil keyEquivalent:@""]; [item setTag: 200]; item = [[_input_cachelevelPopup menu] addItemWithTitle:_NS("Normal") action:nil keyEquivalent:@""]; [item setTag: 300]; item = [[_input_cachelevelPopup menu] addItemWithTitle:_NS("Higher Latency") action:nil keyEquivalent:@""]; [item setTag: 500]; item = [[_input_cachelevelPopup menu] addItemWithTitle:_NS("Highest Latency") action:nil keyEquivalent:@""]; [item setTag: 1000]; #define TestCaC(name, factor) \ cache_equal = cache_equal && \ (i_cache * factor == config_GetInt(p_intf, name)); /* Select the accurate value of the PopupButton */ bool cache_equal = true; int i_cache = config_GetInt(p_intf, "file-caching"); TestCaC("network-caching", 10/3); TestCaC("disc-caching", 1); TestCaC("live-caching", 1); if (cache_equal) { [_input_cachelevelPopup selectItemWithTag: i_cache]; [_input_cachelevel_customLabel setHidden: YES]; } else { [_input_cachelevelPopup selectItemWithTitle: _NS("Custom")]; [_input_cachelevel_customLabel setHidden: NO]; } #undef TestCaC /********************* * subtitle settings * *********************/ [self setupButton:_osd_osdCheckbox forBoolValue: "osd"]; [self setupButton:_osd_encodingPopup forStringList: "subsdec-encoding"]; [self setupField:_osd_langTextField forOption: "sub-language" ]; [self setupField:_osd_fontTextField forOption: "freetype-font"]; [self setupButton:_osd_font_colorPopup forIntList: "freetype-color"]; [self setupButton:_osd_font_sizePopup forIntList: "freetype-rel-fontsize"]; i = config_GetInt(p_intf, "freetype-opacity") * 100.0 / 255.0 + 0.5; [_osd_opacityTextField setIntValue: i]; [_osd_opacitySlider setIntValue: i]; [_osd_opacitySlider setToolTip: _NS(config_GetLabel(p_intf, "freetype-opacity"))]; [_osd_opacityTextField setToolTip: [_osd_opacitySlider toolTip]]; [self setupButton:_osd_forceboldCheckbox forBoolValue: "freetype-bold"]; [self setupButton:_osd_outline_colorPopup forIntList: "freetype-outline-color"]; [self setupButton:_osd_outline_thicknessPopup forIntList: "freetype-outline-thickness"]; /******************** * hotkeys settings * ********************/ _hotkeySettings = [[NSMutableArray alloc] init]; NSMutableArray *tempArray_desc = [[NSMutableArray alloc] init]; NSMutableArray *tempArray_names = [[NSMutableArray alloc] init]; /* Get the main Module */ module_t *p_main = module_get_main(); assert(p_main); unsigned confsize; module_config_t *p_config; p_config = module_config_get (p_main, &confsize); for (size_t i = 0; i < confsize; i++) { module_config_t *p_item = p_config + i; if (CONFIG_ITEM(p_item->i_type) && p_item->psz_name != NULL && !strncmp(p_item->psz_name , "key-", 4) && !EMPTY_STR(p_item->psz_text)) { [tempArray_desc addObject: _NS(p_item->psz_text)]; [tempArray_names addObject: toNSStr(p_item->psz_name)]; if (p_item->value.psz) [_hotkeySettings addObject: toNSStr(p_item->value.psz)]; else [_hotkeySettings addObject: [NSString string]]; } } module_config_free (p_config); _hotkeyDescriptions = [[NSArray alloc] initWithArray:tempArray_desc copyItems: YES]; _hotkeyNames = [[NSArray alloc] initWithArray:tempArray_names copyItems: YES]; [_hotkeys_listbox reloadData]; } #pragma mark - #pragma mark General actions - (void)showSimplePrefs { /* we want to show the interface settings, if no category was chosen */ if ([[self.window toolbar] selectedItemIdentifier] == nil) { [[self.window toolbar] setSelectedItemIdentifier: VLCIntfSettingToolbarIdentifier]; [self showInterfaceSettings]; } [self resetControls]; [self.window makeKeyAndOrderFront: self]; } - (void)showSimplePrefsWithLevel:(NSInteger)i_window_level { [self.window setLevel: i_window_level]; [self showSimplePrefs]; } - (IBAction)buttonAction:(id)sender { if (sender == _cancelButton) { [[NSFontPanel sharedFontPanel] close]; [self.window orderOut: sender]; } else if (sender == _saveButton) { [self saveChangedSettings]; [[NSFontPanel sharedFontPanel] close]; [self.window orderOut: sender]; } else if (sender == _showAllButton) { [self.window orderOut: self]; [[[VLCMain sharedInstance] preferences] showPrefsWithLevel:[self.window level]]; } else msg_Warn(p_intf, "unknown buttonAction sender"); } - (IBAction)resetPreferences:(NSControl *)sender { NSBeginInformationalAlertSheet(_NS("Reset Preferences"), _NS("Cancel"), _NS("Continue"), nil, [sender window], self, @selector(sheetDidEnd: returnCode: contextInfo:), NULL, nil, @"%@", _NS("This will reset VLC media player's preferences.\n\n" "Note that VLC will restart during the process, so your current " "playlist will be emptied and eventual playback, streaming or " "transcoding activities will stop immediately.\n\n" "The Media Library will not be affected.\n\n" "Are you sure you want to continue?")); } - (void)sheetDidEnd:(NSWindow *)o_sheet returnCode:(int)i_return contextInfo:(void *)o_context { if (i_return == NSAlertAlternateReturn) { /* reset VLC's config */ config_ResetAll(p_intf); [self resetControls]; /* force config file creation, since libvlc won't exit normally */ config_SaveConfigFile(p_intf); /* reset OS X defaults */ [[VLCMain sharedInstance] resetAndReinitializeUserDefaults]; /* Relaunch now */ const char * path = [[[NSBundle mainBundle] executablePath] UTF8String]; /* For some reason we need to fork(), not just execl(), which reports a ENOTSUP then. */ if (fork() != 0) { exit(0); return; } execl(path, path, NULL); } } static inline void save_int_list(intf_thread_t * p_intf, id object, const char * name) { NSNumber *p_valueobject = (NSNumber *)[[object selectedItem] representedObject]; if (p_valueobject) { assert([p_valueobject isKindOfClass:[NSNumber class]]); config_PutInt(p_intf, name, [p_valueobject intValue]); } } static inline void save_string_list(intf_thread_t * p_intf, id object, const char * name) { NSString *p_stringobject = (NSString *)[[object selectedItem] representedObject]; if (p_stringobject) { assert([p_stringobject isKindOfClass:[NSString class]]); config_PutPsz(p_intf, name, [p_stringobject UTF8String]); } } + (BOOL)updateRightToLeftSettings { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *isoCode = [defaults stringForKey:@"language"]; if (!isoCode || [isoCode isEqualToString:@"auto"]) { // Automatic handling of right to left [defaults removeObjectForKey:@"NSForceRightToLeftWritingDirection"]; [defaults removeObjectForKey:@"AppleTextDirection"]; } else { for(int i = 0; i < ARRAY_SIZE(language_map); i++) { if (!strcmp(language_map[i].iso, [isoCode UTF8String])) { [defaults setBool:language_map[i].isRightToLeft forKey:@"NSForceRightToLeftWritingDirection"]; [defaults setBool:language_map[i].isRightToLeft forKey:@"AppleTextDirection"]; return YES; } } } return NO; } - (void)saveChangedSettings { #define SaveIntList(object, name) save_int_list(p_intf, object, name) #define SaveStringList(object, name) save_string_list(p_intf, object, name) #define SaveModuleList(object, name) SaveStringList(object, name) /********************** * interface settings * **********************/ if (_intfSettingChanged) { NSUInteger index = [_intf_languagePopup indexOfSelectedItem]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:toNSStr(language_map[index].iso) forKey:@"language"]; [VLCSimplePrefsController updateRightToLeftSettings]; [defaults synchronize]; config_PutInt(p_intf, "metadata-network-access", [_intf_artCheckbox state]); config_PutInt(p_intf, "macosx-appleremote", [_intf_appleremoteCheckbox state]); config_PutInt(p_intf, "macosx-appleremote-sysvol", [_intf_appleremote_sysvolCheckbox state]); config_PutInt(p_intf, "macosx-statusicon", [_intf_statusIconCheckbox state]); config_PutInt(p_intf, "macosx-mediakeys", [_intf_mediakeysCheckbox state]); config_PutInt(p_intf, "macosx-interfacestyle", [_intf_style_darkButtonCell state]); [self changeModule:@"growl" inConfig:@"control" enable:[_intf_enableNotificationsCheckbox state] == NSOnState]; [self changeModule:@"http" inConfig:@"extraintf" enable:[_intf_enableluahttpCheckbox state] == NSOnState]; config_PutPsz(p_intf, "http-password", [[_intf_luahttppwdTextField stringValue] UTF8String]); SaveIntList(_intf_pauseitunesPopup, "macosx-control-itunes"); SaveIntList(_intf_continueplaybackPopup, "macosx-continue-playback"); /* activate stuff without restart */ if ([_intf_appleremoteCheckbox state] == YES) [[VLCCoreInteraction sharedInstance] startListeningWithAppleRemote]; else [[VLCCoreInteraction sharedInstance] stopListeningWithAppleRemote]; _intfSettingChanged = NO; } /****************** * audio settings * ******************/ if (_audioSettingChanged) { config_PutInt(p_intf, "audio", [_audio_enableCheckbox state]); config_PutInt(p_intf, "volume-save", [_audio_autosavevol_yesButtonCell state]); var_SetBool(p_intf, "volume-save", [_audio_autosavevol_yesButtonCell state]); if ([_audio_volTextField isEnabled]) config_PutInt(p_intf, "auhal-volume", ([_audio_volTextField intValue] * AOUT_VOLUME_MAX) / 200); config_PutPsz(p_intf, "audio-language", [[_audio_langTextField stringValue] UTF8String]); SaveModuleList(_audio_visualPopup, "audio-visual"); /* Last.FM is optional */ if (module_exists("audioscrobbler")) { [_audio_lastCheckbox setEnabled: YES]; if ([_audio_lastCheckbox state] == NSOnState) config_AddIntf(p_intf, "audioscrobbler"); else config_RemoveIntf(p_intf, "audioscrobbler"); config_PutPsz(p_intf, "lastfm-username", [[_audio_lastuserTextField stringValue] UTF8String]); config_PutPsz(p_intf, "lastfm-password", [[_audio_lastpwdSecureTextField stringValue] UTF8String]); } else [_audio_lastCheckbox setEnabled: NO]; _audioSettingChanged = NO; } /****************** * video settings * ******************/ if (_videoSettingChanged) { config_PutInt(p_intf, "video", [_video_enableCheckbox state]); config_PutInt(p_intf, "fullscreen", [_video_startInFullscreenCheckbox state]); config_PutInt(p_intf, "video-deco", [_video_videodecoCheckbox state]); config_PutInt(p_intf, "video-on-top", [_video_onTopCheckbox state]); config_PutInt(p_intf, "macosx-black", [_video_blackScreenCheckbox state]); config_PutInt(p_intf, "macosx-pause-minimized", [_video_pauseWhenMinimizedCheckbox state]); config_PutInt(p_intf, "embedded-video", [_video_embeddedCheckbox state]); config_PutInt(p_intf, "macosx-nativefullscreenmode", [_video_nativeFullscreenCheckbox state]); config_PutInt(p_intf, "macosx-vdev", [[_video_devicePopup selectedItem] tag]); config_PutPsz(p_intf, "snapshot-path", [[_video_snap_folderTextField stringValue] UTF8String]); config_PutPsz(p_intf, "snapshot-prefix", [[_video_snap_prefixTextField stringValue] UTF8String]); config_PutInt(p_intf, "snapshot-sequential", [_video_snap_seqnumCheckbox state]); SaveStringList(_video_snap_formatPopup, "snapshot-format"); SaveIntList(_video_deinterlacePopup, "deinterlace"); SaveStringList(_video_deinterlace_modePopup, "deinterlace-mode"); _videoSettingChanged = NO; } /*************************** * input & codecs settings * ***************************/ if (_inputSettingChanged) { config_PutPsz(p_intf, "input-record-path", [[_input_recordTextField stringValue] UTF8String]); config_PutInt(p_intf, "videotoolbox", [_input_hardwareAccelerationCheckbox state]); config_PutInt(p_intf, "postproc-q", [_input_postprocTextField intValue]); config_PutInt(p_intf, "skip-frames", [_input_skipFramesCheckbox state]); SaveIntList(_input_aviPopup, "avi-index"); SaveIntList(_input_skipLoopPopup, "avcodec-skiploopfilter"); #define CaC(name, factor) config_PutInt(p_intf, name, [[_input_cachelevelPopup selectedItem] tag] * factor) if ([[_input_cachelevelPopup selectedItem] tag] == 0) { msg_Dbg(p_intf, "Custom chosen, not adjusting cache values"); } else { msg_Dbg(p_intf, "Adjusting all cache values to: %i", (int)[[_input_cachelevelPopup selectedItem] tag]); CaC("file-caching", 1); CaC("network-caching", 10/3); CaC("disc-caching", 1); CaC("live-caching", 1); } #undef CaC _inputSettingChanged = NO; } /********************** * subtitles settings * **********************/ if (_osdSettingChanged) { config_PutInt(p_intf, "osd", [_osd_osdCheckbox state]); if ([_osd_encodingPopup indexOfSelectedItem] >= 0) SaveStringList(_osd_encodingPopup, "subsdec-encoding"); else config_PutPsz(p_intf, "subsdec-encoding", ""); config_PutPsz(p_intf, "sub-language", [[_osd_langTextField stringValue] UTF8String]); config_PutPsz(p_intf, "freetype-font", [[_osd_fontTextField stringValue] UTF8String]); SaveIntList(_osd_font_colorPopup, "freetype-color"); SaveIntList(_osd_font_sizePopup, "freetype-rel-fontsize"); config_PutInt(p_intf, "freetype-opacity", [_osd_opacityTextField intValue] * 255.0 / 100.0 + 0.5); config_PutInt(p_intf, "freetype-bold", [_osd_forceboldCheckbox state]); SaveIntList(_osd_outline_colorPopup, "freetype-outline-color"); SaveIntList(_osd_outline_thicknessPopup, "freetype-outline-thickness"); _osdSettingChanged = NO; } /******************** * hotkeys settings * ********************/ if (_hotkeyChanged) { NSUInteger hotKeyCount = [_hotkeySettings count]; for (NSUInteger i = 0; i < hotKeyCount; i++) config_PutPsz(p_intf, [[_hotkeyNames objectAtIndex:i] UTF8String], [[_hotkeySettings objectAtIndex:i]UTF8String]); _hotkeyChanged = NO; } [[VLCCoreInteraction sharedInstance] fixIntfSettings]; /* okay, let's save our changes to vlcrc */ config_SaveConfigFile(p_intf); [[NSNotificationCenter defaultCenter] postNotificationName:VLCMediaKeySupportSettingChangedNotification object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:VLCConfigurationChangedNotification object:nil]; } - (void)showSettingsForCategory:(NSView *)categoryView { [_contentView setSubviews:[NSArray array]]; [_contentView addSubview:categoryView]; NSDictionary *views = @{ @"view": categoryView }; NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|[view]|" options:0 metrics:nil views:views]; [_contentView addConstraints:constraints]; constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:views]; [_contentView addConstraints:constraints]; [_scrollView layoutSubtreeIfNeeded]; [_scrollView flashScrollers]; } #pragma mark - #pragma mark Specific actions // disables some video settings which do not work in lion mode - (void)enableLionFullscreenMode: (BOOL)_value { [_video_videodecoCheckbox setEnabled: !_value]; [_video_blackScreenCheckbox setEnabled: !_value]; [_video_devicePopup setEnabled: !_value]; if (_value) { [_video_videodecoCheckbox setState: NSOnState]; [_video_blackScreenCheckbox setState: NSOffState]; NSString *tooltipText = _NS("This setting cannot be changed because the native fullscreen mode is enabled."); [_video_videodecoCheckbox setToolTip:tooltipText]; [_video_blackScreenCheckbox setToolTip:tooltipText]; [_video_devicePopup setToolTip:tooltipText]; } else { [self setupButton:_video_videodecoCheckbox forBoolValue: "video-deco"]; [self setupButton:_video_blackScreenCheckbox forBoolValue: "macosx-black"]; [_video_devicePopup setToolTip:@""]; } } - (IBAction)interfaceSettingChanged:(id)sender { if (sender == _intf_enableluahttpCheckbox) { _intf_luahttppwdTextField.enabled = [sender state] == NSOnState; } _intfSettingChanged = YES; } - (void)showInterfaceSettings { [self showSettingsForCategory:_intfView]; } - (IBAction)audioSettingChanged:(id)sender { if (sender == _audio_volSlider) [_audio_volTextField setIntValue: [_audio_volSlider intValue]]; if (sender == _audio_volTextField) [_audio_volSlider setIntValue: [_audio_volTextField intValue]]; if (sender == _audio_lastCheckbox) { if ([_audio_lastCheckbox state] == NSOnState) { [_audio_lastpwdSecureTextField setEnabled: YES]; [_audio_lastuserTextField setEnabled: YES]; } else { [_audio_lastpwdSecureTextField setEnabled: NO]; [_audio_lastuserTextField setEnabled: NO]; } } if (sender == _audio_autosavevolMatrix) { BOOL enableVolumeSlider = [_audio_autosavevolMatrix selectedTag] == 1; [_audio_volTextField setEnabled: enableVolumeSlider]; [_audio_volSlider setEnabled: enableVolumeSlider]; } _audioSettingChanged = YES; } - (void)showAudioSettings { [self showSettingsForCategory:_audioView]; } - (IBAction)videoSettingChanged:(id)sender { if (sender == _video_nativeFullscreenCheckbox) [self enableLionFullscreenMode:[sender state]]; else if (sender == _video_snap_folderButton) { _selectFolderPanel = [[NSOpenPanel alloc] init]; [_selectFolderPanel setCanChooseDirectories: YES]; [_selectFolderPanel setCanChooseFiles: NO]; [_selectFolderPanel setResolvesAliases: YES]; [_selectFolderPanel setAllowsMultipleSelection: NO]; [_selectFolderPanel setMessage: _NS("Choose the folder to save your video snapshots to.")]; [_selectFolderPanel setCanCreateDirectories: YES]; [_selectFolderPanel setPrompt: _NS("Choose")]; [_selectFolderPanel beginSheetModalForWindow:self.window completionHandler: ^(NSInteger returnCode) { if (returnCode == NSOKButton) { [_video_snap_folderTextField setStringValue: [[_selectFolderPanel URL] path]]; } }]; } _videoSettingChanged = YES; } - (void)showVideoSettings { [self showSettingsForCategory:_videoView]; } - (IBAction)osdSettingChanged:(id)sender { if (sender == _osd_opacityTextField) [_osd_opacitySlider setIntValue: [_osd_opacityTextField intValue]]; if (sender == _osd_opacitySlider) [_osd_opacityTextField setIntValue: [_osd_opacitySlider intValue]]; _osdSettingChanged = YES; } - (void)showOSDSettings { [self showSettingsForCategory:_osdView]; } - (void)controlTextDidChange:(NSNotification *)notification { id notificationObject = [notification object]; if (notificationObject == _audio_langTextField || notificationObject == _audio_lastpwdSecureTextField || notificationObject == _audio_lastuserTextField || notificationObject == _audio_volTextField) _audioSettingChanged = YES; else if (notificationObject == _input_recordTextField || notificationObject == _input_postprocTextField) _inputSettingChanged = YES; else if (notificationObject == _osd_fontTextField || notificationObject == _osd_langTextField || notificationObject == _osd_opacityTextField) _osdSettingChanged = YES; else if (notificationObject == _video_snap_folderTextField || notificationObject == _video_snap_prefixTextField) _videoSettingChanged = YES; else if (notificationObject == _intf_luahttppwdTextField) _intfSettingChanged = YES; } - (IBAction)showFontPicker:(id)sender { char * font = config_GetPsz(p_intf, "freetype-font"); NSString * fontName = font ? toNSStr(font) : nil; free(font); if (fontName) { NSFont * font = [NSFont fontWithName:fontName size:0.0]; [[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:NO]; } [[NSFontManager sharedFontManager] setTarget: self]; [[NSFontPanel sharedFontPanel] setDelegate:self]; [[NSFontPanel sharedFontPanel] makeKeyAndOrderFront:self]; } - (void)changeFont:(id)sender { NSFont *someFont = [NSFont systemFontOfSize:12]; // converts given font to changes in font panel. Original font is irrelevant NSFont *selectedFont = [sender convertFont:someFont]; [_osd_fontTextField setStringValue:[selectedFont fontName]]; [self osdSettingChanged:self]; } - (NSUInteger)validModesForFontPanel:(NSFontPanel *)fontPanel { return NSFontPanelFaceModeMask | NSFontPanelCollectionModeMask; } - (IBAction)inputSettingChanged:(id)sender { if (sender == _input_cachelevelPopup) { if ([[[_input_cachelevelPopup selectedItem] title] isEqualToString: _NS("Custom")]) [_input_cachelevel_customLabel setHidden: NO]; else [_input_cachelevel_customLabel setHidden: YES]; } else if (sender == _input_recordButton) { _selectFolderPanel = [[NSOpenPanel alloc] init]; [_selectFolderPanel setCanChooseDirectories: YES]; [_selectFolderPanel setCanChooseFiles: YES]; [_selectFolderPanel setResolvesAliases: YES]; [_selectFolderPanel setAllowsMultipleSelection: NO]; [_selectFolderPanel setMessage: _NS("Choose the directory or filename where the records will be stored.")]; [_selectFolderPanel setCanCreateDirectories: YES]; [_selectFolderPanel setPrompt: _NS("Choose")]; [_selectFolderPanel beginSheetModalForWindow:self.window completionHandler: ^(NSInteger returnCode) { if (returnCode == NSOKButton) { [_input_recordTextField setStringValue: [[_selectFolderPanel URL] path]]; _inputSettingChanged = YES; } }]; return; } _inputSettingChanged = YES; } - (void)showInputSettings { [self showSettingsForCategory:_inputView]; } - (NSString *)bundleIdentifierForApplicationName:(NSString *)appName { NSWorkspace * workspace = [NSWorkspace sharedWorkspace]; NSString * appPath = [workspace fullPathForApplication:appName]; if (appPath) { NSBundle * appBundle = [NSBundle bundleWithPath:appPath]; return [appBundle bundleIdentifier]; } return nil; } - (NSString *)applicationNameForBundleIdentifier:(NSString *)bundleIdentifier { return [[[NSFileManager defaultManager] displayNameAtPath:[[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:bundleIdentifier]] stringByDeletingPathExtension]; } - (NSImage *)iconForBundleIdentifier:(NSString *)bundleIdentifier { NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; NSSize iconSize = NSMakeSize(16., 16.); NSImage *icon = [workspace iconForFile:[workspace absolutePathForAppBundleWithIdentifier:bundleIdentifier]]; [icon setSize:iconSize]; return icon; } - (IBAction)urlHandlerAction:(id)sender { NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; if (sender == _input_urlhandlerButton) { void (^fillUrlHandlerPopup)(NSString*, NSPopUpButton*) = ^void(NSString *protocol, NSPopUpButton *object) { NSArray *handlers = (__bridge_transfer NSArray *)LSCopyAllHandlersForURLScheme((__bridge CFStringRef)protocol); NSMutableArray *rawHandlers = [[NSMutableArray alloc] init]; [object removeAllItems]; NSUInteger count = [handlers count]; for (NSUInteger x = 0; x < count; x++) { NSString *rawhandler = [handlers objectAtIndex:x]; NSString *handler = [self applicationNameForBundleIdentifier:rawhandler]; if (handler && ![handler isEqualToString:@""]) { [object addItemWithTitle:handler]; [[object lastItem] setImage: [self iconForBundleIdentifier:[handlers objectAtIndex:x]]]; [rawHandlers addObject: rawhandler]; } } [object selectItemAtIndex: [rawHandlers indexOfObject:(__bridge_transfer id)LSCopyDefaultHandlerForURLScheme((__bridge CFStringRef)protocol)]]; }; fillUrlHandlerPopup(@"ftp", _urlhandler_ftpPopup); fillUrlHandlerPopup(@"mms", _urlhandler_mmsPopup); fillUrlHandlerPopup(@"rtmp", _urlhandler_rtmpPopup); fillUrlHandlerPopup(@"rtp", _urlhandler_rtpPopup); fillUrlHandlerPopup(@"rtsp", _urlhandler_rtspPopup); fillUrlHandlerPopup(@"sftp", _urlhandler_sftpPopup); fillUrlHandlerPopup(@"smb", _urlhandler_smbPopup); fillUrlHandlerPopup(@"udp", _urlhandler_udpPopup); [NSApp beginSheet:_urlhandler_win modalForWindow:self.window modalDelegate:self didEndSelector:NULL contextInfo:nil]; } else { [_urlhandler_win orderOut:sender]; [NSApp endSheet:_urlhandler_win]; if (sender == _urlhandler_saveButton) { LSSetDefaultHandlerForURLScheme(CFSTR("ftp"), (__bridge CFStringRef)[self bundleIdentifierForApplicationName:[[_urlhandler_ftpPopup selectedItem] title]]); LSSetDefaultHandlerForURLScheme(CFSTR("mms"), (__bridge CFStringRef)[self bundleIdentifierForApplicationName:[[_urlhandler_mmsPopup selectedItem] title]]); LSSetDefaultHandlerForURLScheme(CFSTR("mmsh"), (__bridge CFStringRef)[self bundleIdentifierForApplicationName:[[_urlhandler_mmsPopup selectedItem] title]]); LSSetDefaultHandlerForURLScheme(CFSTR("rtmp"), (__bridge CFStringRef)[self bundleIdentifierForApplicationName:[[_urlhandler_rtmpPopup selectedItem] title]]); LSSetDefaultHandlerForURLScheme(CFSTR("rtp"), (__bridge CFStringRef)[self bundleIdentifierForApplicationName:[[_urlhandler_rtpPopup selectedItem] title]]); LSSetDefaultHandlerForURLScheme(CFSTR("rtsp"), (__bridge CFStringRef)[self bundleIdentifierForApplicationName:[[_urlhandler_rtspPopup selectedItem] title]]); LSSetDefaultHandlerForURLScheme(CFSTR("sftp"), (__bridge CFStringRef)[self bundleIdentifierForApplicationName:[[_urlhandler_sftpPopup selectedItem] title]]); LSSetDefaultHandlerForURLScheme(CFSTR("smb"), (__bridge CFStringRef)[self bundleIdentifierForApplicationName:[[_urlhandler_smbPopup selectedItem] title]]); LSSetDefaultHandlerForURLScheme(CFSTR("udp"), (__bridge CFStringRef)[self bundleIdentifierForApplicationName:[[_urlhandler_udpPopup selectedItem] title]]); } } } #pragma mark - #pragma mark Hotkey actions - (void)hotkeyTableDoubleClick:(id)object { // -1 is header if ([_hotkeys_listbox clickedRow] >= 0) [self hotkeySettingChanged:_hotkeys_listbox]; } - (IBAction)hotkeySettingChanged:(id)sender { if (sender == _hotkeys_changeButton || sender == _hotkeys_listbox) { [_hotkeys_changeLabel setStringValue: [NSString stringWithFormat: _NS("Press new keys for\n\"%@\""), [_hotkeyDescriptions objectAtIndex:[_hotkeys_listbox selectedRow]]]]; [_hotkeys_change_keysLabel setStringValue: [[VLCStringUtility sharedInstance] OSXStringKeyToString:[_hotkeySettings objectAtIndex:[_hotkeys_listbox selectedRow]]]]; [_hotkeys_change_takenLabel setStringValue: @""]; [_hotkeys_change_win setInitialFirstResponder: [_hotkeys_change_win contentView]]; [_hotkeys_change_win makeFirstResponder: [_hotkeys_change_win contentView]]; [NSApp runModalForWindow:_hotkeys_change_win]; } else if (sender == _hotkeys_change_cancelButton) { [NSApp stopModal]; [_hotkeys_change_win close]; } else if (sender == _hotkeys_change_okButton) { NSInteger i_returnValue; if (! _keyInTransition) { [NSApp stopModal]; [_hotkeys_change_win close]; msg_Err(p_intf, "internal error prevented the hotkey switch"); return; } _hotkeyChanged = YES; i_returnValue = [_hotkeySettings indexOfObject: _keyInTransition]; if (i_returnValue != NSNotFound) [_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]]; NSString *tempString; tempString = [_keyInTransition stringByReplacingOccurrencesOfString:@"-" withString:@"+"]; i_returnValue = [_hotkeySettings indexOfObject: tempString]; if (i_returnValue != NSNotFound) [_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]]; [_hotkeySettings replaceObjectAtIndex: [_hotkeys_listbox selectedRow] withObject:_keyInTransition]; [NSApp stopModal]; [_hotkeys_change_win close]; [_hotkeys_listbox reloadData]; } else if (sender == _hotkeys_clearButton) { [_hotkeySettings replaceObjectAtIndex: [_hotkeys_listbox selectedRow] withObject: [NSString string]]; [_hotkeys_listbox reloadData]; _hotkeyChanged = YES; } } - (void)showHotkeySettings { [self showSettingsForCategory:_hotkeysView]; } - (int)numberOfRowsInTableView:(NSTableView *)aTableView { return [_hotkeySettings count]; } - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { NSString * identifier = [aTableColumn identifier]; if ([identifier isEqualToString: @"action"]) return [_hotkeyDescriptions objectAtIndex:rowIndex]; else if ([identifier isEqualToString: @"shortcut"]) return [[VLCStringUtility sharedInstance] OSXStringKeyToString:[_hotkeySettings objectAtIndex:rowIndex]]; else { msg_Err(p_intf, "unknown TableColumn identifier (%s)!", [identifier UTF8String]); return NULL; } } - (BOOL)changeHotkeyTo: (NSString *)theKey { NSInteger i_returnValue, i_returnValue2; i_returnValue = [_hotkeysNonUseableKeys indexOfObject: theKey]; if (i_returnValue != NSNotFound || [theKey isEqualToString:@""]) { [_hotkeys_change_keysLabel setStringValue: _NS("Invalid combination")]; [_hotkeys_change_takenLabel setStringValue: _NS("Regrettably, these keys cannot be assigned as hotkey shortcuts.")]; [_hotkeys_change_okButton setEnabled: NO]; return NO; } else { [_hotkeys_change_keysLabel setStringValue: [[VLCStringUtility sharedInstance] OSXStringKeyToString:theKey]]; i_returnValue = [_hotkeySettings indexOfObject: theKey]; i_returnValue2 = [_hotkeySettings indexOfObject: [theKey stringByReplacingOccurrencesOfString:@"-" withString:@"+"]]; if (i_returnValue != NSNotFound) [_hotkeys_change_takenLabel setStringValue: [NSString stringWithFormat: _NS("This combination is already taken by \"%@\"."), [_hotkeyDescriptions objectAtIndex:i_returnValue]]]; else if (i_returnValue2 != NSNotFound) [_hotkeys_change_takenLabel setStringValue: [NSString stringWithFormat: _NS("This combination is already taken by \"%@\"."), [_hotkeyDescriptions objectAtIndex:i_returnValue2]]]; else [_hotkeys_change_takenLabel setStringValue: @""]; [_hotkeys_change_okButton setEnabled: YES]; _keyInTransition = theKey; return YES; } } @end