VLCSimplePrefsController.m 63.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_keys.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"
David's avatar
David committed
40
#import "VLCCoreInteraction.h"
41

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

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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
static const char *const ppsz_language[] =
{
    "auto",
    "en",
    "ar",
    "bn",
    "pt_BR",
    "en_GB",
    "el",
    "bg",
    "ca",
    "zh_TW",
    "cs",
    "cy",
    "da",
    "nl",
    "fi",
    "et",
    "eu",
    "fr",
    "ga",
    "gd",
    "gl",
    "ka",
    "de",
    "he",
    "hr",
    "hu",
    "hy",
    "is",
    "id",
    "it",
    "ja",
    "ko",
    "lt",
    "mn",
    "ms",
    "nb",
    "nn",
    "kk",
    "km",
    "ne",
    "oc",
    "fa",
    "pl",
    "pt_PT",
    "pa",
    "ro",
    "ru",
    "zh_CN",
    "si",
    "sr",
    "sk",
    "sl",
    "ckb",
    "es",
    "sv",
    "te",
    "tr",
    "uk",
    "vi",
    "wa",
    NULL,
};

static const char *const ppsz_language_text[] =
{
    N_("Auto"),
    "American English",
    "ﻉﺮﺒﻳ",
    "বাংলা",
    "Português Brasileiro",
    "British English",
    "Νέα Ελληνικά",
    "български език",
    "Català",
    "正體中文",
    "Čeština",
    "Cymraeg",
    "Dansk",
    "Nederlands",
    "Suomi",
    "eesti keel",
    "Euskara",
    "Français",
    "Gaeilge",
    "Gàidhlig",
    "Galego",
    "ქართული",
    "Deutsch",
    "עברית",
    "hrvatski",
    "Magyar",
    "հայերեն",
    "íslenska",
    "Bahasa Indonesia",
    "Italiano",
    "日本語",
    "한국어",
    "lietuvių",
    "Монгол хэл",
    "Melayu",
    "Bokmål",
    "Nynorsk",
    "Қазақ тілі",
    "ភាសាខ្មែរ",
    "नेपाली",
    "Occitan",
    "ﻑﺍﺮﺳی",
    "Polski",
    "Português",
    "ਪੰਜਾਬੀ",
    "Română",
    "Русский",
    "简体中文",
    "සිංහල",
    "српски",
    "Slovensky",
    "slovenščina",
    "کوردیی سۆرانی",
    "Español",
    "Svenska",
    "తెలుగు",
    "Türkçe",
    "украї́нська мо́ва",
    "tiếng Việt",
    "Walon",
};

175
176
177
static NSString* VLCSPrefsToolbarIdentifier = @"Our Simple Preferences Toolbar Identifier";
static NSString* VLCIntfSettingToolbarIdentifier = @"Intf Settings Item Identifier";
static NSString* VLCAudioSettingToolbarIdentifier = @"Audio Settings Item Identifier";
178
static NSString* VLCVideoSettingToolbarIdentifier = @"Video Settings Item Identifier";
179
180
181
static NSString* VLCOSDSettingToolbarIdentifier = @"Subtitles Settings Item Identifier";
static NSString* VLCInputSettingToolbarIdentifier = @"Input Settings Item Identifier";
static NSString* VLCHotkeysSettingToolbarIdentifier = @"Hotkeys Settings Item Identifier";
182

183
@interface VLCSimplePrefs() <NSToolbarDelegate, NSWindowDelegate>
184
{
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    BOOL _audioSettingChanged;
    BOOL _intfSettingChanged;
    BOOL _videoSettingChanged;
    BOOL _osdSettingChanged;
    BOOL _inputSettingChanged;
    BOOL _hotkeyChanged;
    id _currentlyShownCategoryView;

    NSOpenPanel *_selectFolderPanel;
    NSArray *_hotkeyDescriptions;
    NSArray *_hotkeyNames;
    NSArray *_hotkeysNonUseableKeys;
    NSMutableArray *_hotkeySettings;
    NSString *_keyInTransition;
199
200
201
202
203

    intf_thread_t *p_intf;
}
@end

