]> git.sesse.net Git - vlc/blob - modules/gui/macosx/simple_prefs.m
macosx: reuse existing strings
[vlc] / modules / gui / macosx / simple_prefs.m
1 /*****************************************************************************
2 * simple_prefs.m: Simple Preferences for Mac OS X
3 *****************************************************************************
4 * Copyright (C) 2008-2013 VLC authors and VideoLAN
5 * $Id$
6 *
7 * Authors: Felix Paul Kühne <fkuehne at videolan dot org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #import "CompatibilityFixes.h"
28 #import "simple_prefs.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 "intf.h"
38 #import "AppleRemote.h"
39 #import "CoreInteraction.h"
40
41 #import <Sparkle/Sparkle.h>                        //for o_intf_last_update_lbl
42
43 static const char *const ppsz_language[] =
44 {
45     "auto",
46     "en",
47     "ar",
48     "bn",
49     "pt_BR",
50     "en_GB",
51     "el",
52     "bg",
53     "ca",
54     "zh_TW",
55     "cs",
56     "cy",
57     "da",
58     "nl",
59     "fi",
60     "et",
61     "eu",
62     "fr",
63     "ga",
64     "gd",
65     "gl",
66     "ka",
67     "de",
68     "he",
69     "hr",
70     "hu",
71     "hy",
72     "is",
73     "id",
74     "it",
75     "ja",
76     "ko",
77     "lt",
78     "mn",
79     "ms",
80     "nb",
81     "nn",
82     "kk",
83     "km",
84     "ne",
85     "oc",
86     "fa",
87     "pl",
88     "pt_PT",
89     "pa",
90     "ro",
91     "ru",
92     "zh_CN",
93     "si",
94     "sr",
95     "sk",
96     "sl",
97     "ckb",
98     "es",
99     "sv",
100     "te",
101     "tr",
102     "uk",
103     "vi",
104     "wa",
105     NULL,
106 };
107
108 static const char *const ppsz_language_text[] =
109 {
110     N_("Auto"),
111     "American English",
112     "ﻉﺮﺒﻳ",
113     "বাংলা",
114     "Português Brasileiro",
115     "British English",
116     "Νέα Ελληνικά",
117     "български език",
118     "Català",
119     "正體中文",
120     "Čeština",
121     "Cymraeg",
122     "Dansk",
123     "Nederlands",
124     "Suomi",
125     "eesti keel",
126     "Euskara",
127     "Français",
128     "Gaeilge",
129     "Gàidhlig",
130     "Galego",
131     "ქართული",
132     "Deutsch",
133     "עברית",
134     "hrvatski",
135     "Magyar",
136     "հայերեն",
137     "íslenska",
138     "Bahasa Indonesia",
139     "Italiano",
140     "日本語",
141     "한국어",
142     "lietuvių",
143     "Монгол хэл",
144     "Melayu",
145     "Bokmål",
146     "Nynorsk",
147     "Қазақ тілі",
148     "ភាសាខ្មែរ",
149     "नेपाली",
150     "Occitan",
151     "ﻑﺍﺮﺳی",
152     "Polski",
153     "Português",
154     "ਪੰਜਾਬੀ",
155     "Română",
156     "Русский",
157     "简体中文",
158     "සිංහල",
159     "српски",
160     "Slovensky",
161     "slovenščina",
162     "کوردیی سۆرانی",
163     "Español",
164     "Svenska",
165     "తెలుగు",
166     "Türkçe",
167     "украї́нська мо́ва",
168     "tiếng Việt",
169     "Walon",
170 };
171
172 static NSString* VLCSPrefsToolbarIdentifier = @"Our Simple Preferences Toolbar Identifier";
173 static NSString* VLCIntfSettingToolbarIdentifier = @"Intf Settings Item Identifier";
174 static NSString* VLCAudioSettingToolbarIdentifier = @"Audio Settings Item Identifier";
175 static NSString* VLCVideoSettingToolbarIdentifier = @"Video Settings Item Identifier";
176 static NSString* VLCOSDSettingToolbarIdentifier = @"Subtitles Settings Item Identifier";
177 static NSString* VLCInputSettingToolbarIdentifier = @"Input Settings Item Identifier";
178 static NSString* VLCHotkeysSettingToolbarIdentifier = @"Hotkeys Settings Item Identifier";
179
180 @implementation VLCSimplePrefs
181
182 static VLCSimplePrefs *_o_sharedInstance = nil;
183
184 #pragma mark Initialisation
185
186 + (VLCSimplePrefs *)sharedInstance
187 {
188     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
189 }
190
191 - (id)init
192 {
193     if (_o_sharedInstance)
194         [self dealloc];
195     else {
196         _o_sharedInstance = [super init];
197         p_intf = VLCIntf;
198     }
199
200     return _o_sharedInstance;
201 }
202
203 - (void)dealloc
204 {
205     [o_currentlyShownCategoryView release];
206
207     [o_hotkeySettings release];
208     [o_hotkeyDescriptions release];
209     [o_hotkeyNames release];
210     [o_hotkeysNonUseableKeys release];
211
212     [o_keyInTransition release];
213
214     [super dealloc];
215 }
216
217 - (void)awakeFromNib
218 {
219     [self initStrings];
220
221     /* setup the toolbar */
222     NSToolbar * o_sprefs_toolbar = [[[NSToolbar alloc] initWithIdentifier: VLCSPrefsToolbarIdentifier] autorelease];
223     [o_sprefs_toolbar setAllowsUserCustomization: NO];
224     [o_sprefs_toolbar setAutosavesConfiguration: NO];
225     [o_sprefs_toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
226     [o_sprefs_toolbar setSizeMode: NSToolbarSizeModeRegular];
227     [o_sprefs_toolbar setDelegate: self];
228     [o_sprefs_win setToolbar: o_sprefs_toolbar];
229
230     if (!OSX_SNOW_LEOPARD)
231         [o_sprefs_win setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
232
233     [o_hotkeys_listbox setTarget:self];
234     [o_hotkeys_listbox setDoubleAction:@selector(hotkeyTableDoubleClick:)];
235
236     /* setup useful stuff */
237     o_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-z", @"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-?", nil] retain];
238 }
239
240 #define CreateToolbarItem(o_name, o_desc, o_img, sel) \
241     o_toolbarItem = create_toolbar_item(o_itemIdent, o_name, o_desc, o_img, self, @selector(sel));
242 static inline NSToolbarItem *
243 create_toolbar_item(NSString * o_itemIdent, NSString * o_name, NSString * o_desc, NSString * o_img, id target, SEL selector)
244 {
245     NSToolbarItem *o_toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: o_itemIdent] autorelease]; \
246
247     [o_toolbarItem setLabel: o_name];
248     [o_toolbarItem setPaletteLabel: o_desc];
249
250     [o_toolbarItem setToolTip: o_desc];
251     [o_toolbarItem setImage: [NSImage imageNamed: o_img]];
252
253     [o_toolbarItem setTarget: target];
254     [o_toolbarItem setAction: selector];
255
256     [o_toolbarItem setEnabled: YES];
257     [o_toolbarItem setAutovalidates: YES];
258
259     return o_toolbarItem;
260 }
261
262 - (NSToolbarItem *) toolbar: (NSToolbar *)o_sprefs_toolbar
263       itemForItemIdentifier: (NSString *)o_itemIdent
264   willBeInsertedIntoToolbar: (BOOL)b_willBeInserted
265 {
266     NSToolbarItem *o_toolbarItem = nil;
267
268     if ([o_itemIdent isEqual: VLCIntfSettingToolbarIdentifier]) {
269         CreateToolbarItem(_NS("Interface"), _NS("Interface Settings"), @"spref_cone_Interface_64", showInterfaceSettings);
270     } else if ([o_itemIdent isEqual: VLCAudioSettingToolbarIdentifier]) {
271         CreateToolbarItem(_NS("Audio"), _NS("Audio Settings"), @"spref_cone_Audio_64", showAudioSettings);
272     } else if ([o_itemIdent isEqual: VLCVideoSettingToolbarIdentifier]) {
273         CreateToolbarItem(_NS("Video"), _NS("Video Settings"), @"spref_cone_Video_64", showVideoSettings);
274     } else if ([o_itemIdent isEqual: VLCOSDSettingToolbarIdentifier]) {
275         CreateToolbarItem(_NS(SUBPIC_TITLE), _NS("Subtitle & On Screen Display Settings"), @"spref_cone_Subtitles_64", showOSDSettings);
276     } else if ([o_itemIdent isEqual: VLCInputSettingToolbarIdentifier]) {
277         CreateToolbarItem(_NS(INPUT_TITLE), _NS("Input & Codec Settings"), @"spref_cone_Input_64", showInputSettings);
278     } else if ([o_itemIdent isEqual: VLCHotkeysSettingToolbarIdentifier]) {
279         CreateToolbarItem(_NS("Hotkeys"), _NS("Hotkeys settings"), @"spref_cone_Hotkeys_64", showHotkeySettings);
280     }
281
282     return o_toolbarItem;
283 }
284
285 - (NSArray *)toolbarDefaultItemIdentifiers: (NSToolbar *)toolbar
286 {
287     return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
288              VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier,
289              NSToolbarFlexibleSpaceItemIdentifier, nil];
290 }
291
292 - (NSArray *)toolbarAllowedItemIdentifiers: (NSToolbar *)toolbar
293 {
294     return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
295              VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier,
296              NSToolbarFlexibleSpaceItemIdentifier, nil];
297 }
298
299 - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
300 {
301     return [NSArray arrayWithObjects:VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
302              VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier, nil];
303 }
304
305 - (void)initStrings
306 {
307     /* audio */
308     [o_audio_dolby_txt setStringValue: _NS("Force detection of Dolby Surround")];
309     [o_audio_effects_box setTitle: _NS("Effects")];
310     [o_audio_enable_ckb setTitle: _NS("Enable audio")];
311     [o_audio_general_box setTitle: _NS("General Audio")];
312     [o_audio_lang_txt setStringValue: _NS("Preferred Audio language")];
313     [o_audio_last_ckb setTitle: _NS("Enable Last.fm submissions")];
314     [o_audio_lastpwd_txt setStringValue: _NS("Password")];
315     [o_audio_lastuser_txt setStringValue: _NS("User name")];
316     [o_audio_spdif_ckb setTitle: _NS("Use S/PDIF when available")];
317     [o_audio_visual_txt setStringValue: _NS("Visualization")];
318     [o_audio_autosavevol_yes_bcell setTitle: _NS("Keep audio level between sessions")];
319     [o_audio_autosavevol_no_bcell setTitle: _NS("Always reset audio start level to:")];
320
321     /* hotkeys */
322     [o_hotkeys_change_btn setTitle: _NS("Change")];
323     [o_hotkeys_change_win setTitle: _NS("Change Hotkey")];
324     [o_hotkeys_change_cancel_btn setTitle: _NS("Cancel")];
325     [o_hotkeys_change_ok_btn setTitle: _NS("OK")];
326     [o_hotkeys_clear_btn setTitle: _NS("Clear")];
327     [o_hotkeys_lbl setStringValue: _NS("Select an action to change the associated hotkey:")];
328     [[[o_hotkeys_listbox tableColumnWithIdentifier: @"action"] headerCell] setStringValue: _NS("Action")];
329     [[[o_hotkeys_listbox tableColumnWithIdentifier: @"shortcut"] headerCell] setStringValue: _NS("Shortcut")];
330
331     /* input */
332     [o_input_record_box setTitle: _NS("Record directory or filename")];
333     [o_input_record_btn setTitle: _NS("Browse...")];
334     [o_input_record_btn setToolTip: _NS("Directory or filename where the records will be stored")];
335     [o_input_avi_txt setStringValue: _NS("Repair AVI Files")];
336     [o_input_cachelevel_txt setStringValue: _NS("Default Caching Level")];
337     [o_input_caching_box setTitle: _NS("Caching")];
338     [o_input_cachelevel_custom_txt setStringValue: _NS("Use the complete preferences to configure custom caching values for each access module.")];
339     [o_input_mux_box setTitle: _NS("Codecs / Muxers")];
340     [o_input_net_box setTitle: _NS("Network")];
341     [o_input_avcodec_hw_txt setStringValue: _NS("Hardware Acceleration")];
342     [o_input_postproc_txt setStringValue: _NS("Post-Processing Quality")];
343     [o_input_rtsp_ckb setTitle: _NS("Use RTP over RTSP (TCP)")];
344     [o_input_skipLoop_txt setStringValue: _NS("Skip the loop filter for H.264 decoding")];
345     [o_input_mkv_preload_dir_ckb setTitle: _NS("Preload MKV files in the same directory")];
346     [o_input_urlhandler_btn setTitle: _NS("Edit default application settings for network protocols")];
347
348     /* url handler */
349     [o_urlhandler_title_txt setStringValue: _NS("Open network streams using the following protocols")];
350     [o_urlhandler_subtitle_txt setStringValue: _NS("Note that these are system-wide settings.")];
351     [o_urlhandler_save_btn setTitle: _NS("Save")];
352     [o_urlhandler_cancel_btn setTitle: _NS("Cancel")];
353
354     /* interface */
355     [o_intf_language_txt setStringValue: _NS("Language")];
356     [o_intf_style_txt setStringValue: _NS("Interface style")];
357     [o_intf_style_dark_bcell setTitle: _NS("Dark")];
358     [o_intf_style_bright_bcell setTitle: _NS("Bright")];
359     [o_intf_art_txt setStringValue: _NS("Album art download policy")];
360     [o_intf_embedded_ckb setTitle: _NS("Show video within the main window")];
361     [o_intf_nativefullscreen_ckb setTitle: _NS("Use the native fullscreen mode")];
362     [o_intf_fspanel_ckb setTitle: _NS("Show Fullscreen Controller")];
363     [o_intf_network_box setTitle: _NS("Privacy / Network Interaction")];
364     [o_intf_appleremote_ckb setTitle: _NS("Control playback with the Apple Remote")];
365     [o_intf_appleremote_sysvol_ckb setTitle: _NS("Control system volume with the Apple Remote")];
366     [o_intf_mediakeys_ckb setTitle: _NS("Control playback with media keys")];
367     [o_intf_update_ckb setTitle: _NS("Automatically check for updates")];
368     [o_intf_last_update_lbl setStringValue: @""];
369     [o_intf_enableGrowl_ckb setTitle: _NS("Enable Growl notifications (on playlist item change)")];
370     [o_intf_autoresize_ckb setTitle: _NS("Resize interface to the native video size")];
371     [o_intf_pauseminimized_ckb setTitle: _NS("Pause the video playback when minimized")];
372     [o_intf_luahttp_box setTitle:_NS("Lua HTTP")];
373     [o_intf_luahttppwd_lbl setStringValue:_NS("Password")];
374     [o_intf_pauseitunes_lbl setStringValue:_NS("Pause iTunes during VLC playback")];
375
376     /* Subtitles and OSD */
377     [o_osd_encoding_txt setStringValue: _NS("Default Encoding")];
378     [o_osd_font_box setTitle: _NS("Display Settings")];
379     [o_osd_font_btn setTitle: _NS("Choose...")];
380     [o_osd_font_color_txt setStringValue: _NS("Font color")];
381     [o_osd_font_size_txt setStringValue: _NS("Font size")];
382     [o_osd_font_txt setStringValue: _NS("Font")];
383     [o_osd_lang_box setTitle: _NS("Subtitle languages")];
384     [o_osd_lang_txt setStringValue: _NS("Preferred subtitle language")];
385     [o_osd_osd_box setTitle: _NS("On Screen Display")];
386     [o_osd_osd_ckb setTitle: _NS("Enable OSD")];
387     [o_osd_opacity_txt setStringValue: _NS("Opacity")];
388     [o_osd_forcebold_ckb setTitle: _NS("Force bold")];
389     [o_osd_outline_color_txt setStringValue: _NS("Outline color")];
390     [o_osd_outline_thickness_txt setStringValue: _NS("Outline thickness")];
391
392     /* video */
393     [o_video_black_ckb setTitle: _NS("Black screens in Fullscreen mode")];
394     [o_video_device_txt setStringValue: _NS("Fullscreen Video Device")];
395     [o_video_display_box setTitle: _NS("Display")];
396     [o_video_enable_ckb setTitle: _NS("Enable video")];
397     [o_video_fullscreen_ckb setTitle: _NS("Fullscreen")];
398     [o_video_videodeco_ckb setTitle: _NS("Window decorations")];
399     [o_video_onTop_ckb setTitle: _NS("Float on Top")];
400     [o_video_output_txt setStringValue: _NS("Output module")];
401     [o_video_skipFrames_ckb setTitle: _NS("Skip frames")];
402     [o_video_snap_box setTitle: _NS("Video snapshots")];
403     [o_video_snap_folder_btn setTitle: _NS("Browse...")];
404     [o_video_snap_folder_txt setStringValue: _NS("Folder")];
405     [o_video_snap_format_txt setStringValue: _NS("Format")];
406     [o_video_snap_prefix_txt setStringValue: _NS("Prefix")];
407     [o_video_snap_seqnum_ckb setTitle: _NS("Sequential numbering")];
408     [o_video_deinterlace_txt setStringValue: _NS("Deinterlace")];
409     [o_video_deinterlace_mode_txt setStringValue: _NS("Deinterlace mode")];
410     [o_video_video_box setTitle: _NS("Video")];
411
412     /* generic stuff */
413     [o_sprefs_showAll_btn setTitle: _NS("Show All")];
414     [o_sprefs_cancel_btn setTitle: _NS("Cancel")];
415     [o_sprefs_reset_btn setTitle: _NS("Reset All")];
416     [o_sprefs_save_btn setTitle: _NS("Save")];
417     [o_sprefs_win setTitle: _NS("Preferences")];
418 }
419
420 /* TODO: move this part to core */
421 #define config_GetLabel(a,b) __config_GetLabel(VLC_OBJECT(a),b)
422 static inline char * __config_GetLabel(vlc_object_t *p_this, const char *psz_name)
423 {
424     module_config_t *p_config;
425
426     p_config = config_FindConfig(p_this, psz_name);
427
428     /* sanity checks */
429     if (!p_config) {
430         msg_Err(p_this, "option %s does not exist", psz_name);
431         return NULL;
432     }
433
434     if (p_config->psz_longtext)
435         return p_config->psz_longtext;
436     else if (p_config->psz_text)
437         return p_config->psz_text;
438     else
439         msg_Warn(p_this, "option %s does not include any help", psz_name);
440
441     return NULL;
442 }
443
444 #pragma mark -
445 #pragma mark Setup controls
446
447 - (void)setupButton: (NSPopUpButton *)object forStringList: (const char *)name
448 {
449     module_config_t *p_item;
450
451     [object removeAllItems];
452     p_item = config_FindConfig(VLC_OBJECT(p_intf), name);
453     /* serious problem, if no item found */
454     assert(p_item);
455
456     char **values, **texts;
457     ssize_t count = config_GetPszChoices(VLC_OBJECT(VLCIntf), name,
458                                          &values, &texts);
459     if (count < 0) {
460         msg_Err(p_intf, "Cannot get choices for %s", name);
461         return;
462     }
463     for (ssize_t i = 0; i < count && texts; i++) {
464         if (texts[i] == NULL || values[i] == NULL)
465             continue;
466
467         if (strcmp(texts[i], "") != 0) {
468             NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""];
469             [mi setRepresentedObject: toNSStr(values[i])];
470             [[object menu] addItem: [mi autorelease]];
471
472             if (p_item->value.psz && !strcmp(p_item->value.psz, values[i]))
473                 [object selectItem: [object lastItem]];
474             
475         } else {
476             [[object menu] addItem: [NSMenuItem separatorItem]];
477         }
478
479         free(texts[i]);
480         free(values[i]);
481     }
482
483     free(texts);
484     free(values);
485
486     if (p_item->psz_longtext)
487         [object setToolTip: _NS(p_item->psz_longtext)];
488 }
489
490 // just for clarification that this is a module list
491 - (void)setupButton: (NSPopUpButton *)object forModuleList: (const char *)name
492 {
493     [self setupButton: object forStringList: name];
494 }
495
496 - (void)setupButton: (NSPopUpButton *)object forIntList: (const char *)name
497 {
498     module_config_t *p_item;
499
500     [object removeAllItems];
501     p_item = config_FindConfig(VLC_OBJECT(p_intf), name);
502
503     /* serious problem, if no item found */
504     assert(p_item);
505
506     int64_t *values;
507     char **texts;
508     ssize_t count = config_GetIntChoices(VLC_OBJECT(VLCIntf), name, &values, &texts);
509     for (ssize_t i = 0; i < count; i++) {
510         NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""];
511         [mi setRepresentedObject:[NSNumber numberWithInt:values[i]]];
512         [[object menu] addItem: [mi autorelease]];
513
514         if (p_item->value.i == values[i])
515             [object selectItem:[object lastItem]];
516
517         free(texts[i]);
518     }
519     free(texts);
520
521     if (p_item->psz_longtext)
522         [object setToolTip: _NS(p_item->psz_longtext)];
523 }
524
525 - (void)setupButton: (NSButton *)object forBoolValue: (const char *)name
526 {
527     [object setState: config_GetInt(p_intf, name)];
528     [object setToolTip: _NS(config_GetLabel(p_intf, name))];
529 }
530
531 - (void)setupField:(NSTextField *)o_object forOption:(const char *)psz_option
532 {
533     char *psz_tmp = config_GetPsz(p_intf, psz_option);
534     [o_object setStringValue: [NSString stringWithUTF8String:psz_tmp ?: ""]];
535     [o_object setToolTip: _NS(config_GetLabel(p_intf, psz_option))];
536     free(psz_tmp);
537 }
538
539 - (void)resetControls
540 {
541     module_config_t *p_item;
542     int i, y = 0;
543     char *psz_tmp;
544
545     /**********************
546      * interface settings *
547      **********************/
548     NSUInteger sel = 0;
549     const char *pref = NULL;
550     pref = [[[NSUserDefaults standardUserDefaults] objectForKey:@"language"] UTF8String];
551     for (int x = 0; ppsz_language[x] != NULL; x++) {
552         [o_intf_language_pop addItemWithTitle:[NSString stringWithUTF8String:ppsz_language_text[x]]];
553         if (pref) {
554             if (!strcmp(ppsz_language[x], pref))
555                 sel = x;
556         }
557     }
558     [o_intf_language_pop selectItemAtIndex:sel];
559
560     [self setupButton: o_intf_art_pop forIntList: "album-art"];
561
562     [self setupButton: o_intf_fspanel_ckb forBoolValue: "macosx-fspanel"];
563
564     [self setupButton: o_intf_nativefullscreen_ckb forBoolValue: "macosx-nativefullscreenmode"];
565     BOOL b_correct_sdk = NO;
566 #ifdef MAC_OS_X_VERSION_10_7
567     b_correct_sdk = YES;
568 #endif
569     if (!(b_correct_sdk && !OSX_SNOW_LEOPARD)) {
570         [o_intf_nativefullscreen_ckb setState: NSOffState];
571         [o_intf_nativefullscreen_ckb setEnabled: NO];
572     }
573
574     [self setupButton: o_intf_embedded_ckb forBoolValue: "embedded-video"];
575
576     [self setupButton: o_intf_appleremote_ckb forBoolValue: "macosx-appleremote"];
577     [self setupButton: o_intf_appleremote_sysvol_ckb forBoolValue: "macosx-appleremote-sysvol"];
578
579     [self setupButton: o_intf_mediakeys_ckb forBoolValue: "macosx-mediakeys"];
580     if ([[SUUpdater sharedUpdater] lastUpdateCheckDate] != NULL)
581         [o_intf_last_update_lbl setStringValue: [NSString stringWithFormat: _NS("Last check on: %@"), [[[SUUpdater sharedUpdater] lastUpdateCheckDate] descriptionWithLocale: [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]]];
582     else
583         [o_intf_last_update_lbl setStringValue: _NS("No check was performed yet.")];
584     psz_tmp = config_GetPsz(p_intf, "control");
585     if (psz_tmp) {
586         [o_intf_enableGrowl_ckb setState: (NSInteger)strstr(psz_tmp, "growl")];
587         free(psz_tmp);
588     } else
589         [o_intf_enableGrowl_ckb setState: NSOffState];
590     if (config_GetInt(p_intf, "macosx-interfacestyle")) {
591         [o_intf_style_dark_bcell setState: YES];
592         [o_intf_style_bright_bcell setState: NO];
593     } else {
594         [o_intf_style_dark_bcell setState: NO];
595         [o_intf_style_bright_bcell setState: YES];
596     }
597     [self setupButton: o_intf_autoresize_ckb forBoolValue: "macosx-video-autoresize"];
598     [self setupButton: o_intf_pauseminimized_ckb forBoolValue: "macosx-pause-minimized"];
599     [self setupField: o_intf_luahttppwd_fld forOption: "http-password"];
600     [self setupButton: o_intf_pauseitunes_pop forIntList: "macosx-control-itunes"];
601
602     /******************
603      * audio settings *
604      ******************/
605     [self setupButton: o_audio_enable_ckb forBoolValue: "audio"];
606
607     if (config_GetInt(p_intf, "volume-save")) {
608         [o_audio_autosavevol_yes_bcell setState: NSOnState];
609         [o_audio_autosavevol_no_bcell setState: NSOffState];
610         [o_audio_vol_fld setEnabled: NO];
611         [o_audio_vol_sld setEnabled: NO];
612
613         [o_audio_vol_sld setIntValue: 100];
614         [o_audio_vol_fld setIntValue: 100];
615     } else {
616         [o_audio_autosavevol_yes_bcell setState: NSOffState];
617         [o_audio_autosavevol_no_bcell setState: NSOnState];
618         [o_audio_vol_fld setEnabled: YES];
619         [o_audio_vol_sld setEnabled: YES];
620
621         i = var_InheritInteger(p_intf, "auhal-volume");
622         i = i * 200. / AOUT_VOLUME_MAX;
623         [o_audio_vol_sld setIntValue: i];
624         [o_audio_vol_fld setIntValue: i];
625     }
626
627     [self setupButton: o_audio_spdif_ckb forBoolValue: "spdif"];
628
629     [self setupButton: o_audio_dolby_pop forIntList: "force-dolby-surround"];
630     [self setupField: o_audio_lang_fld forOption: "audio-language"];
631
632     [self setupButton: o_audio_visual_pop forModuleList: "audio-visual"];
633
634     /* Last.FM is optional */
635     if (module_exists("audioscrobbler")) {
636         [self setupField: o_audio_lastuser_fld forOption:"lastfm-username"];
637         [self setupField: o_audio_lastpwd_sfld forOption:"lastfm-password"];
638
639         if (config_ExistIntf(VLC_OBJECT(p_intf), "audioscrobbler")) {
640             [o_audio_last_ckb setState: NSOnState];
641             [o_audio_lastuser_fld setEnabled: YES];
642             [o_audio_lastpwd_sfld setEnabled: YES];
643         } else {
644             [o_audio_last_ckb setState: NSOffState];
645             [o_audio_lastuser_fld setEnabled: NO];
646             [o_audio_lastpwd_sfld setEnabled: NO];
647         }
648     } else
649         [o_audio_last_ckb setEnabled: NO];
650
651     /******************
652      * video settings *
653      ******************/
654     [self setupButton: o_video_enable_ckb forBoolValue: "video"];
655     [self setupButton: o_video_fullscreen_ckb forBoolValue: "fullscreen"];
656     [self setupButton: o_video_onTop_ckb forBoolValue: "video-on-top"];
657     [self setupButton: o_video_skipFrames_ckb forBoolValue: "skip-frames"];
658     [self setupButton: o_video_black_ckb forBoolValue: "macosx-black"];
659     [self setupButton: o_video_videodeco_ckb forBoolValue: "video-deco"];
660
661     [self setupButton: o_video_output_pop forModuleList: "vout"];
662
663     [o_video_device_pop removeAllItems];
664     i = 0;
665     y = [[NSScreen screens] count];
666     [o_video_device_pop addItemWithTitle: _NS("Default")];
667     [[o_video_device_pop lastItem] setTag: 0];
668     while (i < y) {
669         NSRect s_rect = [[[NSScreen screens] objectAtIndex:i] frame];
670         [o_video_device_pop addItemWithTitle:
671          [NSString stringWithFormat: @"%@ %i (%ix%i)", _NS("Screen"), i+1,
672                    (int)s_rect.size.width, (int)s_rect.size.height]];
673         [[o_video_device_pop lastItem] setTag: (int)[[[NSScreen screens] objectAtIndex:i] displayID]];
674         i++;
675     }
676     [o_video_device_pop selectItemAtIndex: 0];
677     [o_video_device_pop selectItemWithTag: config_GetInt(p_intf, "macosx-vdev")];
678
679     [self setupField: o_video_snap_folder_fld forOption:"snapshot-path"];
680     [self setupField: o_video_snap_prefix_fld forOption:"snapshot-prefix"];
681     [self setupButton: o_video_snap_seqnum_ckb forBoolValue: "snapshot-sequential"];
682     [self setupButton: o_video_snap_format_pop forStringList: "snapshot-format"];
683     [self setupButton: o_video_deinterlace_pop forIntList: "deinterlace"];
684     [self setupButton: o_video_deinterlace_mode_pop forStringList: "deinterlace-mode"];
685
686     // set lion fullscreen mode restrictions
687     [self enableLionFullscreenMode: [o_intf_nativefullscreen_ckb state]];
688
689     /***************************
690      * input & codecs settings *
691      ***************************/
692     [self setupField: o_input_record_fld forOption:"input-record-path"];
693     [o_input_postproc_fld setIntValue: config_GetInt(p_intf, "postproc-q")];
694     [o_input_postproc_fld setToolTip: _NS(config_GetLabel(p_intf, "postproc-q"))];
695     [self setupButton: o_input_avcodec_hw_pop forModuleList: "avcodec-hw"];
696
697     [self setupButton: o_input_avi_pop forIntList: "avi-index"];
698
699     [self setupButton: o_input_rtsp_ckb forBoolValue: "rtsp-tcp"];
700     [self setupButton: o_input_skipLoop_pop forIntList: "avcodec-skiploopfilter"];
701
702     [self setupButton: o_input_mkv_preload_dir_ckb forBoolValue: "mkv-preload-local-dir"];
703
704     [o_input_cachelevel_pop removeAllItems];
705     [o_input_cachelevel_pop addItemsWithTitles: [NSArray arrayWithObjects:_NS("Custom"), _NS("Lowest latency"),
706      _NS("Low latency"), _NS("Normal"), _NS("High latency"), _NS("Higher latency"), nil]];
707     [[o_input_cachelevel_pop itemAtIndex: 0] setTag: 0];
708     [[o_input_cachelevel_pop itemAtIndex: 1] setTag: 100];
709     [[o_input_cachelevel_pop itemAtIndex: 2] setTag: 200];
710     [[o_input_cachelevel_pop itemAtIndex: 3] setTag: 300];
711     [[o_input_cachelevel_pop itemAtIndex: 4] setTag: 500];
712     [[o_input_cachelevel_pop itemAtIndex: 5] setTag: 1000];
713
714     #define TestCaC(name, factor) \
715     b_cache_equal =  b_cache_equal && \
716     (i_cache * factor == config_GetInt(p_intf, name));
717
718     /* Select the accurate value of the PopupButton */
719     bool b_cache_equal = true;
720     int i_cache = config_GetInt(p_intf, "file-caching");
721
722     TestCaC("network-caching", 10/3);
723     TestCaC("disc-caching", 1);
724     TestCaC("live-caching", 1);
725     if (b_cache_equal) {
726         [o_input_cachelevel_pop selectItemWithTag: i_cache];
727         [o_input_cachelevel_custom_txt setHidden: YES];
728     } else {
729         [o_input_cachelevel_pop selectItemWithTitle: _NS("Custom")];
730         [o_input_cachelevel_custom_txt setHidden: NO];
731     }
732     #undef TestCaC
733
734     /*********************
735      * subtitle settings *
736      *********************/
737     [self setupButton: o_osd_osd_ckb forBoolValue: "osd"];
738
739     [self setupButton: o_osd_encoding_pop forStringList: "subsdec-encoding"];
740     [self setupField: o_osd_lang_fld forOption: "sub-language" ];
741
742     [self setupField: o_osd_font_fld forOption: "freetype-font"];
743     [self setupButton: o_osd_font_color_pop forIntList: "freetype-color"];
744     [self setupButton: o_osd_font_size_pop forIntList: "freetype-rel-fontsize"];
745     i = config_GetInt(p_intf, "freetype-opacity") * 100.0 / 255.0 + 0.5;
746     [o_osd_opacity_fld setIntValue: i];
747     [o_osd_opacity_sld setIntValue: i];
748     [o_osd_opacity_sld setToolTip: _NS(config_GetLabel(p_intf, "freetype-opacity"))];
749     [o_osd_opacity_fld setToolTip: [o_osd_opacity_sld toolTip]];
750     [self setupButton: o_osd_forcebold_ckb forBoolValue: "freetype-bold"];
751     [self setupButton: o_osd_outline_color_pop forIntList: "freetype-outline-color"];
752     [self setupButton: o_osd_outline_thickness_pop forIntList: "freetype-outline-thickness"];
753
754     /********************
755      * hotkeys settings *
756      ********************/
757     const struct hotkey *p_hotkeys = p_intf->p_libvlc->p_hotkeys;
758     [o_hotkeySettings release];
759     o_hotkeySettings = [[NSMutableArray alloc] init];
760     NSMutableArray *o_tempArray_desc = [[NSMutableArray alloc] init];
761     NSMutableArray *o_tempArray_names = [[NSMutableArray alloc] init];
762
763     /* Get the main Module */
764     module_t *p_main = module_get_main();
765     assert(p_main);
766     unsigned confsize;
767     module_config_t *p_config;
768
769     p_config = module_config_get (p_main, &confsize);
770
771     for (size_t i = 0; i < confsize; i++) {
772         module_config_t *p_item = p_config + i;
773
774         if (CONFIG_ITEM(p_item->i_type) && p_item->psz_name != NULL
775            && !strncmp(p_item->psz_name , "key-", 4)
776            && !EMPTY_STR(p_item->psz_text)) {
777             [o_tempArray_desc addObject: _NS(p_item->psz_text)];
778             [o_tempArray_names addObject: [NSString stringWithUTF8String:p_item->psz_name]];
779             if (p_item->value.psz)
780                 [o_hotkeySettings addObject: [NSString stringWithUTF8String:p_item->value.psz]];
781             else
782                 [o_hotkeySettings addObject: [NSString string]];
783         }
784     }
785     module_config_free (p_config);
786
787     [o_hotkeyDescriptions release];
788     o_hotkeyDescriptions = [[NSArray alloc] initWithArray: o_tempArray_desc copyItems: YES];
789     [o_tempArray_desc release];
790     [o_hotkeyNames release];
791     o_hotkeyNames = [[NSArray alloc] initWithArray: o_tempArray_names copyItems: YES];
792     [o_tempArray_names release];
793     [o_hotkeys_listbox reloadData];
794 }
795
796 #pragma mark -
797 #pragma mark General actions
798
799 - (void)showSimplePrefs
800 {
801     /* we want to show the interface settings, if no category was chosen */
802     if ([[o_sprefs_win toolbar] selectedItemIdentifier] == nil) {
803         [[o_sprefs_win toolbar] setSelectedItemIdentifier: VLCIntfSettingToolbarIdentifier];
804         [self showInterfaceSettings];
805     }
806
807     [self resetControls];
808
809     [o_sprefs_win center];
810     [o_sprefs_win makeKeyAndOrderFront: self];
811 }
812
813 - (void)showSimplePrefsWithLevel:(NSInteger)i_window_level
814 {
815     [o_sprefs_win setLevel: i_window_level];
816     [self showSimplePrefs];
817 }
818
819 - (IBAction)buttonAction:(id)sender
820 {
821     if (sender == o_sprefs_cancel_btn) {
822         [[NSFontPanel sharedFontPanel] close];
823         [o_sprefs_win orderOut: sender];
824     } else if (sender == o_sprefs_save_btn) {
825         [self saveChangedSettings];
826         [[NSFontPanel sharedFontPanel] close];
827         [o_sprefs_win orderOut: sender];
828     } else if (sender == o_sprefs_showAll_btn) {
829         [o_sprefs_win orderOut: self];
830         [[[VLCMain sharedInstance] preferences] showPrefsWithLevel:[o_sprefs_win level]];
831     } else
832         msg_Warn(p_intf, "unknown buttonAction sender");
833 }
834
835 - (IBAction)resetPreferences:(NSControl *)sender
836 {
837     NSBeginInformationalAlertSheet(_NS("Reset Preferences"), _NS("Cancel"),
838                                    _NS("Continue"), nil, [sender window], self,
839                                    @selector(sheetDidEnd: returnCode: contextInfo:), NULL, nil, @"%@",
840                                    _NS("This will reset VLC media player's preferences.\n\n"
841                                        "Note that VLC will restart during the process, so your current "
842                                        "playlist will be emptied and eventual playback, streaming or "
843                                        "transcoding activities will stop immediately.\n\n"
844                                        "The Media Library will not be affected.\n\n"
845                                        "Are you sure you want to continue?"));
846 }
847
848 - (void)sheetDidEnd:(NSWindow *)o_sheet
849          returnCode:(int)i_return
850         contextInfo:(void *)o_context
851 {
852     if (i_return == NSAlertAlternateReturn) {
853         /* reset VLC's config */
854         config_ResetAll(p_intf);
855         [self resetControls];
856
857         /* force config file creation, since libvlc won't exit normally */
858         config_SaveConfigFile(p_intf);
859
860         /* reset OS X defaults */
861         [[VLCMain sharedInstance] resetAndReinitializeUserDefaults];
862
863         /* Relaunch now */
864         const char * path = [[[NSBundle mainBundle] executablePath] UTF8String];
865
866         /* For some reason we need to fork(), not just execl(), which reports a ENOTSUP then. */
867         if (fork() != 0) {
868             exit(0);
869             return;
870         }
871         execl(path, path, NULL);
872     }
873 }
874
875 static inline void save_int_list(intf_thread_t * p_intf, id object, const char * name)
876 {
877     NSNumber *p_valueobject = (NSNumber *)[[object selectedItem] representedObject];
878     if (p_valueobject) {
879         assert([p_valueobject isKindOfClass:[NSNumber class]]);
880         config_PutInt(p_intf, name, [p_valueobject intValue]);
881     }
882 }
883
884 static inline void save_string_list(intf_thread_t * p_intf, id object, const char * name)
885 {
886     NSString *p_stringobject = (NSString *)[[object selectedItem] representedObject];
887     if (p_stringobject) {
888         assert([p_stringobject isKindOfClass:[NSString class]]);
889         config_PutPsz(p_intf, name, [p_stringobject UTF8String]);
890     }
891 }
892
893 - (void)saveChangedSettings
894 {
895     NSString *tmpString;
896     NSRange tmpRange;
897
898 #define SaveIntList(object, name) save_int_list(p_intf, object, name)
899
900 #define SaveStringList(object, name) save_string_list(p_intf, object, name)
901 #define SaveModuleList(object, name) SaveStringList(object, name)
902
903 #define getString(name) [NSString stringWithFormat:@"%s", config_GetPsz(p_intf, name)]
904
905     /**********************
906      * interface settings *
907      **********************/
908     if (b_intfSettingChanged) {
909         NSUInteger index = [o_intf_language_pop indexOfSelectedItem];
910         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
911         [defaults setObject:[NSString stringWithUTF8String:ppsz_language[index]] forKey:@"language"];
912         [defaults synchronize];
913
914         SaveIntList(o_intf_art_pop, "album-art");
915
916         config_PutInt(p_intf, "macosx-fspanel", [o_intf_fspanel_ckb state]);
917         config_PutInt(p_intf, "embedded-video", [o_intf_embedded_ckb state]);
918
919         config_PutInt(p_intf, "macosx-appleremote", [o_intf_appleremote_ckb state]);
920         config_PutInt(p_intf, "macosx-appleremote-sysvol", [o_intf_appleremote_sysvol_ckb state]);
921         config_PutInt(p_intf, "macosx-mediakeys", [o_intf_mediakeys_ckb state]);
922         config_PutInt(p_intf, "macosx-interfacestyle", [o_intf_style_dark_bcell state]);
923         config_PutInt(p_intf, "macosx-nativefullscreenmode", [o_intf_nativefullscreen_ckb state]);
924         config_PutInt(p_intf, "macosx-pause-minimized", [o_intf_pauseminimized_ckb state]);
925         config_PutInt(p_intf, "macosx-video-autoresize", [o_intf_autoresize_ckb state]);
926         if ([o_intf_enableGrowl_ckb state] == NSOnState) {
927             tmpString = getString("control");
928             tmpRange = [tmpString rangeOfString:@"growl"];
929             if ([tmpString length] > 0 && tmpRange.location == NSNotFound)
930             {
931                 tmpString = [tmpString stringByAppendingString: @":growl"];
932                 config_PutPsz(p_intf, "control", [tmpString UTF8String]);
933             }
934             else
935                 config_PutPsz(p_intf, "control", "growl");
936         } else {
937             tmpString = getString("control");
938             if (! [tmpString isEqualToString:@""])
939             {
940                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@":growl"]];
941                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"growl:"]];
942                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"growl"]];
943                 config_PutPsz(p_intf, "control", [tmpString UTF8String]);
944             }
945         }
946         config_PutPsz(p_intf, "http-password", [[o_intf_luahttppwd_fld stringValue] UTF8String]);
947
948         SaveIntList(o_intf_pauseitunes_pop, "macosx-control-itunes");
949
950         /* activate stuff without restart */
951         if ([o_intf_appleremote_ckb state] == YES)
952             [[[VLCMain sharedInstance] appleRemoteController] startListening: [VLCMain sharedInstance]];
953         else
954             [[[VLCMain sharedInstance] appleRemoteController] stopListening: [VLCMain sharedInstance]];
955         b_intfSettingChanged = NO;
956     }
957
958     /******************
959      * audio settings *
960      ******************/
961     if (b_audioSettingChanged) {
962         config_PutInt(p_intf, "audio", [o_audio_enable_ckb state]);
963         config_PutInt(p_intf, "volume-save", [o_audio_autosavevol_yes_bcell state]);
964         var_SetBool(p_intf, "volume-save", [o_audio_autosavevol_yes_bcell state]);
965         config_PutInt(p_intf, "spdif", [o_audio_spdif_ckb state]);
966         if ([o_audio_vol_fld isEnabled])
967             config_PutInt(p_intf, "auhal-volume", ([o_audio_vol_fld intValue] * AOUT_VOLUME_MAX) / 200);
968
969         SaveIntList(o_audio_dolby_pop, "force-dolby-surround");
970
971         config_PutPsz(p_intf, "audio-language", [[o_audio_lang_fld stringValue] UTF8String]);
972
973         SaveModuleList(o_audio_visual_pop, "audio-visual");
974
975         /* Last.FM is optional */
976         if (module_exists("audioscrobbler")) {
977             [o_audio_last_ckb setEnabled: YES];
978             if ([o_audio_last_ckb state] == NSOnState)
979                 config_AddIntf(p_intf, "audioscrobbler");
980             else
981                 config_RemoveIntf(p_intf, "audioscrobbler");
982
983             config_PutPsz(p_intf, "lastfm-username", [[o_audio_lastuser_fld stringValue] UTF8String]);
984             config_PutPsz(p_intf, "lastfm-password", [[o_audio_lastpwd_sfld stringValue] UTF8String]);
985         }
986         else
987             [o_audio_last_ckb setEnabled: NO];
988         b_audioSettingChanged = NO;
989     }
990
991     /******************
992      * video settings *
993      ******************/
994     if (b_videoSettingChanged) {
995         config_PutInt(p_intf, "video", [o_video_enable_ckb state]);
996         config_PutInt(p_intf, "fullscreen", [o_video_fullscreen_ckb state]);
997         config_PutInt(p_intf, "video-deco", [o_video_videodeco_ckb state]);
998         config_PutInt(p_intf, "video-on-top", [o_video_onTop_ckb state]);
999         config_PutInt(p_intf, "skip-frames", [o_video_skipFrames_ckb state]);
1000         config_PutInt(p_intf, "macosx-black", [o_video_black_ckb state]);
1001
1002         SaveModuleList(o_video_output_pop, "vout");
1003         config_PutInt(p_intf, "macosx-vdev", [[o_video_device_pop selectedItem] tag]);
1004
1005         config_PutPsz(p_intf, "snapshot-path", [[o_video_snap_folder_fld stringValue] UTF8String]);
1006         config_PutPsz(p_intf, "snapshot-prefix", [[o_video_snap_prefix_fld stringValue] UTF8String]);
1007         config_PutInt(p_intf, "snapshot-sequential", [o_video_snap_seqnum_ckb state]);
1008         SaveStringList(o_video_snap_format_pop, "snapshot-format");
1009         SaveIntList(o_video_deinterlace_pop, "deinterlace");
1010         SaveStringList(o_video_deinterlace_mode_pop, "deinterlace-mode");
1011         b_videoSettingChanged = NO;
1012     }
1013
1014     /***************************
1015      * input & codecs settings *
1016      ***************************/
1017     if (b_inputSettingChanged) {
1018         config_PutPsz(p_intf, "input-record-path", [[o_input_record_fld stringValue] UTF8String]);
1019         config_PutInt(p_intf, "postproc-q", [o_input_postproc_fld intValue]);
1020
1021         SaveIntList(o_input_avi_pop, "avi-index");
1022
1023         config_PutInt(p_intf, "rtsp-tcp", [o_input_rtsp_ckb state]);
1024         SaveModuleList(o_input_avcodec_hw_pop, "avcodec-hw");
1025         SaveIntList(o_input_skipLoop_pop, "avcodec-skiploopfilter");
1026
1027         config_PutInt(p_intf, "mkv-preload-local-dir", [o_input_mkv_preload_dir_ckb state]);
1028
1029         #define CaC(name, factor) config_PutInt(p_intf, name, [[o_input_cachelevel_pop selectedItem] tag] * factor)
1030         if ([[o_input_cachelevel_pop selectedItem] tag] == 0) {
1031             msg_Dbg(p_intf, "Custom chosen, not adjusting cache values");
1032         } else {
1033             msg_Dbg(p_intf, "Adjusting all cache values to: %i", (int)[[o_input_cachelevel_pop selectedItem] tag]);
1034             CaC("file-caching", 1);
1035             CaC("network-caching", 10/3);
1036             CaC("disc-caching", 1);
1037             CaC("live-caching", 1);
1038         }
1039         #undef CaC
1040         b_inputSettingChanged = NO;
1041     }
1042
1043     /**********************
1044      * subtitles settings *
1045      **********************/
1046     if (b_osdSettingChanged) {
1047         config_PutInt(p_intf, "osd", [o_osd_osd_ckb state]);
1048
1049         if ([o_osd_encoding_pop indexOfSelectedItem] >= 0)
1050             SaveStringList(o_osd_encoding_pop, "subsdec-encoding");
1051         else
1052             config_PutPsz(p_intf, "subsdec-encoding", "");
1053
1054         config_PutPsz(p_intf, "sub-language", [[o_osd_lang_fld stringValue] UTF8String]);
1055
1056         config_PutPsz(p_intf, "freetype-font", [[o_osd_font_fld stringValue] UTF8String]);
1057         SaveIntList(o_osd_font_color_pop, "freetype-color");
1058         SaveIntList(o_osd_font_size_pop, "freetype-rel-fontsize");
1059         config_PutInt(p_intf, "freetype-opacity", [o_osd_opacity_fld intValue] * 255.0 / 100.0 + 0.5);
1060         config_PutInt(p_intf, "freetype-bold", [o_osd_forcebold_ckb state]);
1061         SaveIntList(o_osd_outline_color_pop, "freetype-outline-color");
1062         SaveIntList(o_osd_outline_thickness_pop, "freetype-outline-thickness");
1063         b_osdSettingChanged = NO;
1064     }
1065
1066     /********************
1067      * hotkeys settings *
1068      ********************/
1069     if (b_hotkeyChanged) {
1070         NSUInteger hotKeyCount = [o_hotkeySettings count];
1071         for (NSUInteger i = 0; i < hotKeyCount; i++)
1072             config_PutPsz(p_intf, [[o_hotkeyNames objectAtIndex:i] UTF8String], [[o_hotkeySettings objectAtIndex:i]UTF8String]);
1073         b_hotkeyChanged = NO;
1074     }
1075
1076     [[VLCCoreInteraction sharedInstance] fixPreferences];
1077
1078     /* okay, let's save our changes to vlcrc */
1079     config_SaveConfigFile(p_intf);
1080
1081     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCMediaKeySupportSettingChanged"
1082                                                             object: nil
1083                                                           userInfo: nil];
1084 }
1085
1086 - (void)showSettingsForCategory: (id)o_new_category_view
1087 {
1088     NSRect o_win_rect, o_view_rect, o_old_view_rect;
1089     o_win_rect = [o_sprefs_win frame];
1090     o_view_rect = [o_new_category_view frame];
1091
1092     if (o_currentlyShownCategoryView != nil) {
1093         /* restore our window's height, if we've shown another category previously */
1094         o_old_view_rect = [o_currentlyShownCategoryView frame];
1095         o_win_rect.size.height = o_win_rect.size.height - o_old_view_rect.size.height;
1096         o_win_rect.origin.y = (o_win_rect.origin.y + o_old_view_rect.size.height) - o_view_rect.size.height;
1097     }
1098
1099     o_win_rect.size.height = o_win_rect.size.height + o_view_rect.size.height;
1100
1101     [o_new_category_view setFrame: NSMakeRect(0,
1102                                                [o_sprefs_controls_box frame].size.height,
1103                                                o_view_rect.size.width,
1104                                                o_view_rect.size.height)];
1105     [o_new_category_view setAutoresizesSubviews: YES];
1106     if (o_currentlyShownCategoryView) {
1107         [[[o_sprefs_win contentView] animator] replaceSubview: o_currentlyShownCategoryView with: o_new_category_view];
1108         [o_currentlyShownCategoryView release];
1109         [[o_sprefs_win animator] setFrame: o_win_rect display:YES];
1110     } else {
1111         [[o_sprefs_win contentView] addSubview: o_new_category_view];
1112         [o_sprefs_win setFrame: o_win_rect display:YES animate:NO];
1113     }
1114
1115     /* keep our current category for further reference */
1116     o_currentlyShownCategoryView = o_new_category_view;
1117     [o_currentlyShownCategoryView retain];
1118 }
1119
1120 #pragma mark -
1121 #pragma mark Specific actions
1122
1123 // disables some video settings which do not work in lion mode
1124 - (void)enableLionFullscreenMode: (BOOL)b_value
1125 {
1126     [o_video_videodeco_ckb setEnabled: !b_value];
1127     [o_video_black_ckb setEnabled: !b_value];
1128
1129     if (b_value) {
1130         [o_video_videodeco_ckb setState: NSOnState];
1131         [o_video_black_ckb setState: NSOffState];
1132
1133         NSString *o_tooltipText = _NS("This setting cannot be changed because the native fullscreen mode is enabled.");
1134         [o_video_videodeco_ckb setToolTip: o_tooltipText];
1135         [o_video_black_ckb setToolTip: o_tooltipText];
1136     } else {
1137         [self setupButton: o_video_videodeco_ckb forBoolValue: "video-deco"];
1138         [self setupButton: o_video_black_ckb forBoolValue: "macosx-black"];
1139     }
1140 }
1141
1142 - (IBAction)interfaceSettingChanged:(id)sender
1143 {
1144     if (sender == o_intf_nativefullscreen_ckb)
1145         [self enableLionFullscreenMode:[sender state]];
1146
1147     b_intfSettingChanged = YES;
1148 }
1149
1150 - (void)showInterfaceSettings
1151 {
1152     [self showSettingsForCategory: o_intf_view];
1153 }
1154
1155 - (IBAction)audioSettingChanged:(id)sender
1156 {
1157     if (sender == o_audio_vol_sld)
1158         [o_audio_vol_fld setIntValue: [o_audio_vol_sld intValue]];
1159
1160     if (sender == o_audio_vol_fld)
1161         [o_audio_vol_sld setIntValue: [o_audio_vol_fld intValue]];
1162
1163     if (sender == o_audio_last_ckb) {
1164         if ([o_audio_last_ckb state] == NSOnState) {
1165             [o_audio_lastpwd_sfld setEnabled: YES];
1166             [o_audio_lastuser_fld setEnabled: YES];
1167         } else {
1168             [o_audio_lastpwd_sfld setEnabled: NO];
1169             [o_audio_lastuser_fld setEnabled: NO];
1170         }
1171     }
1172
1173     if (sender == o_audio_autosavevol_matrix) {
1174         BOOL enableVolumeSlider = [o_audio_autosavevol_matrix selectedTag] == 1;
1175         [o_audio_vol_fld setEnabled: enableVolumeSlider];
1176         [o_audio_vol_sld setEnabled: enableVolumeSlider];
1177     }
1178
1179     b_audioSettingChanged = YES;
1180 }
1181
1182 - (void)showAudioSettings
1183 {
1184     [self showSettingsForCategory: o_audio_view];
1185 }
1186
1187 - (IBAction)videoSettingChanged:(id)sender
1188 {
1189     if (sender == o_video_snap_folder_btn) {
1190         o_selectFolderPanel = [[NSOpenPanel alloc] init];
1191         [o_selectFolderPanel setCanChooseDirectories: YES];
1192         [o_selectFolderPanel setCanChooseFiles: NO];
1193         [o_selectFolderPanel setResolvesAliases: YES];
1194         [o_selectFolderPanel setAllowsMultipleSelection: NO];
1195         [o_selectFolderPanel setMessage: _NS("Choose the folder to save your video snapshots to.")];
1196         [o_selectFolderPanel setCanCreateDirectories: YES];
1197         [o_selectFolderPanel setPrompt: _NS("Choose")];
1198         [o_selectFolderPanel beginSheetModalForWindow: o_sprefs_win completionHandler: ^(NSInteger returnCode) {
1199             if (returnCode == NSOKButton)
1200             {
1201                 [o_video_snap_folder_fld setStringValue: [[o_selectFolderPanel URL] path]];
1202                 b_videoSettingChanged = YES;
1203             }
1204         }];
1205         [o_selectFolderPanel release];
1206     } else
1207         b_videoSettingChanged = YES;
1208 }
1209
1210 - (void)showVideoSettings
1211 {
1212     [self showSettingsForCategory: o_video_view];
1213 }
1214
1215 - (IBAction)osdSettingChanged:(id)sender
1216 {
1217     if (sender == o_osd_opacity_fld)
1218         [o_osd_opacity_sld setIntValue: [o_osd_opacity_fld intValue]];
1219
1220     if (sender == o_osd_opacity_sld)
1221         [o_osd_opacity_fld setIntValue: [o_osd_opacity_sld intValue]];
1222
1223     b_osdSettingChanged = YES;
1224 }
1225
1226 - (void)showOSDSettings
1227 {
1228     [self showSettingsForCategory: o_osd_view];
1229 }
1230
1231 - (void)controlTextDidChange:(NSNotification *)o_notification
1232 {
1233     id notificationObject = [o_notification object];
1234     if (notificationObject == o_audio_lang_fld ||
1235        notificationObject ==  o_audio_lastpwd_sfld ||
1236        notificationObject ==  o_audio_lastuser_fld ||
1237        notificationObject == o_audio_vol_fld)
1238         b_audioSettingChanged = YES;
1239     else if (notificationObject == o_input_record_fld ||
1240             notificationObject == o_input_postproc_fld)
1241         b_inputSettingChanged = YES;
1242     else if (notificationObject == o_osd_font_fld ||
1243             notificationObject == o_osd_lang_fld ||
1244             notificationObject == o_osd_opacity_fld)
1245         b_osdSettingChanged = YES;
1246     else if (notificationObject == o_video_snap_folder_fld ||
1247             notificationObject == o_video_snap_prefix_fld)
1248         b_videoSettingChanged = YES;
1249     else if (notificationObject == o_intf_luahttppwd_fld)
1250         b_intfSettingChanged = YES;
1251 }
1252
1253 - (IBAction)showFontPicker:(id)sender
1254 {
1255     char * font = config_GetPsz(p_intf, "freetype-font");
1256     NSString * fontName = font ? [NSString stringWithUTF8String:font] : nil;
1257     free(font);
1258     if (fontName) {
1259         NSFont * font = [NSFont fontWithName:fontName size:0.0];
1260         [[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:NO];
1261     }
1262     [[NSFontManager sharedFontManager] setTarget: self];
1263     [[NSFontPanel sharedFontPanel] orderFront:self];
1264 }
1265
1266 - (void)changeFont:(id)sender
1267 {
1268     NSFont * font = [sender convertFont:[[NSFontManager sharedFontManager] selectedFont]];
1269     [o_osd_font_fld setStringValue:[font fontName]];
1270     [self osdSettingChanged:self];
1271 }
1272
1273 - (IBAction)inputSettingChanged:(id)sender
1274 {
1275     if (sender == o_input_cachelevel_pop) {
1276         if ([[[o_input_cachelevel_pop selectedItem] title] isEqualToString: _NS("Custom")])
1277             [o_input_cachelevel_custom_txt setHidden: NO];
1278         else
1279             [o_input_cachelevel_custom_txt setHidden: YES];
1280     } else if (sender == o_input_record_btn) {
1281         o_selectFolderPanel = [[NSOpenPanel alloc] init];
1282         [o_selectFolderPanel setCanChooseDirectories: YES];
1283         [o_selectFolderPanel setCanChooseFiles: YES];
1284         [o_selectFolderPanel setResolvesAliases: YES];
1285         [o_selectFolderPanel setAllowsMultipleSelection: NO];
1286         [o_selectFolderPanel setMessage: _NS("Choose the directory or filename where the records will be stored.")];
1287         [o_selectFolderPanel setCanCreateDirectories: YES];
1288         [o_selectFolderPanel setPrompt: _NS("Choose")];
1289         [o_selectFolderPanel beginSheetModalForWindow: o_sprefs_win completionHandler: ^(NSInteger returnCode) {
1290             if (returnCode == NSOKButton)
1291             {
1292                 [o_input_record_fld setStringValue: [[o_selectFolderPanel URL] path]];
1293                 b_inputSettingChanged = YES;
1294             }
1295         }];
1296         [o_selectFolderPanel release];
1297
1298         return;
1299     }
1300
1301     b_inputSettingChanged = YES;
1302 }
1303
1304 - (void)showInputSettings
1305 {
1306     [self showSettingsForCategory: o_input_view];
1307 }
1308
1309 - (NSString *)bundleIdentifierForApplicationName:(NSString *)appName
1310 {
1311     NSWorkspace * workspace = [NSWorkspace sharedWorkspace];
1312     NSString * appPath = [workspace fullPathForApplication:appName];
1313     if (appPath) {
1314         NSBundle * appBundle = [NSBundle bundleWithPath:appPath];
1315         return [appBundle bundleIdentifier];
1316     }
1317     return nil;
1318 }
1319
1320 - (NSString *)applicationNameForBundleIdentifier:(NSString *)bundleIdentifier
1321 {
1322     return [[[NSFileManager defaultManager] displayNameAtPath:[[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:bundleIdentifier]] stringByDeletingPathExtension];
1323 }
1324
1325 - (NSImage *)iconForBundleIdentifier:(NSString *)bundleIdentifier
1326 {
1327     NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
1328     NSSize iconSize = NSMakeSize(16., 16.);
1329     NSImage *icon = [workspace iconForFile:[workspace absolutePathForAppBundleWithIdentifier:bundleIdentifier]];
1330     [icon setSize:iconSize];
1331     return icon;
1332 }
1333
1334 - (IBAction)urlHandlerAction:(id)sender
1335 {
1336     NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
1337
1338     if (sender == o_input_urlhandler_btn) {
1339         NSArray *handlers;
1340         NSString *handler;
1341         NSString *rawhandler;
1342         NSMutableArray *rawHandlers;
1343         NSUInteger count;
1344
1345 #define fillUrlHandlerPopup( protocol, object ) \
1346         handlers = (NSArray *)LSCopyAllHandlersForURLScheme(CFSTR( protocol )); \
1347         rawHandlers = [[NSMutableArray alloc] init]; \
1348         [object removeAllItems]; \
1349         count = [handlers count]; \
1350         for (NSUInteger x = 0; x < count; x++) { \
1351             rawhandler = [handlers objectAtIndex:x]; \
1352             handler = [self applicationNameForBundleIdentifier:rawhandler]; \
1353             if (handler && ![handler isEqualToString:@""]) { \
1354                 [object addItemWithTitle:handler]; \
1355                 [[object lastItem] setImage: [self iconForBundleIdentifier:[handlers objectAtIndex:x]]]; \
1356                 [rawHandlers addObject: rawhandler]; \
1357             } \
1358         } \
1359         [object selectItemAtIndex: [rawHandlers indexOfObject:(id)LSCopyDefaultHandlerForURLScheme(CFSTR( protocol ))]]; \
1360         [rawHandlers release]
1361
1362         fillUrlHandlerPopup( "ftp", o_urlhandler_ftp_pop);
1363         fillUrlHandlerPopup( "mms", o_urlhandler_mms_pop);
1364         fillUrlHandlerPopup( "rtmp", o_urlhandler_rtmp_pop);
1365         fillUrlHandlerPopup( "rtp", o_urlhandler_rtp_pop);
1366         fillUrlHandlerPopup( "rtsp", o_urlhandler_rtsp_pop);
1367         fillUrlHandlerPopup( "sftp", o_urlhandler_sftp_pop);
1368         fillUrlHandlerPopup( "smb", o_urlhandler_smb_pop);
1369         fillUrlHandlerPopup( "udp", o_urlhandler_udp_pop);
1370
1371 #undef fillUrlHandlerPopup
1372
1373         [NSApp beginSheet:o_urlhandler_win modalForWindow:o_sprefs_win modalDelegate:self didEndSelector:NULL contextInfo:nil];
1374     } else {
1375         [o_urlhandler_win orderOut:sender];
1376         [NSApp endSheet: o_urlhandler_win];
1377
1378         if (sender == o_urlhandler_save_btn) {
1379             LSSetDefaultHandlerForURLScheme(CFSTR("ftp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_ftp_pop selectedItem] title]]);
1380             LSSetDefaultHandlerForURLScheme(CFSTR("mms"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_mms_pop selectedItem] title]]);
1381             LSSetDefaultHandlerForURLScheme(CFSTR("mmsh"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_mms_pop selectedItem] title]]);
1382             LSSetDefaultHandlerForURLScheme(CFSTR("rtmp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_rtmp_pop selectedItem] title]]);
1383             LSSetDefaultHandlerForURLScheme(CFSTR("rtp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_rtp_pop selectedItem] title]]);
1384             LSSetDefaultHandlerForURLScheme(CFSTR("rtsp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_rtsp_pop selectedItem] title]]);
1385             LSSetDefaultHandlerForURLScheme(CFSTR("sftp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_sftp_pop selectedItem] title]]);
1386             LSSetDefaultHandlerForURLScheme(CFSTR("smb"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_smb_pop selectedItem] title]]);
1387             LSSetDefaultHandlerForURLScheme(CFSTR("udp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_udp_pop selectedItem] title]]);
1388         }
1389     }
1390 }
1391
1392 #pragma mark -
1393 #pragma mark Hotkey actions
1394
1395 - (void)hotkeyTableDoubleClick:(id)object
1396 {
1397     // -1 is header
1398     if ([o_hotkeys_listbox clickedRow] >= 0)
1399         [self hotkeySettingChanged:o_hotkeys_listbox];
1400 }
1401
1402 - (IBAction)hotkeySettingChanged:(id)sender
1403 {
1404     if (sender == o_hotkeys_change_btn || sender == o_hotkeys_listbox) {
1405         [o_hotkeys_change_lbl setStringValue: [NSString stringWithFormat: _NS("Press new keys for\n\"%@\""),
1406                                                [o_hotkeyDescriptions objectAtIndex:[o_hotkeys_listbox selectedRow]]]];
1407         [o_hotkeys_change_keys_lbl setStringValue: [[VLCStringUtility sharedInstance] OSXStringKeyToString:[o_hotkeySettings objectAtIndex:[o_hotkeys_listbox selectedRow]]]];
1408         [o_hotkeys_change_taken_lbl setStringValue: @""];
1409         [o_hotkeys_change_win setInitialFirstResponder: [o_hotkeys_change_win contentView]];
1410         [o_hotkeys_change_win makeFirstResponder: [o_hotkeys_change_win contentView]];
1411         [NSApp runModalForWindow: o_hotkeys_change_win];
1412     } else if (sender == o_hotkeys_change_cancel_btn) {
1413         [NSApp stopModal];
1414         [o_hotkeys_change_win close];
1415     } else if (sender == o_hotkeys_change_ok_btn) {
1416         NSInteger i_returnValue;
1417         if (! o_keyInTransition) {
1418             [NSApp stopModal];
1419             [o_hotkeys_change_win close];
1420             msg_Err(p_intf, "internal error prevented the hotkey switch");
1421             return;
1422         }
1423
1424         b_hotkeyChanged = YES;
1425
1426         i_returnValue = [o_hotkeySettings indexOfObject: o_keyInTransition];
1427         if (i_returnValue != NSNotFound)
1428             [o_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]];
1429         NSString *tempString;
1430         tempString = [o_keyInTransition stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
1431         i_returnValue = [o_hotkeySettings indexOfObject: tempString];
1432         if (i_returnValue != NSNotFound)
1433             [o_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]];
1434
1435         [o_hotkeySettings replaceObjectAtIndex: [o_hotkeys_listbox selectedRow] withObject: [o_keyInTransition retain]];
1436
1437         [NSApp stopModal];
1438         [o_hotkeys_change_win close];
1439
1440         [o_hotkeys_listbox reloadData];
1441     } else if (sender == o_hotkeys_clear_btn) {
1442         [o_hotkeySettings replaceObjectAtIndex: [o_hotkeys_listbox selectedRow] withObject: [NSString string]];
1443         [o_hotkeys_listbox reloadData];
1444         b_hotkeyChanged = YES;
1445     }
1446
1447     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCMediaKeySupportSettingChanged"
1448                                                         object: nil
1449                                                       userInfo: nil];
1450 }
1451
1452 - (void)showHotkeySettings
1453 {
1454     [self showSettingsForCategory: o_hotkeys_view];
1455 }
1456
1457 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
1458 {
1459     return [o_hotkeySettings count];
1460 }
1461
1462 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
1463 {
1464     NSString * identifier = [aTableColumn identifier];
1465
1466     if ([identifier isEqualToString: @"action"])
1467         return [o_hotkeyDescriptions objectAtIndex:rowIndex];
1468     else if ([identifier isEqualToString: @"shortcut"])
1469         return [[VLCStringUtility sharedInstance] OSXStringKeyToString:[o_hotkeySettings objectAtIndex:rowIndex]];
1470     else {
1471         msg_Err(p_intf, "unknown TableColumn identifier (%s)!", [identifier UTF8String]);
1472         return NULL;
1473     }
1474 }
1475
1476 - (BOOL)changeHotkeyTo: (NSString *)theKey
1477 {
1478     NSInteger i_returnValue, i_returnValue2;
1479     i_returnValue = [o_hotkeysNonUseableKeys indexOfObject: theKey];
1480
1481     if (i_returnValue != NSNotFound || [theKey isEqualToString:@""]) {
1482         [o_hotkeys_change_keys_lbl setStringValue: _NS("Invalid combination")];
1483         [o_hotkeys_change_taken_lbl setStringValue: _NS("Regrettably, these keys cannot be assigned as hotkey shortcuts.")];
1484         [o_hotkeys_change_ok_btn setEnabled: NO];
1485         return NO;
1486     } else {
1487         [o_hotkeys_change_keys_lbl setStringValue: [[VLCStringUtility sharedInstance] OSXStringKeyToString:theKey]];
1488
1489         i_returnValue = [o_hotkeySettings indexOfObject: theKey];
1490         i_returnValue2 = [o_hotkeySettings indexOfObject: [theKey stringByReplacingOccurrencesOfString:@"-" withString:@"+"]];
1491         if (i_returnValue != NSNotFound)
1492             [o_hotkeys_change_taken_lbl setStringValue: [NSString stringWithFormat:
1493                                                          _NS("This combination is already taken by \"%@\"."),
1494                                                          [o_hotkeyDescriptions objectAtIndex:i_returnValue]]];
1495         else if (i_returnValue2 != NSNotFound)
1496             [o_hotkeys_change_taken_lbl setStringValue: [NSString stringWithFormat:
1497                                                          _NS("This combination is already taken by \"%@\"."),
1498                                                          [o_hotkeyDescriptions objectAtIndex:i_returnValue2]]];
1499         else
1500             [o_hotkeys_change_taken_lbl setStringValue: @""];
1501
1502         [o_hotkeys_change_ok_btn setEnabled: YES];
1503         [o_keyInTransition release];
1504         o_keyInTransition = theKey;
1505         [o_keyInTransition retain];
1506         return YES;
1507     }
1508 }
1509
1510 @end
1511
1512 /********************
1513  * hotkeys settings *
1514  ********************/
1515
1516 @implementation VLCHotkeyChangeWindow
1517
1518 - (BOOL)acceptsFirstResponder
1519 {
1520     return YES;
1521 }
1522
1523 - (BOOL)becomeFirstResponder
1524 {
1525     return YES;
1526 }
1527
1528 - (BOOL)resignFirstResponder
1529 {
1530     /* We need to stay the first responder or we'll miss the user's input */
1531     return NO;
1532 }
1533
1534 - (BOOL)performKeyEquivalent:(NSEvent *)o_theEvent
1535 {
1536     NSMutableString *tempString = [[[NSMutableString alloc] init] autorelease];
1537     NSString *keyString = [o_theEvent characters];
1538
1539     unichar key = [keyString characterAtIndex:0];
1540     NSUInteger i_modifiers = [o_theEvent modifierFlags];
1541
1542     /* modifiers */
1543     if (i_modifiers & NSControlKeyMask)
1544         [tempString appendString:@"Ctrl-"];
1545     if (i_modifiers & NSAlternateKeyMask )
1546         [tempString appendString:@"Alt-"];
1547     if (i_modifiers & NSShiftKeyMask)
1548         [tempString appendString:@"Shift-"];
1549     if (i_modifiers & NSCommandKeyMask)
1550         [tempString appendString:@"Command-"];
1551
1552     /* non character keys */
1553     if (key == NSUpArrowFunctionKey)
1554         [tempString appendString:@"Up"];
1555     else if (key == NSDownArrowFunctionKey)
1556         [tempString appendString:@"Down"];
1557     else if (key == NSLeftArrowFunctionKey)
1558         [tempString appendString:@"Left"];
1559     else if (key == NSRightArrowFunctionKey)
1560         [tempString appendString:@"Right"];
1561     else if (key == NSF1FunctionKey)
1562         [tempString appendString:@"F1"];
1563     else if (key == NSF2FunctionKey)
1564         [tempString appendString:@"F2"];
1565     else if (key == NSF3FunctionKey)
1566         [tempString appendString:@"F3"];
1567     else if (key == NSF4FunctionKey)
1568         [tempString appendString:@"F4"];
1569     else if (key == NSF5FunctionKey)
1570         [tempString appendString:@"F5"];
1571     else if (key == NSF6FunctionKey)
1572         [tempString appendString:@"F6"];
1573     else if (key == NSF7FunctionKey)
1574         [tempString appendString:@"F7"];
1575     else if (key == NSF8FunctionKey)
1576         [tempString appendString:@"F8"];
1577     else if (key == NSF9FunctionKey)
1578         [tempString appendString:@"F9"];
1579     else if (key == NSF10FunctionKey)
1580         [tempString appendString:@"F10"];
1581     else if (key == NSF11FunctionKey)
1582         [tempString appendString:@"F11"];
1583     else if (key == NSF12FunctionKey)
1584         [tempString appendString:@"F12"];
1585     else if (key == NSInsertFunctionKey)
1586         [tempString appendString:@"Insert"];
1587     else if (key == NSHomeFunctionKey)
1588         [tempString appendString:@"Home"];
1589     else if (key == NSEndFunctionKey)
1590         [tempString appendString:@"End"];
1591     else if (key == NSPageUpFunctionKey)
1592         [tempString appendString:@"Pageup"];
1593     else if (key == NSPageDownFunctionKey)
1594         [tempString appendString:@"Pagedown"];
1595     else if (key == NSMenuFunctionKey)
1596         [tempString appendString:@"Menu"];
1597     else if (key == NSTabCharacter)
1598         [tempString appendString:@"Tab"];
1599     else if (key == NSCarriageReturnCharacter)
1600         [tempString appendString:@"Enter"];
1601     else if (key == NSEnterCharacter)
1602         [tempString appendString:@"Enter"];
1603     else if (key == NSDeleteCharacter)
1604         [tempString appendString:@"Delete"];
1605     else if (key == NSBackspaceCharacter)
1606         [tempString appendString:@"Backspace"];
1607     else if (key == 0x001B)
1608         [tempString appendString:@"Esc"];
1609     else if (key == ' ')
1610         [tempString appendString:@"Space"];
1611     else if (![[[o_theEvent charactersIgnoringModifiers] lowercaseString] isEqualToString:@""]) //plain characters
1612         [tempString appendString:[[o_theEvent charactersIgnoringModifiers] lowercaseString]];
1613     else
1614         return NO;
1615
1616     return [[[VLCMain sharedInstance] simplePreferences] changeHotkeyTo: tempString];
1617 }
1618
1619 @end
1620
1621 @implementation VLCSimplePrefsWindow
1622
1623 - (BOOL)acceptsFirstResponder
1624 {
1625     return YES;
1626 }
1627
1628 - (void)changeFont:(id)sender
1629 {
1630     [[[VLCMain sharedInstance] simplePreferences] changeFont: sender];
1631 }
1632 @end