VLCSimplePrefsController.m 60.4 KB
Newer Older
1
/*****************************************************************************
2
* VLCSimplePrefsController.m: Simple Preferences for Mac OS X
3
*****************************************************************************
4
* Copyright (C) 2008-2014 VLC authors and VideoLAN
5
* $Id$
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
*
* Authors: Felix Paul Kühne <fkuehne at videolan dot org>
*
* 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.
*****************************************************************************/
23 24 25
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
26

27
#import "CompatibilityFixes.h"
28
#import "VLCSimplePrefsController.h"
29
#import "prefs.h"
30
#import <vlc_actions.h>
31
#import <vlc_interface.h>
32
#import <vlc_dialog.h>
33
#import <vlc_modules.h>
34
#import <vlc_plugin.h>
35
#import <vlc_config_cat.h>
36
#import "misc.h"
37
#import "VLCMain.h"
38
#import "VLCMain+OldPrefs.h"
39
#import "AppleRemote.h"
40
#import "VLCCoreInteraction.h"
41
#import "NSScreen+VLCAdditions.h"
42

43
#ifdef HAVE_SPARKLE
44
#import <Sparkle/Sparkle.h>                        //for o_intf_last_updateLabel
45
#endif
46

47

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
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 },
    { "bn",    "বাংলা",                  NO },
    { "pt_BR", "Português Brasileiro",  NO },
    { "en_GB", "British English",       NO },
    { "el",    "Νέα Ελληνικά",          NO },
    { "bg",    "български език",        NO },
    { "ca",    "Català",                NO },
    { "zh_TW", "正體中文",               NO },
    { "cs",    "Čeština",               NO },
    { "cy",    "Cymraeg",               NO },
    { "da",    "Dansk",                 NO },
    { "nl",    "Nederlands",            NO },
    { "fi",    "Suomi",                 NO },
    { "et",    "eesti keel",            NO },
    { "eu",    "Euskara",               NO },
    { "fr",    "Français",              NO },
    { "ga",    "Gaeilge",               NO },
    { "gd",    "Gàidhlig",              NO },
    { "gl",    "Galego",                NO },
    { "ka",    "ქართული",               NO },
    { "de",    "Deutsch",               NO },
    { "he",    "עברית",                  YES },
    { "hr",    "hrvatski",              NO },
    { "hu",    "Magyar",                NO },
    { "hy",    "հայերեն",                NO },
    { "is",    "íslenska",              NO },
    { "id",    "Bahasa Indonesia",      NO },
    { "it",    "Italiano",              NO },
    { "ja",    "日本語",                 NO },
    { "ko",    "한국어",                  NO },
    { "lt",    "lietuvių",              NO },
    { "mn",    "Монгол хэл",            NO },
    { "ms",    "Melayu",                NO },
    { "nb",    "Bokmål",                NO },
    { "nn",    "Nynorsk",               NO },
    { "kk",    "Қазақ тілі",            NO },
    { "km",    "ភាសាខ្មែរ",                NO },
    { "ne",    "नेपाली",                  NO },
    { "oc",    "Occitan",               NO },
    { "fa",    "فارسی",                 YES },
    { "pl",    "Polski",                NO },
    { "pt_PT", "Português",             NO },
    { "pa",    "ਪੰਜਾਬੀ",                  NO },
    { "ro",    "Română",                NO },
    { "ru",    "Русский",               NO },
    { "zh_CN", "简体中文",               NO },
    { "si",    "සිංහල",                NO },
    { "sr",    "српски",                NO },
    { "sk",    "Slovensky",             NO },
    { "sl",    "slovenščina",           NO },
    { "ckb",   "کوردیی سۆرانی",         YES },
    { "es",    "Español",               NO },
    { "sv",    "Svenska",               NO },
    { "te",    "తెలుగు",                 NO },
    { "tr",    "Türkçe",                NO },
    { "uk",    "украї́нська мо́ва",       NO },
    { "vi",    "tiếng Việt",            NO },
    { "wa",    "Walon",                 NO }
114 115
};

116 117 118
static NSString* VLCSPrefsToolbarIdentifier = @"Our Simple Preferences Toolbar Identifier";
static NSString* VLCIntfSettingToolbarIdentifier = @"Intf Settings Item Identifier";
static NSString* VLCAudioSettingToolbarIdentifier = @"Audio Settings Item Identifier";
119
static NSString* VLCVideoSettingToolbarIdentifier = @"Video Settings Item Identifier";
120 121 122
static NSString* VLCOSDSettingToolbarIdentifier = @"Subtitles Settings Item Identifier";
static NSString* VLCInputSettingToolbarIdentifier = @"Input Settings Item Identifier";
static NSString* VLCHotkeysSettingToolbarIdentifier = @"Hotkeys Settings Item Identifier";
123