204
205
@implementation VLCSimplePrefs

206
207
#pragma mark Initialisation

208
209
- (id)init
{
210
211
    self = [super initWithWindowNibName:@"SimplePreferences"];
    if (self) {
David's avatar
David committed
212
        p_intf = getIntf();
213
214
    }

215
    return self;
216
217
}

218
- (void)windowDidLoad
219
220
{
    [self initStrings];
221

222
#ifdef HAVE_SPARKLE
223
    [_intf_updateCheckbox bind:@"value"
224
225
226
227
                   toObject:[SUUpdater sharedUpdater]
                withKeyPath:@"automaticallyChecksForUpdates"
                    options:nil];
#else
228
229
    [_intf_updateCheckbox setState:NSOffState];
    [_intf_updateCheckbox setEnabled:NO];
230
231
#endif

232
    /* setup the toolbar */
233
234
235
236
237
238
    NSToolbar * toolbar = [[NSToolbar alloc] initWithIdentifier: VLCSPrefsToolbarIdentifier];
    [toolbar setAllowsUserCustomization: NO];
    [toolbar setAutosavesConfiguration: NO];
    [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
    [toolbar setSizeMode: NSToolbarSizeModeRegular];
    [toolbar setDelegate: self];
239
    [self.window setToolbar:toolbar];
240

241
242
    [self.window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
    [self.window setHidesOnDeactivate:YES];
243

244
245
    [_hotkeys_listbox setTarget:self];
    [_hotkeys_listbox setDoubleAction:@selector(hotkeyTableDoubleClick:)];
246

247
    /* setup useful stuff */
248
    _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];
249
250
}

251
252
#define CreateToolbarItem(name, desc, img, sel) \
    toolbarItem = create_toolbar_item(itemIdent, name, desc, img, self, @selector(sel));
253
static inline NSToolbarItem *
254
create_toolbar_item(NSString *itemIdent, NSString *name, NSString *desc, NSString *img, id target, SEL selector)
255
{
256
    NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier: itemIdent];
257

258
259
    [toolbarItem setLabel:name];
    [toolbarItem setPaletteLabel:desc];
260

261
262
    [toolbarItem setToolTip:desc];
    [toolbarItem setImage:[NSImage imageNamed:img]];
263

264
265
    [toolbarItem setTarget:target];
    [toolbarItem setAction:selector];
266

267
268
    [toolbarItem setEnabled:YES];
    [toolbarItem setAutovalidates:YES];
269

270
    return toolbarItem;
271
272
}

273
274
275
- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar
      itemForItemIdentifier:(NSString *)itemIdent
  willBeInsertedIntoToolbar:(BOOL)willBeInserted
276
{
277
    NSToolbarItem *toolbarItem = nil;
278

279
    if ([itemIdent isEqual: VLCIntfSettingToolbarIdentifier]) {
280
        CreateToolbarItem(_NS("Interface"), _NS("Interface Settings"), @"VLCInterfaceCone", showInterfaceSettings);
281
    } else if ([itemIdent isEqual: VLCAudioSettingToolbarIdentifier]) {
282
        CreateToolbarItem(_NS("Audio"), _NS("Audio Settings"), @"VLCAudioCone", showAudioSettings);
283
    } else if ([itemIdent isEqual: VLCVideoSettingToolbarIdentifier]) {
284
        CreateToolbarItem(_NS("Video"), _NS("Video Settings"), @"VLCVideoCone", showVideoSettings);
285
    } else if ([itemIdent isEqual: VLCOSDSettingToolbarIdentifier]) {
286
        CreateToolbarItem(_NS(SUBPIC_TITLE), _NS("Subtitle & On Screen Display Settings"), @"VLCSubtitleCone", showOSDSettings);
287
    } else if ([itemIdent isEqual: VLCInputSettingToolbarIdentifier]) {
288
        CreateToolbarItem(_NS(INPUT_TITLE), _NS("Input & Codec Settings"), @"VLCInputCone", showInputSettings);
289
    } else if ([itemIdent isEqual: VLCHotkeysSettingToolbarIdentifier]) {
290
        CreateToolbarItem(_NS("Hotkeys"), _NS("Hotkeys settings"), @"VLCHotkeysCone", showHotkeySettings);
291
292
    }

293
    return toolbarItem;
294
295
296
297
}

- (NSArray *)toolbarDefaultItemIdentifiers: (NSToolbar *)toolbar
{
298
    return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
299
             VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier,
300
             NSToolbarFlexibleSpaceItemIdentifier, nil];
301
302
303
304
}

- (NSArray *)toolbarAllowedItemIdentifiers: (NSToolbar *)toolbar
{
305
    return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
306
             VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier,
307
             NSToolbarFlexibleSpaceItemIdentifier, nil];
308
309
310
311
}

- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
{
312
313
    return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
             VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier, nil];
314
315
316
317
}

- (void)initStrings
{
318
    /* audio */
319
320
321
322
323
324
325
326
327
328
329
    [_audio_dolbyLabel setStringValue: _NS("Force detection of Dolby Surround")];
    [_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:")];
330
331

    /* hotkeys */
332
333
334
335
336
337
338
339
    [_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")];
340
341

    /* input */
342
343
344
345
346
347
348
349
350
351
352
353
    [_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_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")];
354
    [_input_skipFramesCheckbox setTitle: _NS("Skip frames")];
355
356

    /* url handler */
357
358
359
360
    [_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")];
361
362

    /* interface */
363
    [_intf_generalSettingsBox setTitle:_NS("General settings")];
364
365
366
367
    [_intf_languageLabel setStringValue: _NS("Language")];
    [_intf_styleLabel setStringValue: _NS("Interface style")];
    [_intf_style_darkButtonCell setTitle: _NS("Dark")];
    [_intf_style_brightButtonCell setTitle: _NS("Bright")];
368
369
370

    [_intf_playbackControlBox setTitle:_NS("Playback control")];
    [_intf_continueplaybackLabel setStringValue:_NS("Continue playback")];
371
372
    [_intf_appleremoteCheckbox setTitle: _NS("Control playback with the Apple Remote")];
    [_intf_mediakeysCheckbox setTitle: _NS("Control playback with media keys")];
373
    [_intf_appleremote_sysvolCheckbox setTitle: _NS("Control system volume with the Apple Remote")];
Goran Dokic's avatar
Goran Dokic committed
374
    [_intf_statusIconCheckbox setTitle: _NS("Display VLC status menu icon")];
375
376
377
378
379
380

    [_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")];
381
382
383
    [_intf_artCheckbox setTitle: _NS("Allow metadata network access")];
    [_intf_updateCheckbox setTitle: _NS("Automatically check for updates")];
    [_intf_last_updateLabel setStringValue: @""];
384
385

    [_intf_luahttpBox setTitle:_NS("HTTP web interface")];
386
    [_intf_luahttppwdLabel setStringValue:_NS("Password")];
387

388
    /* Subtitles and OSD */
389
390
391
392
393
394
395
396
397
398
399
400
401
402
    [_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")];
403
404

    /* video */
405
    [_video_enableCheckbox setTitle: _NS("Enable video")];
406
407
408
    [_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")];
409
    [_video_onTopCheckbox setTitle: _NS("Float on Top")];
410
411
412
413
414
415
416
417
    [_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")];

418
419
420
421
422
423
424
425
426
    [_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")];
427

428
    /* generic stuff */
429
430
431
432
    [_showAllButton setTitle: _NS("Show All")];
    [_cancelButton setTitle: _NS("Cancel")];
    [_resetButton setTitle: _NS("Reset All")];
    [_saveButton setTitle: _NS("Save")];
433
    [self.window setTitle: _NS("Preferences")];
434
435
}

436
437
/* TODO: move this part to core */
#define config_GetLabel(a,b) __config_GetLabel(VLC_OBJECT(a),b)
438
static inline const char * __config_GetLabel(vlc_object_t *p_this, const char *psz_name)
439
440
441
{
    module_config_t *p_config;

442
    p_config = config_FindConfig(p_this, psz_name);
443
444

    /* sanity checks */
445
446
    if (!p_config) {
        msg_Err(p_this, "option %s does not exist", psz_name);
447
448
449
        return NULL;
    }

450
    if (p_config->psz_longtext)
451
        return p_config->psz_longtext;
452
    else if (p_config->psz_text)
453
454
        return p_config->psz_text;
    else
455
        msg_Warn(p_this, "option %s does not include any help", psz_name);
456
457
458
459

    return NULL;
}

460
461
462
#pragma mark -
#pragma mark Setup controls

463
464
465
466
467
- (void)setupButton: (NSPopUpButton *)object forStringList: (const char *)name
{
    module_config_t *p_item;

    [object removeAllItems];
468
    p_item = config_FindConfig(VLC_OBJECT(p_intf), name);
469
    /* serious problem, if no item found */
470
    assert(p_item);
471

472
    char **values, **texts;
David's avatar
David committed
473
    ssize_t count = config_GetPszChoices(VLC_OBJECT(getIntf()), name,
474
475
476
477
478
479
480
                                         &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)
481
            continue;
482
483
484
485

        if (strcmp(texts[i], "") != 0) {
            NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""];
            [mi setRepresentedObject: toNSStr(values[i])];
486
            [[object menu] addItem:mi];
487
488
489
490
491

            if (p_item->value.psz && !strcmp(p_item->value.psz, values[i]))
                [object selectItem: [object lastItem]];
        } else {
            [[object menu] addItem: [NSMenuItem separatorItem]];
492
        }
493
494
495

        free(texts[i]);
        free(values[i]);
496
    }
497
498
499
500
501
502
503
504
505
506
507
508

    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];
509
510
511
512
513
514
515
}

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

    [object removeAllItems];
516
    p_item = config_FindConfig(VLC_OBJECT(p_intf), name);
517
518

    /* serious problem, if no item found */
519
    assert(p_item);
520

521
522
    int64_t *values;
    char **texts;
David's avatar
David committed
523
    ssize_t count = config_GetIntChoices(VLC_OBJECT(getIntf()), name, &values, &texts);
524
525
526
    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]]];
527
        [[object menu] addItem:mi];
528
529

        if (p_item->value.i == values[i])
530
            [object selectItem:[object lastItem]];
531
532

        free(texts[i]);
533
    }
534
535
536
537
    free(texts);

    if (p_item->psz_longtext)
        [object setToolTip: _NS(p_item->psz_longtext)];
538
539
}

540
541
- (void)setupButton: (NSButton *)object forBoolValue: (const char *)name
{
542
    [object setState: config_GetInt(p_intf, name)];
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
543
    [object setToolTip: _NS(config_GetLabel(p_intf, name))];
544
545
}

546
- (void)setupField:(NSTextField *)object forOption:(const char *)psz_option
547
{
548
    char *psz_tmp = config_GetPsz(p_intf, psz_option);
549
    [object setStringValue: toNSStr(psz_tmp)];
550
    [object setToolTip: _NS(config_GetLabel(p_intf, psz_option))];
551
    free(psz_tmp);
552
553
}

554
555
556
- (void)resetControls
{
    module_config_t *p_item;
557
    int i, y = 0;
558
559
560
561
562
    char *psz_tmp;

    /**********************
     * interface settings *
     **********************/
563
564
565
566
    NSUInteger sel = 0;
    const char *pref = NULL;
    pref = [[[NSUserDefaults standardUserDefaults] objectForKey:@"language"] UTF8String];
    for (int x = 0; ppsz_language[x] != NULL; x++) {
567
        [_intf_languagePopup addItemWithTitle:toNSStr(ppsz_language_text[x])];
568
569
570
571
572
        if (pref) {
            if (!strcmp(ppsz_language[x], pref))
                sel = x;
        }
    }
573
    [_intf_languagePopup selectItemAtIndex:sel];
574

575
    [self setupButton:_intf_continueplaybackPopup forIntList: "macosx-continue-playback"];
576
577
578
579
580
581
582
    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];
    }