124
@interface VLCSimplePrefsController() <NSToolbarDelegate, NSWindowDelegate>
125
{
126 127 128 129 130 131 132 133 134 135 136 137 138
    BOOL _audioSettingChanged;
    BOOL _intfSettingChanged;
    BOOL _videoSettingChanged;
    BOOL _osdSettingChanged;
    BOOL _inputSettingChanged;
    BOOL _hotkeyChanged;

    NSOpenPanel *_selectFolderPanel;
    NSArray *_hotkeyDescriptions;
    NSArray *_hotkeyNames;
    NSArray *_hotkeysNonUseableKeys;
    NSMutableArray *_hotkeySettings;
    NSString *_keyInTransition;
139 140 141 142 143

    intf_thread_t *p_intf;
}
@end

144
@implementation VLCSimplePrefsController
145

146 147
#pragma mark Initialisation

148 149
- (id)init
{
150 151
    self = [super initWithWindowNibName:@"SimplePreferences"];
    if (self) {
152
        p_intf = getIntf();
153 154
    }

155
    return self;
156 157
}

158
- (void)windowDidLoad
159 160
{
    [self initStrings];
161

162
#ifdef HAVE_SPARKLE
163
    [_intf_updateCheckbox bind:@"value"
164 165 166 167
                   toObject:[SUUpdater sharedUpdater]
                withKeyPath:@"automaticallyChecksForUpdates"
                    options:nil];
#else
168 169
    [_intf_updateCheckbox setState:NSOffState];
    [_intf_updateCheckbox setEnabled:NO];
170 171
#endif

172
    /* setup the toolbar */
173 174 175 176 177 178
    NSToolbar * toolbar = [[NSToolbar alloc] initWithIdentifier: VLCSPrefsToolbarIdentifier];
    [toolbar setAllowsUserCustomization: NO];
    [toolbar setAutosavesConfiguration: NO];
    [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
    [toolbar setSizeMode: NSToolbarSizeModeRegular];
    [toolbar setDelegate: self];
179
    [self.window setToolbar:toolbar];
180

181 182
    [self.window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
    [self.window setHidesOnDeactivate:YES];
183

184 185
    [_hotkeys_listbox setTarget:self];
    [_hotkeys_listbox setDoubleAction:@selector(hotkeyTableDoubleClick:)];
186

187
    /* setup useful stuff */
188
    _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];
189 190 191 192 193 194 195

    // 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];
196 197
}

198 199
#define CreateToolbarItem(name, desc, img, sel) \
    toolbarItem = create_toolbar_item(itemIdent, name, desc, img, self, @selector(sel));
200
static inline NSToolbarItem *
201
create_toolbar_item(NSString *itemIdent, NSString *name, NSString *desc, NSString *img, id target, SEL selector)
202
{
203
    NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier: itemIdent];
204

205 206
    [toolbarItem setLabel:name];
    [toolbarItem setPaletteLabel:desc];
207

208 209
    [toolbarItem setToolTip:desc];
    [toolbarItem setImage:[NSImage imageNamed:img]];
210

211 212
    [toolbarItem setTarget:target];
    [toolbarItem setAction:selector];
213

214 215
    [toolbarItem setEnabled:YES];
    [toolbarItem setAutovalidates:YES];
216

217
    return toolbarItem;
218 219
}

220 221 222
- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar
      itemForItemIdentifier:(NSString *)itemIdent
  willBeInsertedIntoToolbar:(BOOL)willBeInserted
223
{
224
    NSToolbarItem *toolbarItem = nil;
225

226
    if ([itemIdent isEqual: VLCIntfSettingToolbarIdentifier]) {
227
        CreateToolbarItem(_NS("Interface"), _NS("Interface Settings"), @"VLCInterfaceCone", showInterfaceSettings);
228
    } else if ([itemIdent isEqual: VLCAudioSettingToolbarIdentifier]) {
229
        CreateToolbarItem(_NS("Audio"), _NS("Audio Settings"), @"VLCAudioCone", showAudioSettings);
230
    } else if ([itemIdent isEqual: VLCVideoSettingToolbarIdentifier]) {
231
        CreateToolbarItem(_NS("Video"), _NS("Video Settings"), @"VLCVideoCone", showVideoSettings);
232
    } else if ([itemIdent isEqual: VLCOSDSettingToolbarIdentifier]) {
233
        CreateToolbarItem(_NS(SUBPIC_TITLE), _NS("Subtitle & On Screen Display Settings"), @"VLCSubtitleCone", showOSDSettings);
234
    } else if ([itemIdent isEqual: VLCInputSettingToolbarIdentifier]) {
235
        CreateToolbarItem(_NS(INPUT_TITLE), _NS("Input & Codec Settings"), @"VLCInputCone", showInputSettings);
236
    } else if ([itemIdent isEqual: VLCHotkeysSettingToolbarIdentifier]) {
237
        CreateToolbarItem(_NS("Hotkeys"), _NS("Hotkeys settings"), @"VLCHotkeysCone", showHotkeySettings);
238 239
    }

240
    return toolbarItem;
241 242 243 244
}

- (NSArray *)toolbarDefaultItemIdentifiers: (NSToolbar *)toolbar
{
245
    return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
246
             VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier,
247
             NSToolbarFlexibleSpaceItemIdentifier, nil];