583
584
    [self setupButton:_intf_appleremoteCheckbox forBoolValue: "macosx-appleremote"];
    [self setupButton:_intf_appleremote_sysvolCheckbox forBoolValue: "macosx-appleremote-sysvol"];
Goran Dokic's avatar
Goran Dokic committed
585
    [self setupButton:_intf_statusIconCheckbox forBoolValue: "macosx-statusicon"];
586
    [self setupButton:_intf_mediakeysCheckbox forBoolValue: "macosx-mediakeys"];
587

588
589
    [self setupButton:_video_nativeFullscreenCheckbox forBoolValue: "macosx-nativefullscreenmode"];
    [self setupButton:_video_embeddedCheckbox forBoolValue: "embedded-video"];
590

591
    [self setupButton:_intf_pauseitunesPopup forIntList: "macosx-control-itunes"];
592

593
    [self setupButton:_intf_artCheckbox forBoolValue: "metadata-network-access"];
594

595

596
#ifdef HAVE_SPARKLE
597
    if ([[SUUpdater sharedUpdater] lastUpdateCheckDate] != NULL)
598
        [_intf_last_updateLabel setStringValue: [NSString stringWithFormat: _NS("Last check on: %@"), [[[SUUpdater sharedUpdater] lastUpdateCheckDate] descriptionWithLocale: [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]]];
599
    else
600
        [_intf_last_updateLabel setStringValue: _NS("No check was performed yet.")];
601
602
#endif

603
    psz_tmp = config_GetPsz(p_intf, "control");
604
    if (psz_tmp) {
605
        [_intf_enableNotificationsCheckbox setState: (NSInteger)strstr(psz_tmp, "growl")];
606
607
        free(psz_tmp);
    } else
608
        [_intf_enableNotificationsCheckbox setState: NSOffState];
609
    if (config_GetInt(p_intf, "macosx-interfacestyle")) {
610
611
        [_intf_style_darkButtonCell setState: YES];
        [_intf_style_brightButtonCell setState: NO];
612
    } else {
613
614
        [_intf_style_darkButtonCell setState: NO];
        [_intf_style_brightButtonCell setState: YES];
615
    }
616

617
    [self setupField:_intf_luahttppwdTextField forOption: "http-password"];
618
619
620
621

    /******************
     * audio settings *
     ******************/
622
    [self setupButton:_audio_enableCheckbox forBoolValue: "audio"];
623

624
    if (config_GetInt(p_intf, "volume-save")) {
625
626
627
628
        [_audio_autosavevol_yesButtonCell setState: NSOnState];
        [_audio_autosavevol_noButtonCell setState: NSOffState];
        [_audio_volTextField setEnabled: NO];
        [_audio_volSlider setEnabled: NO];
629

630
631
        [_audio_volSlider setIntValue: 100];
        [_audio_volTextField setIntValue: 100];
632
    } else {
633
634
635
636
        [_audio_autosavevol_yesButtonCell setState: NSOffState];
        [_audio_autosavevol_noButtonCell setState: NSOnState];
        [_audio_volTextField setEnabled: YES];
        [_audio_volSlider setEnabled: YES];
637

638
        i = var_InheritInteger(p_intf, "auhal-volume");
639
        i = i * 200. / AOUT_VOLUME_MAX;
640
641
        [_audio_volSlider setIntValue: i];
        [_audio_volTextField setIntValue: i];
642
    }
643

644
645
    [self setupButton:_audio_dolbyPopup forIntList: "force-dolby-surround"];
    [self setupField:_audio_langTextField forOption: "audio-language"];
646

647
    [self setupButton:_audio_visualPopup forModuleList: "audio-visual"];
648

649
    /* Last.FM is optional */
650
    if (module_exists("audioscrobbler")) {
651
652
        [self setupField:_audio_lastuserTextField forOption:"lastfm-username"];
        [self setupField:_audio_lastpwdSecureTextField forOption:"lastfm-password"];
653

654
        if (config_ExistIntf(VLC_OBJECT(p_intf), "audioscrobbler")) {
655
656
657
            [_audio_lastCheckbox setState: NSOnState];
            [_audio_lastuserTextField setEnabled: YES];
            [_audio_lastpwdSecureTextField setEnabled: YES];
658
        } else {
659
660
661
            [_audio_lastCheckbox setState: NSOffState];
            [_audio_lastuserTextField setEnabled: NO];
            [_audio_lastpwdSecureTextField setEnabled: NO];
662
        }
663
    } else
664
        [_audio_lastCheckbox setEnabled: NO];
665
666
667
668

    /******************
     * video settings *
     ******************/
669
    [self setupButton:_video_enableCheckbox forBoolValue: "video"];
670
    [self setupButton:_video_startInFullscreenCheckbox forBoolValue: "fullscreen"];
671
    [self setupButton:_video_onTopCheckbox forBoolValue: "video-on-top"];
672
    [self setupButton:_video_blackScreenCheckbox forBoolValue: "macosx-black"];
673
    [self setupButton:_video_videodecoCheckbox forBoolValue: "video-deco"];
674
    [self setupButton:_video_pauseWhenMinimizedCheckbox forBoolValue: "macosx-pause-minimized"];
675
676

    [_video_devicePopup removeAllItems];
677
678
    i = 0;
    y = [[NSScreen screens] count];
679
680
    [_video_devicePopup addItemWithTitle: _NS("Default")];
    [[_video_devicePopup lastItem] setTag: 0];
681
    while (i < y) {
682
        NSRect s_rect = [[[NSScreen screens] objectAtIndex:i] frame];
683
        [_video_devicePopup addItemWithTitle:
684
685
         [NSString stringWithFormat: @"%@ %i (%ix%i)", _NS("Screen"), i+1,
                   (int)s_rect.size.width, (int)s_rect.size.height]];
686
        [[_video_devicePopup lastItem] setTag: (int)[[[NSScreen screens] objectAtIndex:i] displayID]];
687
688
        i++;
    }
689
690
    [_video_devicePopup selectItemAtIndex: 0];
    [_video_devicePopup selectItemWithTag: config_GetInt(p_intf, "macosx-vdev")];
691

692
693
694
695
696
697
    [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"];
698

699
    // set lion fullscreen mode restrictions
700
    [self enableLionFullscreenMode: [_video_nativeFullscreenCheckbox state]];
701

702
703
704
    /***************************
     * input & codecs settings *
     ***************************/
705
706
707
    [self setupField:_input_recordTextField forOption:"input-record-path"];
    [_input_postprocTextField setIntValue: config_GetInt(p_intf, "postproc-q")];
    [_input_postprocTextField setToolTip: _NS(config_GetLabel(p_intf, "postproc-q"))];
708
    [self setupButton:_input_skipFramesCheckbox forBoolValue: "skip-frames"];
709
710
    [self setupButton:_input_aviPopup forIntList: "avi-index"];
    [self setupButton:_input_skipLoopPopup forIntList: "avcodec-skiploopfilter"];
711

712
    [_input_cachelevelPopup removeAllItems];
713
714
715
716
717
718
719
720
721
722
723
724
    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];
725

726
    #define TestCaC(name, factor) \
727
    cache_equal = cache_equal && \
728
    (i_cache * factor == config_GetInt(p_intf, name));
729
730

    /* Select the accurate value of the PopupButton */
731
    bool cache_equal = true;
732
    int i_cache = config_GetInt(p_intf, "file-caching");
733

734
735
736
    TestCaC("network-caching", 10/3);
    TestCaC("disc-caching", 1);
    TestCaC("live-caching", 1);
737
738
739
    if (cache_equal) {
        [_input_cachelevelPopup selectItemWithTag: i_cache];
        [_input_cachelevel_customLabel setHidden: YES];
740
    } else {
741
742
        [_input_cachelevelPopup selectItemWithTitle: _NS("Custom")];
        [_input_cachelevel_customLabel setHidden: NO];
743
    }
744
    #undef TestCaC
745
746
747
748

    /*********************
     * subtitle settings *
     *********************/
749
    [self setupButton:_osd_osdCheckbox forBoolValue: "osd"];
750

751
752
    [self setupButton:_osd_encodingPopup forStringList: "subsdec-encoding"];
    [self setupField:_osd_langTextField forOption: "sub-language" ];
753

754
755
756
    [self setupField:_osd_fontTextField forOption: "freetype-font"];
    [self setupButton:_osd_font_colorPopup forIntList: "freetype-color"];
    [self setupButton:_osd_font_sizePopup forIntList: "freetype-rel-fontsize"];
757
    i = config_GetInt(p_intf, "freetype-opacity") * 100.0 / 255.0 + 0.5;
758
759
760
761
762
763
764
    [_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"];
765

766
767
768
    /********************
     * hotkeys settings *
     ********************/
769
    const struct hotkey *p_hotkeys = p_intf->obj.libvlc->p_hotkeys;
770
771
772
    _hotkeySettings = [[NSMutableArray alloc] init];
    NSMutableArray *tempArray_desc = [[NSMutableArray alloc] init];
    NSMutableArray *tempArray_names = [[NSMutableArray alloc] init];
773

774
775
    /* Get the main Module */
    module_t *p_main = module_get_main();
776
    assert(p_main);
777
778
    unsigned confsize;
    module_config_t *p_config;
779

780
    p_config = module_config_get (p_main, &confsize);
781

782
    for (size_t i = 0; i < confsize; i++) {
783
        module_config_t *p_item = p_config + i;
784

785
786
787
        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)) {
788
            [tempArray_desc addObject: _NS(p_item->psz_text)];
789
            [tempArray_names addObject: toNSStr(p_item->psz_name)];
790
            if (p_item->value.psz)
791
                [_hotkeySettings addObject: toNSStr(p_item->value.psz)];
792
            else
793
                [_hotkeySettings addObject: [NSString string]];
794
        }
795
    }
796
    module_config_free (p_config);
797

798
799
    _hotkeyDescriptions = [[NSArray alloc] initWithArray:tempArray_desc copyItems: YES];
    _hotkeyNames = [[NSArray alloc] initWithArray:tempArray_names copyItems: YES];
800

801
    [_hotkeys_listbox reloadData];
802
803
}

804
805
806
#pragma mark -
#pragma mark General actions

807
808
809
- (void)showSimplePrefs
{
    /* we want to show the interface settings, if no category was chosen */
810
811
    if ([[self.window toolbar] selectedItemIdentifier] == nil) {
        [[self.window toolbar] setSelectedItemIdentifier: VLCIntfSettingToolbarIdentifier];
812
813
        [self showInterfaceSettings];
    }
814

815
    [self resetControls];
816

817
    [self.window makeKeyAndOrderFront: self];
818
819
}

820
821
- (void)showSimplePrefsWithLevel:(NSInteger)i_window_level
{
822
    [self.window setLevel: i_window_level];
823
824
825
    [self showSimplePrefs];
}

826
827
- (IBAction)buttonAction:(id)sender
{
828
    if (sender == _cancelButton) {
829
        [[NSFontPanel sharedFontPanel] close];
830
        [self.window orderOut: sender];
831
    } else if (sender == _saveButton) {
832
        [self saveChangedSettings];
833
        [[NSFontPanel sharedFontPanel] close];
834
        [self.window orderOut: sender];
835
    } else if (sender == _showAllButton) {
836
837
        [self.window orderOut: self];
        [[[VLCMain sharedInstance] preferences] showPrefsWithLevel:[self.window level]];
838
839
    } else
        msg_Warn(p_intf, "unknown buttonAction sender");
840
841
}