248 249 250 251
}

- (NSArray *)toolbarAllowedItemIdentifiers: (NSToolbar *)toolbar
{
252
    return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
253
             VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier,
254
             NSToolbarFlexibleSpaceItemIdentifier, nil];
255 256 257 258
}

- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
{
259 260
    return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
             VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier, nil];
261 262 263 264
}

- (void)initStrings
{
265
    /* audio */
266 267 268 269 270 271 272 273 274 275
    [_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:")];
276 277

    /* hotkeys */
278 279 280 281 282 283 284 285
    [_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")];
286 287

    /* input */
288 289 290 291 292 293 294 295 296
    [_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")];
297
    [_input_hardwareAccelerationCheckbox setTitle: _NS("Enable hardware acceleration")];
298 299 300
    [_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")];
301
    [_input_skipFramesCheckbox setTitle: _NS("Skip frames")];
302 303

    /* url handler */
304 305 306 307
    [_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")];
308 309

    /* interface */
310
    [_intf_generalSettingsBox setTitle:_NS("General settings")];
311
    [_intf_languageLabel setStringValue: _NS("Language")];
312 313 314

    [_intf_playbackControlBox setTitle:_NS("Playback control")];
    [_intf_continueplaybackLabel setStringValue:_NS("Continue playback")];
315 316
    [_intf_appleremoteCheckbox setTitle: _NS("Control playback with the Apple Remote")];
    [_intf_mediakeysCheckbox setTitle: _NS("Control playback with media keys")];
317
    [_intf_appleremote_sysvolCheckbox setTitle: _NS("Control system volume with the Apple Remote")];
318
    [_intf_statusIconCheckbox setTitle: _NS("Display VLC status menu icon")];
319 320 321 322 323 324

    [_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")];
325 326 327
    [_intf_artCheckbox setTitle: _NS("Allow metadata network access")];
    [_intf_updateCheckbox setTitle: _NS("Automatically check for updates")];
    [_intf_last_updateLabel setStringValue: @""];
328 329

    [_intf_luahttpBox setTitle:_NS("HTTP web interface")];
330
    [_intf_enableluahttpCheckbox setTitle: _NS("Enable HTTP web interface")];
331
    [_intf_luahttppwdLabel setStringValue:_NS("Password")];
332

333
    /* Subtitles and OSD */
334 335 336 337 338 339 340 341 342 343 344 345 346 347
    [_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")];
348 349

    /* video */
350
    [_video_enableCheckbox setTitle: _NS("Enable video")];
351 352 353
    [_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")];
354
    [_video_onTopCheckbox setTitle: _NS("Float on Top")];
355 356 357 358 359 360 361 362
    [_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")];

363 364 365 366 367 368 369 370 371
    [_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")];
372

373
    /* generic stuff */
374 375 376 377
    [_showAllButton setTitle: _NS("Show All")];
    [_cancelButton setTitle: _NS("Cancel")];
    [_resetButton setTitle: _NS("Reset All")];
    [_saveButton setTitle: _NS("Save")];
378
    [self.window setTitle: _NS("Preferences")];
379 380
}

381 382
/* TODO: move this part to core */
#define config_GetLabel(a,b) __config_GetLabel(VLC_OBJECT(a),b)
383
static inline const char * __config_GetLabel(vlc_object_t *p_this, const char *psz_name)
384
{
385
    module_config_t *p_config = config_FindConfig(psz_name);
386 387

    /* sanity checks */
388 389
    if (!p_config) {
        msg_Err(p_this, "option %s does not exist", psz_name);
390 391 392
        return NULL;
    }

393
    if (p_config->psz_longtext)
394
        return p_config->psz_longtext;
395
    else if (p_config->psz_text)
396 397
        return p_config->psz_text;
    else
398
        msg_Warn(p_this, "option %s does not include any help", psz_name);
399 400 401 402

    return NULL;
}

403 404 405
#pragma mark -
#pragma mark Setup controls

406 407 408 409 410
- (void)setupButton: (NSPopUpButton *)object forStringList: (const char *)name
{
    module_config_t *p_item;

    [object removeAllItems];
411
    p_item = config_FindConfig(name);
412
    /* serious problem, if no item found */
413
    assert(p_item);
414

415
    char **values, **texts;
416
    ssize_t count = config_GetPszChoices(name, &values, &texts);
417 418 419 420 421 422
    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)
423
            continue;
424 425 426 427

        if (strcmp(texts[i], "") != 0) {
            NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""];
            [mi setRepresentedObject: toNSStr(values[i])];
428
            [[object menu] addItem:mi];
429 430 431 432 433

            if (p_item->value.psz && !strcmp(p_item->value.psz, values[i]))
                [object selectItem: [object lastItem]];
        } else {
            [[object menu] addItem: [NSMenuItem separatorItem]];
434
        }
435 436 437

        free(texts[i]);
        free(values[i]);
438
    }
439 440 441 442 443 444 445 446 447 448 449 450

    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];
451 452 453 454 455 456 457
}

- (void)setupButton: (NSPopUpButton *)object forIntList: (const char *)name
{
    module_config_t *p_item;

    [object removeAllItems];
458
    p_item = config_FindConfig(name);
459 460

    /* serious problem, if no item found */
461
    assert(p_item);
462

463 464
    int64_t *values;
    char **texts;
465
    ssize_t count = config_GetIntChoices(name, &values, &texts);
466 467
    for (ssize_t i = 0; i < count; i++) {
        NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""];
468
        [mi setRepresentedObject:[NSNumber numberWithInteger:values[i]]];
469
        [[object menu] addItem:mi];
470 471

        if (p_item->value.i == values[i])
472
            [object selectItem:[object lastItem]];
473 474

        free(texts[i]);
475
    }
476 477 478 479
    free(texts);

    if (p_item->psz_longtext)
        [object setToolTip: _NS(p_item->psz_longtext)];
480 481
}

482 483
- (void)setupButton: (NSButton *)object forBoolValue: (const char *)name
{
484
    [object setState: config_GetInt(name)];
485
    [object setToolTip: _NS(config_GetLabel(p_intf, name))];
486 487
}

488
- (void)setupField:(NSTextField *)object forOption:(const char *)psz_option
489
{
490
    char *psz_tmp = config_GetPsz(psz_option);
491
    [object setStringValue: toNSStr(psz_tmp)];
492
    [object setToolTip: _NS(config_GetLabel(p_intf, psz_option))];
493
    free(psz_tmp);
494 495
}

496 497
- (BOOL)hasModule:(NSString *)moduleName inConfig:(NSString *)config
{
498
    char *value = config_GetPsz([config UTF8String]);
499 500 501 502 503 504 505 506
    NSString *modules = toNSStr(value);
    free(value);

    return [[modules componentsSeparatedByString:@":"] containsObject:moduleName];
}

- (void)changeModule:(NSString *)moduleName inConfig:(NSString *)config enable:(BOOL)enable
{
507
    char *value = config_GetPsz([config UTF8String]);
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
    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:@""];

523
    config_PutPsz([config UTF8String], [[components componentsJoinedByString:@":"] UTF8String]);
524 525
}

526 527
- (void)resetControls
{
528 529
    int i = 0;
    NSInteger y = 0;
530 531 532 533

    /**********************
     * interface settings *
     **********************/
534 535 536
    NSUInteger sel = 0;
    const char *pref = NULL;
    pref = [[[NSUserDefaults standardUserDefaults] objectForKey:@"language"] UTF8String];
537 538
    for (int x = 0; x < ARRAY_SIZE(language_map); x++) {
        [_intf_languagePopup addItemWithTitle:toNSStr(language_map[x].name)];
539
        if (pref) {
540
            if (!strcmp(language_map[x].iso, pref))
541 542 543
                sel = x;
        }
    }
544
    [_intf_languagePopup selectItemAtIndex:sel];
545

546
    [self setupButton:_intf_continueplaybackPopup forIntList: "macosx-continue-playback"];
547 548 549 550 551 552 553
    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];
    }

554 555
    [self setupButton:_intf_appleremoteCheckbox forBoolValue: "macosx-appleremote"];
    [self setupButton:_intf_appleremote_sysvolCheckbox forBoolValue: "macosx-appleremote-sysvol"];
556
    [self setupButton:_intf_statusIconCheckbox forBoolValue: "macosx-statusicon"];
557
    [self setupButton:_intf_mediakeysCheckbox forBoolValue: "macosx-mediakeys"];
558

559 560
    [self setupButton:_video_nativeFullscreenCheckbox forBoolValue: "macosx-nativefullscreenmode"];
    [self setupButton:_video_embeddedCheckbox forBoolValue: "embedded-video"];
561

562
    [self setupButton:_intf_pauseitunesPopup forIntList: "macosx-control-itunes"];
563

564
    [self setupButton:_intf_artCheckbox forBoolValue: "metadata-network-access"];
565

566

567
#ifdef HAVE_SPARKLE
568
    if ([[SUUpdater sharedUpdater] lastUpdateCheckDate] != NULL)
569
        [_intf_last_updateLabel setStringValue: [NSString stringWithFormat: _NS("Last check on: %@"), [[[SUUpdater sharedUpdater] lastUpdateCheckDate] descriptionWithLocale: [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]]];
570
    else
571
        [_intf_last_updateLabel setStringValue: _NS("No check was performed yet.")];
572 573
#endif

574 575 576 577 578 579 580
    BOOL growlEnabled = [self hasModule:@"growl" inConfig:@"control"];
    [_intf_enableNotificationsCheckbox setState: growlEnabled ? NSOnState : NSOffState];

    BOOL httpEnabled = [self hasModule:@"http" inConfig:@"extraintf"];
    [_intf_enableluahttpCheckbox setState: httpEnabled ? NSOnState : NSOffState];
    _intf_luahttppwdTextField.enabled = httpEnabled;

581
    [self setupField:_intf_luahttppwdTextField forOption: "http-password"];
582 583 584 585

    /******************
     * audio settings *
     ******************/
586
    [self setupButton:_audio_enableCheckbox forBoolValue: "audio"];
587

588
    if (config_GetInt("volume-save")) {
589 590 591 592
        [_audio_autosavevol_yesButtonCell setState: NSOnState];
        [_audio_autosavevol_noButtonCell setState: NSOffState];
        [_audio_volTextField setEnabled: NO];
        [_audio_volSlider setEnabled: NO];
593

594 595
        [_audio_volSlider setIntValue: 100];
        [_audio_volTextField setIntValue: 100];
596
    } else {
597 598 599 600
        [_audio_autosavevol_yesButtonCell setState: NSOffState];
        [_audio_autosavevol_noButtonCell setState: NSOnState];
        [_audio_volTextField setEnabled: YES];
        [_audio_volSlider setEnabled: YES];
601

602
        i = (int)var_InheritInteger(p_intf, "auhal-volume");
603
        i = i * 200. / AOUT_VOLUME_MAX;
604 605
        [_audio_volSlider setIntValue: i];
        [_audio_volTextField setIntValue: i];
606
    }
607

608
    [self setupField:_audio_langTextField forOption: "audio-language"];
609

610
    [self setupButton:_audio_visualPopup forModuleList: "audio-visual"];
611

612
    /* Last.FM is optional */
613
    if (module_exists("audioscrobbler")) {
614 615
        [self setupField:_audio_lastuserTextField forOption:"lastfm-username"];
        [self setupField:_audio_lastpwdSecureTextField forOption:"lastfm-password"];
616

617
        if (config_ExistIntf("audioscrobbler")) {
618 619 620
            [_audio_lastCheckbox setState: NSOnState];
            [_audio_lastuserTextField setEnabled: YES];
            [_audio_lastpwdSecureTextField setEnabled: YES];
621
        } else {
622 623 624
            [_audio_lastCheckbox setState: NSOffState];
            [_audio_lastuserTextField setEnabled: NO];
            [_audio_lastpwdSecureTextField setEnabled: NO];
625
        }
626
    } else
627
        [_audio_lastCheckbox setEnabled: NO];
628 629 630 631

    /******************
     * video settings *
     ******************/
632
    [self setupButton:_video_enableCheckbox forBoolValue: "video"];
633
    [self setupButton:_video_startInFullscreenCheckbox forBoolValue: "fullscreen"];
634
    [self setupButton:_video_onTopCheckbox forBoolValue: "video-on-top"];
635
    [self setupButton:_video_blackScreenCheckbox forBoolValue: "macosx-black"];
636
    [self setupButton:_video_videodecoCheckbox forBoolValue: "video-deco"];
637
    [self setupButton:_video_pauseWhenMinimizedCheckbox forBoolValue: "macosx-pause-minimized"];
638 639

    [_video_devicePopup removeAllItems];
640 641
    i = 0;
    y = [[NSScreen screens] count];
642 643
    [_video_devicePopup addItemWithTitle: _NS("Default")];
    [[_video_devicePopup lastItem] setTag: 0];
644
    while (i < y) {
645
        NSRect s_rect = [[[NSScreen screens] objectAtIndex:i] frame];
646
        [_video_devicePopup addItemWithTitle:
647 648
         [NSString stringWithFormat: @"%@ %i (%ix%i)", _NS("Screen"), i+1,
                   (int)s_rect.size.width, (int)s_rect.size.height]];
649
        [[_video_devicePopup lastItem] setTag: (int)[[[NSScreen screens] objectAtIndex:i] displayID]];
650 651
        i++;
    }
652
    [_video_devicePopup selectItemAtIndex: 0];
653
    [_video_devicePopup selectItemWithTag: config_GetInt("macosx-vdev")];
654

655 656 657 658 659 660
    [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"];
661

662
    // set lion fullscreen mode restrictions
663
    [self enableLionFullscreenMode: [_video_nativeFullscreenCheckbox state]];
664

665 666 667
    /***************************
     * input & codecs settings *
     ***************************/
668
    [self setupField:_input_recordTextField forOption:"input-record-path"];
669 670

    [self setupButton:_input_hardwareAccelerationCheckbox forBoolValue: "videotoolbox"];
671
//    [_input_postprocTextField setIntValue: config_GetInt("postproc-q")];
672
    [_input_postprocTextField setToolTip: _NS(config_GetLabel(p_intf, "postproc-q"))];
673
    [self setupButton:_input_skipFramesCheckbox forBoolValue: "skip-frames"];
674 675
    [self setupButton:_input_aviPopup forIntList: "avi-index"];
    [self setupButton:_input_skipLoopPopup forIntList: "avcodec-skiploopfilter"];
676

677
    [_input_cachelevelPopup removeAllItems];
678 679 680 681 682 683 684 685 686 687 688 689
    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];
690

691
    #define TestCaC(name, factor) \
692
    cache_equal = cache_equal && \
693
    (i_cache * factor == config_GetInt(name));
694 695

    /* Select the accurate value of the PopupButton */
696
    bool cache_equal = true;
697
    int i_cache = (int)config_GetInt("file-caching");
698

699 700 701
    TestCaC("network-caching", 10/3);
    TestCaC("disc-caching", 1);
    TestCaC("live-caching", 1);
702 703 704
    if (cache_equal) {
        [_input_cachelevelPopup selectItemWithTag: i_cache];
        [_input_cachelevel_customLabel setHidden: YES];
705
    } else {
706 707
        [_input_cachelevelPopup selectItemWithTitle: _NS("Custom")];
        [_input_cachelevel_customLabel setHidden: NO];
708
    }
709
    #undef TestCaC
710 711 712 713

    /*********************
     * subtitle settings *
     *********************/
714
    [self setupButton:_osd_osdCheckbox forBoolValue: "osd"];
715

716 717
    [self setupButton:_osd_encodingPopup forStringList: "subsdec-encoding"];
    [self setupField:_osd_langTextField forOption: "sub-language" ];
718

719 720 721
    [self setupField:_osd_fontTextField forOption: "freetype-font"];
    [self setupButton:_osd_font_colorPopup forIntList: "freetype-color"];
    [self setupButton:_osd_font_sizePopup forIntList: "freetype-rel-fontsize"];
722
    i = config_GetInt("freetype-opacity") * 100.0 / 255.0 + 0.5;
723 724 725 726 727 728 729
    [_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"];
730

731 732 733
    /********************
     * hotkeys settings *
     ********************/
734 735 736
    _hotkeySettings = [[NSMutableArray alloc] init];
    NSMutableArray *tempArray_desc = [[NSMutableArray alloc] init];
    NSMutableArray *tempArray_names = [[NSMutableArray alloc] init];
737

738 739
    /* Get the main Module */
    module_t *p_main = module_get_main();
740
    assert(p_main);
741 742
    unsigned confsize;
    module_config_t *p_config;
743

744
    p_config = module_config_get (p_main, &confsize);
745

746
    for (size_t i = 0; i < confsize; i++) {
747
        module_config_t *p_item = p_config + i;
748

749 750 751
        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)) {
752
            [tempArray_desc addObject: _NS(p_item->psz_text)];
753
            [tempArray_names addObject: toNSStr(p_item->psz_name)];
754
            if (p_item->value.psz)
755
                [_hotkeySettings addObject: toNSStr(p_item->value.psz)];
756
            else
757
                [_hotkeySettings addObject: [NSString string]];
758
        }
759
    }
760
    module_config_free (p_config);
761

762 763
    _hotkeyDescriptions = [[NSArray alloc] initWithArray:tempArray_desc copyItems: YES];
    _hotkeyNames = [[NSArray alloc] initWithArray:tempArray_names copyItems: YES];
764

765
    [_hotkeys_listbox reloadData];
766 767
}

768 769 770
#pragma mark -
#pragma mark General actions

771 772 773
- (void)showSimplePrefs
{
    /* we want to show the interface settings, if no category was chosen */
774 775
    if ([[self.window toolbar] selectedItemIdentifier] == nil) {
        [[self.window toolbar] setSelectedItemIdentifier: VLCIntfSettingToolbarIdentifier];
776 777
        [self showInterfaceSettings];
    }
778

779
    [self resetControls];
780

781
    [self.window makeKeyAndOrderFront: self];
782 783
}

784 785
- (void)showSimplePrefsWithLevel:(NSInteger)i_window_level
{
786
    [self.window setLevel: i_window_level];
787 788 789
    [self showSimplePrefs];
}

790 791
- (IBAction)buttonAction:(id)sender
{
792
    if (sender == _cancelButton) {
793
        [[NSFontPanel sharedFontPanel] close];
794
        [self.window orderOut: sender];
795
    } else if (sender == _saveButton) {
796
        [self saveChangedSettings];
797
        [[NSFontPanel sharedFontPanel] close];
798
        [self.window orderOut: sender];
799
    } else if (sender == _showAllButton) {
800 801
        [self.window orderOut: self];
        [[[VLCMain sharedInstance] preferences] showPrefsWithLevel:[self.window level]];
802 803
    } else
        msg_Warn(p_intf, "unknown buttonAction sender");
804 805
}

806 807 808 809 810 811 812 813 814 815 816 817 818
- (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?"));
}

819
- (void)sheetDidEnd:(NSWindow *)o_sheet
820 821 822
         returnCode:(int)i_return
        contextInfo:(void *)o_context
{
823
    if (i_return == NSAlertAlternateReturn) {
824
        /* reset VLC's config */
825
        config_ResetAll();
826
        [self resetControls];
827 828

        /* force config file creation, since libvlc won't exit normally */
829
        config_SaveConfigFile(p_intf);
830 831

        /* reset OS X defaults */
832
        [[VLCMain sharedInstance] resetAndReinitializeUserDefaults];
833 834 835 836 837 838 839 840 841 842

        /* 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);
843 844 845
    }
}

846
static inline void save_int_list(intf_thread_t * p_intf, id object, const char * name)
847
{
848 849 850
    NSNumber *p_valueobject = (NSNumber *)[[object selectedItem] representedObject];
    if (p_valueobject) {
        assert([p_valueobject isKindOfClass:[NSNumber class]]);
851
        config_PutInt(name, [p_valueobject intValue]);
852
    }
853 854
}

855
static inline void save_string_list(intf_thread_t * p_intf, id object, const char * name)
856
{
857 858 859
    NSString *p_stringobject = (NSString *)[[object selectedItem] representedObject];
    if (p_stringobject) {
        assert([p_stringobject isKindOfClass:[NSString class]]);
860
        config_PutPsz(name, [p_stringobject UTF8String]);
861
    }
862 863
}

864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
+ (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;
}

886 887
- (void)saveChangedSettings
{
888
#define SaveIntList(object, name) save_int_list(p_intf, object, name)
889

890
#define SaveStringList(object, name) save_string_list(p_intf, object, name)
891
#define SaveModuleList(object, name) SaveStringList(object, name)
892

893 894 895
    /**********************
     * interface settings *
     **********************/
896 897
    if (_intfSettingChanged) {
        NSUInteger index = [_intf_languagePopup indexOfSelectedItem];
898
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
899
        [defaults setObject:toNSStr(language_map[index].iso) forKey:@"language"];
900
        [VLCSimplePrefsController updateRightToLeftSettings];
901 902
        [defaults synchronize];

903
        config_PutInt("metadata-network-access", [_intf_artCheckbox state]);
904

905 906 907 908
        config_PutInt("macosx-appleremote", [_intf_appleremoteCheckbox state]);
        config_PutInt("macosx-appleremote-sysvol", [_intf_appleremote_sysvolCheckbox state]);
        config_PutInt("macosx-statusicon", [_intf_statusIconCheckbox state]);
        config_PutInt("macosx-mediakeys", [_intf_mediakeysCheckbox state]);
909

910 911 912
        [self changeModule:@"growl" inConfig:@"control" enable:[_intf_enableNotificationsCheckbox state] == NSOnState];

        [self changeModule:@"http" inConfig:@"extraintf" enable:[_intf_enableluahttpCheckbox state] == NSOnState];
913
        config_PutPsz("http-password", [[_intf_luahttppwdTextField stringValue] UTF8String]);
914

915 916
        SaveIntList(_intf_pauseitunesPopup, "macosx-control-itunes");
        SaveIntList(_intf_continueplaybackPopup, "macosx-continue-playback");
917

918
        /* activate stuff without restart */
919
        if ([_intf_appleremoteCheckbox state] == YES)
920
            [[VLCCoreInteraction sharedInstance] startListeningWithAppleRemote];
921
        else
922
            [[VLCCoreInteraction sharedInstance] stopListeningWithAppleRemote];
923
        _intfSettingChanged = NO;
924
    }
925

926 927 928
    /******************
     * audio settings *
     ******************/
929
    if (_audioSettingChanged) {
930 931
        config_PutInt("audio", [_audio_enableCheckbox state]);
        config_PutInt("volume-save", [_audio_autosavevol_yesButtonCell state]);
932 933
        var_SetBool(p_intf, "volume-save", [_audio_autosavevol_yesButtonCell state]);
        if ([_audio_volTextField isEnabled])
934
            config_PutInt("auhal-volume", ([_audio_volTextField intValue] * AOUT_VOLUME_MAX) / 200);
935

936
        config_PutPsz("audio-language", [[_audio_langTextField stringValue] UTF8String]);
937

938
        SaveModuleList(_audio_visualPopup, "audio-visual");
939

940
        /* Last.FM is optional */
941
        if (module_exists("audioscrobbler")) {
942 943
            [_audio_lastCheckbox setEnabled: YES];
            if ([_audio_lastCheckbox state] == NSOnState)
944
                config_AddIntf("audioscrobbler");
945
            else
946
                config_RemoveIntf("audioscrobbler");
947

948 949
            config_PutPsz("lastfm-username", [[_audio_lastuserTextField stringValue] UTF8String]);
            config_PutPsz("lastfm-password", [[_audio_lastpwdSecureTextField stringValue] UTF8String]);
950
        }
951
        else
952 953
            [_audio_lastCheckbox setEnabled: NO];
        _audioSettingChanged = NO;
954
    }
955

956 957 958
    /******************
     * video settings *
     ******************/
959
    if (_videoSettingChanged) {
960 961 962 963 964
        config_PutInt("video", [_video_enableCheckbox state]);
        config_PutInt("fullscreen", [_video_startInFullscreenCheckbox state]);
        config_PutInt("video-deco", [_video_videodecoCheckbox state]);
        config_PutInt("video-on-top", [_video_onTopCheckbox state]);
        config_PutInt("macosx-black", [_video_blackScreenCheckbox state]);
965

966
        config_PutInt("macosx-pause-minimized", [_video_pauseWhenMinimizedCheckbox state]);
967

968 969 970
        config_PutInt("embedded-video", [_video_embeddedCheckbox state]);
        config_PutInt("macosx-nativefullscreenmode", [_video_nativeFullscreenCheckbox state]);
        config_PutInt("macosx-vdev", [[_video_devicePopup selectedItem] tag]);
971

972 973 974
        config_PutPsz("snapshot-path", [[_video_snap_folderTextField stringValue] UTF8String]);
        config_PutPsz("snapshot-prefix", [[_video_snap_prefixTextField stringValue] UTF8String]);
        config_PutInt("snapshot-sequential", [_video_snap_seqnumCheckbox state]);
975 976 977 978
        SaveStringList(_video_snap_formatPopup, "snapshot-format");
        SaveIntList(_video_deinterlacePopup, "deinterlace");
        SaveStringList(_video_deinterlace_modePopup, "deinterlace-mode");
        _videoSettingChanged = NO;
979
    }
980

981 982 983
    /***************************
     * input & codecs settings *
     ***************************/
984
    if (_inputSettingChanged) {
985
        config_PutPsz("input-record-path", [[_input_recordTextField stringValue] UTF8String]);
986 987

        config_PutInt("videotoolbox", [_input_hardwareAccelerationCheckbox state]);
988 989
        config_PutInt("postproc-q", [_input_postprocTextField intValue]);
        config_PutInt("skip-frames", [_input_skipFramesCheckbox state]);
990

991
        SaveIntList(_input_aviPopup, "avi-index");
992

993
        SaveIntList(_input_skipLoopPopup, "avcodec-skiploopfilter");
994

995
        #define CaC(name, factor) config_PutInt(name, [[_input_cachelevelPopup selectedItem] tag] * factor)
996
        if ([[_input_cachelevelPopup selectedItem] tag] == 0) {
997 998
            msg_Dbg(p_intf, "Custom chosen, not adjusting cache values");
        } else {
999
            msg_Dbg(p_intf, "Adjusting all cache values to: %i", (int)[[_input_cachelevelPopup selectedItem] tag]);
1000 1001 1002 1003
            CaC("file-caching", 1);
            CaC("network-caching", 10/3);
            CaC("disc-caching", 1);
            CaC("live-caching", 1);
1004
        }
1005
        #undef CaC
1006
        _inputSettingChanged = NO;
1007
    }
1008

1009 1010 1011
    /**********************
     * subtitles settings *
     **********************/
1012
    if (_osdSettingChanged) {
1013
        config_PutInt("osd", [_osd_osdCheckbox state]);
1014

1015 1016
        if ([_osd_encodingPopup indexOfSelectedItem] >= 0)
            SaveStringList(_osd_encodingPopup, "subsdec-encoding");
1017
        else
1018
            config_PutPsz("subsdec-encoding", "");
1019

1020
        config_PutPsz("sub-language", [[_osd_langTextField stringValue] UTF8String]);
1021

1022
        config_PutPsz("freetype-font", [[_osd_fontTextField stringValue] UTF8String]);
1023 1024
        SaveIntList(_osd_font_colorPopup, "freetype-color");
        SaveIntList(_osd_font_sizePopup, "freetype-rel-fontsize");
1025 1026
        config_PutInt("freetype-opacity", [_osd_opacityTextField intValue] * 255.0 / 100.0 + 0.5);
        config_PutInt("freetype-bold", [_osd_forceboldCheckbox state]);
1027 1028 1029
        SaveIntList(_osd_outline_colorPopup, "freetype-outline-color");
        SaveIntList(_osd_outline_thicknessPopup, "freetype-outline-thickness");
        _osdSettingChanged = NO;
1030
    }
1031

1032 1033 1034
    /********************
     * hotkeys settings *
     ********************/
1035 1036
    if (_hotkeyChanged) {
        NSUInteger hotKeyCount = [_hotkeySettings count];
1037
        for (NSUInteger i = 0; i < hotKeyCount; i++)
1038
            config_PutPsz([[_hotkeyNames objectAtIndex:i] UTF8String], [[_hotkeySettings objectAtIndex:i]UTF8String]);
1039
        _hotkeyChanged = NO;
1040
    }
1041

1042
    [[VLCCoreInteraction sharedInstance] fixIntfSettings];
1043

1044
    /* okay, let's save our changes to vlcrc */
1045
    config_SaveConfigFile(p_intf);
1046

1047
    [[NSNotificationCenter defaultCenter] postNotificationName:VLCMediaKeySupportSettingChangedNotification object:nil];
1048
    [[NSNotificationCenter defaultCenter] postNotificationName:VLCConfigurationChangedNotification object:nil];
1049 1050
}

1051
- (void)showSettingsForCategory:(NSView *)categoryView
1052
{
1053 1054
    [_contentView setSubviews:[NSArray array]];
    [_contentView addSubview:categoryView];
1055

1056
    NSDictionary *views = @{ @"view": categoryView };
1057
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|[view]|" options:0 metrics:nil views:views];
1058
    [_contentView addConstraints:constraints];
1059
    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:views];
1060
    [_contentView addConstraints:constraints];
1061