842
843
844
845
846
847
848
849
850
851
852
853
854
- (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?"));
}

855
- (void)sheetDidEnd:(NSWindow *)o_sheet
856
857
858
         returnCode:(int)i_return
        contextInfo:(void *)o_context
{
859
    if (i_return == NSAlertAlternateReturn) {
860
        /* reset VLC's config */
861
        config_ResetAll(p_intf);
862
        [self resetControls];
863
864

        /* force config file creation, since libvlc won't exit normally */
865
        config_SaveConfigFile(p_intf);
866
867

        /* reset OS X defaults */
868
        [[VLCMain sharedInstance] resetAndReinitializeUserDefaults];
869
870
871
872
873
874
875
876
877
878

        /* 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);
879
880
881
    }
}

882
static inline void save_int_list(intf_thread_t * p_intf, id object, const char * name)
883
{
884
885
886
887
888
    NSNumber *p_valueobject = (NSNumber *)[[object selectedItem] representedObject];
    if (p_valueobject) {
        assert([p_valueobject isKindOfClass:[NSNumber class]]);
        config_PutInt(p_intf, name, [p_valueobject intValue]);
    }
889
890
}

891
static inline void save_string_list(intf_thread_t * p_intf, id object, const char * name)
892
{
893
894
895
896
897
    NSString *p_stringobject = (NSString *)[[object selectedItem] representedObject];
    if (p_stringobject) {
        assert([p_stringobject isKindOfClass:[NSString class]]);
        config_PutPsz(p_intf, name, [p_stringobject UTF8String]);
    }
898
899
900
901
}

- (void)saveChangedSettings
{
902
903
    NSString *tmpString;
    NSRange tmpRange;
904

905
#define SaveIntList(object, name) save_int_list(p_intf, object, name)
906

907
#define SaveStringList(object, name) save_string_list(p_intf, object, name)
908
#define SaveModuleList(object, name) SaveStringList(object, name)
909

910
#define getString(name) [NSString stringWithFormat:@"%s", config_GetPsz(p_intf, name)]
911

912
913
914
    /**********************
     * interface settings *
     **********************/
915
916
    if (_intfSettingChanged) {
        NSUInteger index = [_intf_languagePopup indexOfSelectedItem];
917
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
918
        [defaults setObject:toNSStr(ppsz_language[index]) forKey:@"language"];
919
920
        [defaults synchronize];

921
        config_PutInt(p_intf, "metadata-network-access", [_intf_artCheckbox state]);
922

923
924
        config_PutInt(p_intf, "macosx-appleremote", [_intf_appleremoteCheckbox state]);
        config_PutInt(p_intf, "macosx-appleremote-sysvol", [_intf_appleremote_sysvolCheckbox state]);
Goran Dokic's avatar
Goran Dokic committed
925
        config_PutInt(p_intf, "macosx-statusicon", [_intf_statusIconCheckbox state]);
926
927
        config_PutInt(p_intf, "macosx-mediakeys", [_intf_mediakeysCheckbox state]);
        config_PutInt(p_intf, "macosx-interfacestyle", [_intf_style_darkButtonCell state]);
928

929
        if ([_intf_enableNotificationsCheckbox state] == NSOnState) {
Felix Paul Kühne's avatar