]> git.sesse.net Git - vlc/blob - modules/gui/macosx/simple_prefs.m
macosx: Fix drawing issues with podcast controls and dropzone
[vlc] / modules / gui / macosx / simple_prefs.m
1 /*****************************************************************************
2 * simple_prefs.m: Simple Preferences for Mac OS X
3 *****************************************************************************
4 * Copyright (C) 2008-2014 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-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("Audio 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_embedded_ckb setTitle: _NS("Show video within the main window")];
360     [o_intf_nativefullscreen_ckb setTitle: _NS("Use the native fullscreen mode")];
361     [o_intf_fspanel_ckb setTitle: _NS("Show Fullscreen Controller")];
362     [o_intf_network_box setTitle: _NS("Privacy / Network Interaction")];
363     [o_intf_appleremote_ckb setTitle: _NS("Control playback with the Apple Remote")];
364     [o_intf_appleremote_sysvol_ckb setTitle: _NS("Control system volume with the Apple Remote")];
365     [o_intf_mediakeys_ckb setTitle: _NS("Control playback with media keys")];
366     [o_intf_art_ckb setTitle: _NS("Allow metadata network access")];
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("Control external music players")];
375     [o_intf_continueplayback_lbl setStringValue:_NS("Continue playback")];
376
377     /* Subtitles and OSD */
378     [o_osd_encoding_txt setStringValue: _NS("Default Encoding")];
379     [o_osd_font_box setTitle: _NS("Display Settings")];
380     [o_osd_font_btn setTitle: _NS("Choose...")];
381     [o_osd_font_color_txt setStringValue: _NS("Font color")];
382     [o_osd_font_size_txt setStringValue: _NS("Font size")];
383     [o_osd_font_txt setStringValue: _NS("Font")];
384     [o_osd_lang_box setTitle: _NS("Subtitle languages")];
385     [o_osd_lang_txt setStringValue: _NS("Preferred subtitle language")];
386     [o_osd_osd_box setTitle: _NS("On Screen Display")];
387     [o_osd_osd_ckb setTitle: _NS("Enable OSD")];
388     [o_osd_opacity_txt setStringValue: _NS("Opacity")];
389     [o_osd_forcebold_ckb setTitle: _NS("Force bold")];
390     [o_osd_outline_color_txt setStringValue: _NS("Outline color")];
391     [o_osd_outline_thickness_txt setStringValue: _NS("Outline thickness")];
392
393     /* video */
394     [o_video_black_ckb setTitle: _NS("Black screens in Fullscreen mode")];
395     [o_video_device_txt setStringValue: _NS("Fullscreen Video Device")];
396     [o_video_display_box setTitle: _NS("Display")];
397     [o_video_enable_ckb setTitle: _NS("Enable video")];
398     [o_video_fullscreen_ckb setTitle: _NS("Fullscreen")];
399     [o_video_videodeco_ckb setTitle: _NS("Window decorations")];
400     [o_video_onTop_ckb setTitle: _NS("Float on Top")];
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_ckb forBoolValue: "metadata-network-access"];
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     [self setupButton: o_intf_continueplayback_pop forIntList: "macosx-continue-playback"];
602
603     /******************
604      * audio settings *
605      ******************/
606     [self setupButton: o_audio_enable_ckb forBoolValue: "audio"];
607
608     if (config_GetInt(p_intf, "volume-save")) {
609         [o_audio_autosavevol_yes_bcell setState: NSOnState];
610         [o_audio_autosavevol_no_bcell setState: NSOffState];
611         [o_audio_vol_fld setEnabled: NO];
612         [o_audio_vol_sld setEnabled: NO];
613
614         [o_audio_vol_sld setIntValue: 100];
615         [o_audio_vol_fld setIntValue: 100];
616     } else {
617         [o_audio_autosavevol_yes_bcell setState: NSOffState];
618         [o_audio_autosavevol_no_bcell setState: NSOnState];
619         [o_audio_vol_fld setEnabled: YES];
620         [o_audio_vol_sld setEnabled: YES];
621
622         i = var_InheritInteger(p_intf, "auhal-volume");
623         i = i * 200. / AOUT_VOLUME_MAX;
624         [o_audio_vol_sld setIntValue: i];
625         [o_audio_vol_fld setIntValue: i];
626     }
627
628     [self setupButton: o_audio_spdif_ckb forBoolValue: "spdif"];
629
630     [self setupButton: o_audio_dolby_pop forIntList: "force-dolby-surround"];
631     [self setupField: o_audio_lang_fld forOption: "audio-language"];
632
633     [self setupButton: o_audio_visual_pop forModuleList: "audio-visual"];
634
635     /* Last.FM is optional */
636     if (module_exists("audioscrobbler")) {
637         [self setupField: o_audio_lastuser_fld forOption:"lastfm-username"];
638         [self setupField: o_audio_lastpwd_sfld forOption:"lastfm-password"];
639
640         if (config_ExistIntf(VLC_OBJECT(p_intf), "audioscrobbler")) {
641             [o_audio_last_ckb setState: NSOnState];
642             [o_audio_lastuser_fld setEnabled: YES];
643             [o_audio_lastpwd_sfld setEnabled: YES];
644         } else {
645             [o_audio_last_ckb setState: NSOffState];
646             [o_audio_lastuser_fld setEnabled: NO];
647             [o_audio_lastpwd_sfld setEnabled: NO];
648         }
649     } else
650         [o_audio_last_ckb setEnabled: NO];
651
652     /******************
653      * video settings *
654      ******************/
655     [self setupButton: o_video_enable_ckb forBoolValue: "video"];
656     [self setupButton: o_video_fullscreen_ckb forBoolValue: "fullscreen"];
657     [self setupButton: o_video_onTop_ckb forBoolValue: "video-on-top"];
658     [self setupButton: o_video_skipFrames_ckb forBoolValue: "skip-frames"];
659     [self setupButton: o_video_black_ckb forBoolValue: "macosx-black"];
660     [self setupButton: o_video_videodeco_ckb forBoolValue: "video-deco"];
661
662     [o_video_device_pop removeAllItems];
663     i = 0;
664     y = [[NSScreen screens] count];
665     [o_video_device_pop addItemWithTitle: _NS("Default")];
666     [[o_video_device_pop lastItem] setTag: 0];
667     while (i < y) {
668         NSRect s_rect = [[[NSScreen screens] objectAtIndex:i] frame];
669         [o_video_device_pop addItemWithTitle:
670          [NSString stringWithFormat: @"%@ %i (%ix%i)", _NS("Screen"), i+1,
671                    (int)s_rect.size.width, (int)s_rect.size.height]];
672         [[o_video_device_pop lastItem] setTag: (int)[[[NSScreen screens] objectAtIndex:i] displayID]];
673         i++;
674     }
675     [o_video_device_pop selectItemAtIndex: 0];
676     [o_video_device_pop selectItemWithTag: config_GetInt(p_intf, "macosx-vdev")];
677
678     [self setupField: o_video_snap_folder_fld forOption:"snapshot-path"];
679     [self setupField: o_video_snap_prefix_fld forOption:"snapshot-prefix"];
680     [self setupButton: o_video_snap_seqnum_ckb forBoolValue: "snapshot-sequential"];
681     [self setupButton: o_video_snap_format_pop forStringList: "snapshot-format"];
682     [self setupButton: o_video_deinterlace_pop forIntList: "deinterlace"];
683     [self setupButton: o_video_deinterlace_mode_pop forStringList: "deinterlace-mode"];
684
685     // set lion fullscreen mode restrictions
686     [self enableLionFullscreenMode: [o_intf_nativefullscreen_ckb state]];
687
688     /***************************
689      * input & codecs settings *
690      ***************************/
691     [self setupField: o_input_record_fld forOption:"input-record-path"];
692     [o_input_postproc_fld setIntValue: config_GetInt(p_intf, "postproc-q")];
693     [o_input_postproc_fld setToolTip: _NS(config_GetLabel(p_intf, "postproc-q"))];
694     [self setupButton: o_input_avcodec_hw_pop forModuleList: "avcodec-hw"];
695
696     [self setupButton: o_input_avi_pop forIntList: "avi-index"];
697
698     [self setupButton: o_input_rtsp_ckb forBoolValue: "rtsp-tcp"];
699     [self setupButton: o_input_skipLoop_pop forIntList: "avcodec-skiploopfilter"];
700
701     [self setupButton: o_input_mkv_preload_dir_ckb forBoolValue: "mkv-preload-local-dir"];
702
703     [o_input_cachelevel_pop removeAllItems];
704     [o_input_cachelevel_pop addItemsWithTitles: [NSArray arrayWithObjects:_NS("Custom"), _NS("Lowest latency"),
705      _NS("Low latency"), _NS("Normal"), _NS("High latency"), _NS("Higher latency"), nil]];
706     [[o_input_cachelevel_pop itemAtIndex: 0] setTag: 0];
707     [[o_input_cachelevel_pop itemAtIndex: 1] setTag: 100];
708     [[o_input_cachelevel_pop itemAtIndex: 2] setTag: 200];
709     [[o_input_cachelevel_pop itemAtIndex: 3] setTag: 300];
710     [[o_input_cachelevel_pop itemAtIndex: 4] setTag: 500];
711     [[o_input_cachelevel_pop itemAtIndex: 5] setTag: 1000];
712
713     #define TestCaC(name, factor) \
714     b_cache_equal =  b_cache_equal && \
715     (i_cache * factor == config_GetInt(p_intf, name));
716
717     /* Select the accurate value of the PopupButton */
718     bool b_cache_equal = true;
719     int i_cache = config_GetInt(p_intf, "file-caching");
720
721     TestCaC("network-caching", 10/3);
722     TestCaC("disc-caching", 1);
723     TestCaC("live-caching", 1);
724     if (b_cache_equal) {
725         [o_input_cachelevel_pop selectItemWithTag: i_cache];
726         [o_input_cachelevel_custom_txt setHidden: YES];
727     } else {
728         [o_input_cachelevel_pop selectItemWithTitle: _NS("Custom")];
729         [o_input_cachelevel_custom_txt setHidden: NO];
730     }
731     #undef TestCaC
732
733     /*********************
734      * subtitle settings *
735      *********************/
736     [self setupButton: o_osd_osd_ckb forBoolValue: "osd"];
737
738     [self setupButton: o_osd_encoding_pop forStringList: "subsdec-encoding"];
739     [self setupField: o_osd_lang_fld forOption: "sub-language" ];
740
741     [self setupField: o_osd_font_fld forOption: "freetype-font"];
742     [self setupButton: o_osd_font_color_pop forIntList: "freetype-color"];
743     [self setupButton: o_osd_font_size_pop forIntList: "freetype-rel-fontsize"];
744     i = config_GetInt(p_intf, "freetype-opacity") * 100.0 / 255.0 + 0.5;
745     [o_osd_opacity_fld setIntValue: i];
746     [o_osd_opacity_sld setIntValue: i];
747     [o_osd_opacity_sld setToolTip: _NS(config_GetLabel(p_intf, "freetype-opacity"))];
748     [o_osd_opacity_fld setToolTip: [o_osd_opacity_sld toolTip]];
749     [self setupButton: o_osd_forcebold_ckb forBoolValue: "freetype-bold"];
750     [self setupButton: o_osd_outline_color_pop forIntList: "freetype-outline-color"];
751     [self setupButton: o_osd_outline_thickness_pop forIntList: "freetype-outline-thickness"];
752
753     /********************
754      * hotkeys settings *
755      ********************/
756     const struct hotkey *p_hotkeys = p_intf->p_libvlc->p_hotkeys;
757     [o_hotkeySettings release];
758     o_hotkeySettings = [[NSMutableArray alloc] init];
759     NSMutableArray *o_tempArray_desc = [[NSMutableArray alloc] init];
760     NSMutableArray *o_tempArray_names = [[NSMutableArray alloc] init];
761
762     /* Get the main Module */
763     module_t *p_main = module_get_main();
764     assert(p_main);
765     unsigned confsize;
766     module_config_t *p_config;
767
768     p_config = module_config_get (p_main, &confsize);
769
770     for (size_t i = 0; i < confsize; i++) {
771         module_config_t *p_item = p_config + i;
772
773         if (CONFIG_ITEM(p_item->i_type) && p_item->psz_name != NULL
774            && !strncmp(p_item->psz_name , "key-", 4)
775            && !EMPTY_STR(p_item->psz_text)) {
776             [o_tempArray_desc addObject: _NS(p_item->psz_text)];
777             [o_tempArray_names addObject: [NSString stringWithUTF8String:p_item->psz_name]];
778             if (p_item->value.psz)
779                 [o_hotkeySettings addObject: [NSString stringWithUTF8String:p_item->value.psz]];
780             else
781                 [o_hotkeySettings addObject: [NSString string]];
782         }
783     }
784     module_config_free (p_config);
785
786     [o_hotkeyDescriptions release];
787     o_hotkeyDescriptions = [[NSArray alloc] initWithArray: o_tempArray_desc copyItems: YES];
788     [o_tempArray_desc release];
789     [o_hotkeyNames release];
790     o_hotkeyNames = [[NSArray alloc] initWithArray: o_tempArray_names copyItems: YES];
791     [o_tempArray_names release];
792     [o_hotkeys_listbox reloadData];
793 }
794
795 #pragma mark -
796 #pragma mark General actions
797
798 - (void)showSimplePrefs
799 {
800     /* we want to show the interface settings, if no category was chosen */
801     if ([[o_sprefs_win toolbar] selectedItemIdentifier] == nil) {
802         [[o_sprefs_win toolbar] setSelectedItemIdentifier: VLCIntfSettingToolbarIdentifier];
803         [self showInterfaceSettings];
804     }
805
806     [self resetControls];
807
808     [o_sprefs_win center];
809     [o_sprefs_win makeKeyAndOrderFront: self];
810 }
811
812 - (void)showSimplePrefsWithLevel:(NSInteger)i_window_level
813 {
814     [o_sprefs_win setLevel: i_window_level];
815     [self showSimplePrefs];
816 }
817
818 - (IBAction)buttonAction:(id)sender
819 {
820     if (sender == o_sprefs_cancel_btn) {
821         [[NSFontPanel sharedFontPanel] close];
822         [o_sprefs_win orderOut: sender];
823     } else if (sender == o_sprefs_save_btn) {
824         [self saveChangedSettings];
825         [[NSFontPanel sharedFontPanel] close];
826         [o_sprefs_win orderOut: sender];
827     } else if (sender == o_sprefs_showAll_btn) {
828         [o_sprefs_win orderOut: self];
829         [[[VLCMain sharedInstance] preferences] showPrefsWithLevel:[o_sprefs_win level]];
830     } else
831         msg_Warn(p_intf, "unknown buttonAction sender");
832 }
833
834 - (IBAction)resetPreferences:(NSControl *)sender
835 {
836     NSBeginInformationalAlertSheet(_NS("Reset Preferences"), _NS("Cancel"),
837                                    _NS("Continue"), nil, [sender window], self,
838                                    @selector(sheetDidEnd: returnCode: contextInfo:), NULL, nil, @"%@",
839                                    _NS("This will reset VLC media player's preferences.\n\n"
840                                        "Note that VLC will restart during the process, so your current "
841                                        "playlist will be emptied and eventual playback, streaming or "
842                                        "transcoding activities will stop immediately.\n\n"
843                                        "The Media Library will not be affected.\n\n"
844                                        "Are you sure you want to continue?"));
845 }
846
847 - (void)sheetDidEnd:(NSWindow *)o_sheet
848          returnCode:(int)i_return
849         contextInfo:(void *)o_context
850 {
851     if (i_return == NSAlertAlternateReturn) {
852         /* reset VLC's config */
853         config_ResetAll(p_intf);
854         [self resetControls];
855
856         /* force config file creation, since libvlc won't exit normally */
857         config_SaveConfigFile(p_intf);
858
859         /* reset OS X defaults */
860         [[VLCMain sharedInstance] resetAndReinitializeUserDefaults];
861
862         /* Relaunch now */
863         const char * path = [[[NSBundle mainBundle] executablePath] UTF8String];
864
865         /* For some reason we need to fork(), not just execl(), which reports a ENOTSUP then. */
866         if (fork() != 0) {
867             exit(0);
868             return;
869         }
870         execl(path, path, NULL);
871     }
872 }
873
874 static inline void save_int_list(intf_thread_t * p_intf, id object, const char * name)
875 {
876     NSNumber *p_valueobject = (NSNumber *)[[object selectedItem] representedObject];
877     if (p_valueobject) {
878         assert([p_valueobject isKindOfClass:[NSNumber class]]);
879         config_PutInt(p_intf, name, [p_valueobject intValue]);
880     }
881 }
882
883 static inline void save_string_list(intf_thread_t * p_intf, id object, const char * name)
884 {
885     NSString *p_stringobject = (NSString *)[[object selectedItem] representedObject];
886     if (p_stringobject) {
887         assert([p_stringobject isKindOfClass:[NSString class]]);
888         config_PutPsz(p_intf, name, [p_stringobject UTF8String]);
889     }
890 }
891
892 - (void)saveChangedSettings
893 {
894     NSString *tmpString;
895     NSRange tmpRange;
896
897 #define SaveIntList(object, name) save_int_list(p_intf, object, name)
898
899 #define SaveStringList(object, name) save_string_list(p_intf, object, name)
900 #define SaveModuleList(object, name) SaveStringList(object, name)
901
902 #define getString(name) [NSString stringWithFormat:@"%s", config_GetPsz(p_intf, name)]
903
904     /**********************
905      * interface settings *
906      **********************/
907     if (b_intfSettingChanged) {
908         NSUInteger index = [o_intf_language_pop indexOfSelectedItem];
909         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
910         [defaults setObject:[NSString stringWithUTF8String:ppsz_language[index]] forKey:@"language"];
911         [defaults synchronize];
912
913         config_PutInt(p_intf, "metadata-network-access", [o_intf_art_ckb state]);
914
915         config_PutInt(p_intf, "macosx-fspanel", [o_intf_fspanel_ckb state]);
916         config_PutInt(p_intf, "embedded-video", [o_intf_embedded_ckb state]);
917
918         config_PutInt(p_intf, "macosx-appleremote", [o_intf_appleremote_ckb state]);
919         config_PutInt(p_intf, "macosx-appleremote-sysvol", [o_intf_appleremote_sysvol_ckb state]);
920         config_PutInt(p_intf, "macosx-mediakeys", [o_intf_mediakeys_ckb state]);
921         config_PutInt(p_intf, "macosx-interfacestyle", [o_intf_style_dark_bcell state]);
922         config_PutInt(p_intf, "macosx-nativefullscreenmode", [o_intf_nativefullscreen_ckb state]);
923         config_PutInt(p_intf, "macosx-pause-minimized", [o_intf_pauseminimized_ckb state]);
924         config_PutInt(p_intf, "macosx-video-autoresize", [o_intf_autoresize_ckb state]);
925         if ([o_intf_enableGrowl_ckb state] == NSOnState) {
926             tmpString = getString("control");
927             tmpRange = [tmpString rangeOfString:@"growl"];
928             if ([tmpString length] > 0 && tmpRange.location == NSNotFound)
929             {
930                 tmpString = [tmpString stringByAppendingString: @":growl"];
931                 config_PutPsz(p_intf, "control", [tmpString UTF8String]);
932             }
933             else
934                 config_PutPsz(p_intf, "control", "growl");
935         } else {
936             tmpString = getString("control");
937             if (! [tmpString isEqualToString:@""])
938             {
939                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@":growl"]];
940                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"growl:"]];
941                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"growl"]];
942                 config_PutPsz(p_intf, "control", [tmpString UTF8String]);
943             }
944         }
945         config_PutPsz(p_intf, "http-password", [[o_intf_luahttppwd_fld stringValue] UTF8String]);
946
947         SaveIntList(o_intf_pauseitunes_pop, "macosx-control-itunes");
948         SaveIntList(o_intf_continueplayback_pop, "macosx-continue-playback");
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         config_PutInt(p_intf, "macosx-vdev", [[o_video_device_pop selectedItem] tag]);
1003
1004         config_PutPsz(p_intf, "snapshot-path", [[o_video_snap_folder_fld stringValue] UTF8String]);
1005         config_PutPsz(p_intf, "snapshot-prefix", [[o_video_snap_prefix_fld stringValue] UTF8String]);
1006         config_PutInt(p_intf, "snapshot-sequential", [o_video_snap_seqnum_ckb state]);
1007         SaveStringList(o_video_snap_format_pop, "snapshot-format");
1008         SaveIntList(o_video_deinterlace_pop, "deinterlace");
1009         SaveStringList(o_video_deinterlace_mode_pop, "deinterlace-mode");
1010         b_videoSettingChanged = NO;
1011     }
1012
1013     /***************************
1014      * input & codecs settings *
1015      ***************************/
1016     if (b_inputSettingChanged) {
1017         config_PutPsz(p_intf, "input-record-path", [[o_input_record_fld stringValue] UTF8String]);
1018         config_PutInt(p_intf, "postproc-q", [o_input_postproc_fld intValue]);
1019
1020         SaveIntList(o_input_avi_pop, "avi-index");
1021
1022         config_PutInt(p_intf, "rtsp-tcp", [o_input_rtsp_ckb state]);
1023         SaveModuleList(o_input_avcodec_hw_pop, "avcodec-hw");
1024         SaveIntList(o_input_skipLoop_pop, "avcodec-skiploopfilter");
1025
1026         config_PutInt(p_intf, "mkv-preload-local-dir", [o_input_mkv_preload_dir_ckb state]);
1027
1028         #define CaC(name, factor) config_PutInt(p_intf, name, [[o_input_cachelevel_pop selectedItem] tag] * factor)
1029         if ([[o_input_cachelevel_pop selectedItem] tag] == 0) {
1030             msg_Dbg(p_intf, "Custom chosen, not adjusting cache values");
1031         } else {
1032             msg_Dbg(p_intf, "Adjusting all cache values to: %i", (int)[[o_input_cachelevel_pop selectedItem] tag]);
1033             CaC("file-caching", 1);
1034             CaC("network-caching", 10/3);
1035             CaC("disc-caching", 1);
1036             CaC("live-caching", 1);
1037         }
1038         #undef CaC
1039         b_inputSettingChanged = NO;
1040     }
1041
1042     /**********************
1043      * subtitles settings *
1044      **********************/
1045     if (b_osdSettingChanged) {
1046         config_PutInt(p_intf, "osd", [o_osd_osd_ckb state]);
1047
1048         if ([o_osd_encoding_pop indexOfSelectedItem] >= 0)
1049             SaveStringList(o_osd_encoding_pop, "subsdec-encoding");
1050         else
1051             config_PutPsz(p_intf, "subsdec-encoding", "");
1052
1053         config_PutPsz(p_intf, "sub-language", [[o_osd_lang_fld stringValue] UTF8String]);
1054
1055         config_PutPsz(p_intf, "freetype-font", [[o_osd_font_fld stringValue] UTF8String]);
1056         SaveIntList(o_osd_font_color_pop, "freetype-color");
1057         SaveIntList(o_osd_font_size_pop, "freetype-rel-fontsize");
1058         config_PutInt(p_intf, "freetype-opacity", [o_osd_opacity_fld intValue] * 255.0 / 100.0 + 0.5);
1059         config_PutInt(p_intf, "freetype-bold", [o_osd_forcebold_ckb state]);
1060         SaveIntList(o_osd_outline_color_pop, "freetype-outline-color");
1061         SaveIntList(o_osd_outline_thickness_pop, "freetype-outline-thickness");
1062         b_osdSettingChanged = NO;
1063     }
1064
1065     /********************
1066      * hotkeys settings *
1067      ********************/
1068     if (b_hotkeyChanged) {
1069         NSUInteger hotKeyCount = [o_hotkeySettings count];
1070         for (NSUInteger i = 0; i < hotKeyCount; i++)
1071             config_PutPsz(p_intf, [[o_hotkeyNames objectAtIndex:i] UTF8String], [[o_hotkeySettings objectAtIndex:i]UTF8String]);
1072         b_hotkeyChanged = NO;
1073     }
1074
1075     [[VLCCoreInteraction sharedInstance] fixPreferences];
1076
1077     /* okay, let's save our changes to vlcrc */
1078     config_SaveConfigFile(p_intf);
1079
1080     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCMediaKeySupportSettingChanged"
1081                                                             object: nil
1082                                                           userInfo: nil];
1083 }
1084
1085 - (void)showSettingsForCategory: (id)o_new_category_view
1086 {
1087     NSRect o_win_rect, o_view_rect, o_old_view_rect;
1088     o_win_rect = [o_sprefs_win frame];
1089     o_view_rect = [o_new_category_view frame];
1090
1091     if (o_currentlyShownCategoryView == o_new_category_view)
1092         return;
1093
1094     if (o_currentlyShownCategoryView != nil) {
1095         /* restore our window's height, if we've shown another category previously */
1096         o_old_view_rect = [o_currentlyShownCategoryView frame];
1097         o_win_rect.size.height = o_win_rect.size.height - o_old_view_rect.size.height;
1098         o_win_rect.origin.y = (o_win_rect.origin.y + o_old_view_rect.size.height) - o_view_rect.size.height;
1099     }
1100
1101     o_win_rect.size.height = o_win_rect.size.height + o_view_rect.size.height;
1102
1103     [o_new_category_view setFrame: NSMakeRect(0,
1104                                                [o_sprefs_controls_box frame].size.height,
1105                                                o_view_rect.size.width,
1106                                                o_view_rect.size.height)];
1107     [o_new_category_view setAutoresizesSubviews: YES];
1108     if (o_currentlyShownCategoryView) {
1109         [[[o_sprefs_win contentView] animator] replaceSubview: o_currentlyShownCategoryView with: o_new_category_view];
1110         [o_currentlyShownCategoryView release];
1111         [[o_sprefs_win animator] setFrame: o_win_rect display:YES];
1112     } else {
1113         [[o_sprefs_win contentView] addSubview: o_new_category_view];
1114         [o_sprefs_win setFrame: o_win_rect display:YES animate:NO];
1115     }
1116
1117     /* keep our current category for further reference */
1118     o_currentlyShownCategoryView = o_new_category_view;
1119     [o_currentlyShownCategoryView retain];
1120 }
1121
1122 #pragma mark -
1123 #pragma mark Specific actions
1124
1125 // disables some video settings which do not work in lion mode
1126 - (void)enableLionFullscreenMode: (BOOL)b_value
1127 {
1128     [o_video_videodeco_ckb setEnabled: !b_value];
1129     [o_video_black_ckb setEnabled: !b_value];
1130
1131     if (b_value) {
1132         [o_video_videodeco_ckb setState: NSOnState];
1133         [o_video_black_ckb setState: NSOffState];
1134
1135         NSString *o_tooltipText = _NS("This setting cannot be changed because the native fullscreen mode is enabled.");
1136         [o_video_videodeco_ckb setToolTip: o_tooltipText];
1137         [o_video_black_ckb setToolTip: o_tooltipText];
1138     } else {
1139         [self setupButton: o_video_videodeco_ckb forBoolValue: "video-deco"];
1140         [self setupButton: o_video_black_ckb forBoolValue: "macosx-black"];
1141     }
1142 }
1143
1144 - (IBAction)interfaceSettingChanged:(id)sender
1145 {
1146     if (sender == o_intf_nativefullscreen_ckb)
1147         [self enableLionFullscreenMode:[sender state]];
1148
1149     b_intfSettingChanged = YES;
1150 }
1151
1152 - (void)showInterfaceSettings
1153 {
1154     [self showSettingsForCategory: o_intf_view];
1155 }
1156
1157 - (IBAction)audioSettingChanged:(id)sender
1158 {
1159     if (sender == o_audio_vol_sld)
1160         [o_audio_vol_fld setIntValue: [o_audio_vol_sld intValue]];
1161
1162     if (sender == o_audio_vol_fld)
1163         [o_audio_vol_sld setIntValue: [o_audio_vol_fld intValue]];
1164
1165     if (sender == o_audio_last_ckb) {
1166         if ([o_audio_last_ckb state] == NSOnState) {
1167             [o_audio_lastpwd_sfld setEnabled: YES];
1168             [o_audio_lastuser_fld setEnabled: YES];
1169         } else {
1170             [o_audio_lastpwd_sfld setEnabled: NO];
1171             [o_audio_lastuser_fld setEnabled: NO];
1172         }
1173     }
1174
1175     if (sender == o_audio_autosavevol_matrix) {
1176         BOOL enableVolumeSlider = [o_audio_autosavevol_matrix selectedTag] == 1;
1177         [o_audio_vol_fld setEnabled: enableVolumeSlider];
1178         [o_audio_vol_sld setEnabled: enableVolumeSlider];
1179     }
1180
1181     b_audioSettingChanged = YES;
1182 }
1183
1184 - (void)showAudioSettings
1185 {
1186     [self showSettingsForCategory: o_audio_view];
1187 }
1188
1189 - (IBAction)videoSettingChanged:(id)sender
1190 {
1191     if (sender == o_video_snap_folder_btn) {
1192         o_selectFolderPanel = [[NSOpenPanel alloc] init];
1193         [o_selectFolderPanel setCanChooseDirectories: YES];
1194         [o_selectFolderPanel setCanChooseFiles: NO];
1195         [o_selectFolderPanel setResolvesAliases: YES];
1196         [o_selectFolderPanel setAllowsMultipleSelection: NO];
1197         [o_selectFolderPanel setMessage: _NS("Choose the folder to save your video snapshots to.")];
1198         [o_selectFolderPanel setCanCreateDirectories: YES];
1199         [o_selectFolderPanel setPrompt: _NS("Choose")];
1200         [o_selectFolderPanel beginSheetModalForWindow: o_sprefs_win completionHandler: ^(NSInteger returnCode) {
1201             if (returnCode == NSOKButton)
1202             {
1203                 [o_video_snap_folder_fld setStringValue: [[o_selectFolderPanel URL] path]];
1204                 b_videoSettingChanged = YES;
1205             }
1206         }];
1207         [o_selectFolderPanel release];
1208     } else
1209         b_videoSettingChanged = YES;
1210 }
1211
1212 - (void)showVideoSettings
1213 {
1214     [self showSettingsForCategory: o_video_view];
1215 }
1216
1217 - (IBAction)osdSettingChanged:(id)sender
1218 {
1219     if (sender == o_osd_opacity_fld)
1220         [o_osd_opacity_sld setIntValue: [o_osd_opacity_fld intValue]];
1221
1222     if (sender == o_osd_opacity_sld)
1223         [o_osd_opacity_fld setIntValue: [o_osd_opacity_sld intValue]];
1224
1225     b_osdSettingChanged = YES;
1226 }
1227
1228 - (void)showOSDSettings
1229 {
1230     [self showSettingsForCategory: o_osd_view];
1231 }
1232
1233 - (void)controlTextDidChange:(NSNotification *)o_notification
1234 {
1235     id notificationObject = [o_notification object];
1236     if (notificationObject == o_audio_lang_fld ||
1237        notificationObject ==  o_audio_lastpwd_sfld ||
1238        notificationObject ==  o_audio_lastuser_fld ||
1239        notificationObject == o_audio_vol_fld)
1240         b_audioSettingChanged = YES;
1241     else if (notificationObject == o_input_record_fld ||
1242             notificationObject == o_input_postproc_fld)
1243         b_inputSettingChanged = YES;
1244     else if (notificationObject == o_osd_font_fld ||
1245             notificationObject == o_osd_lang_fld ||
1246             notificationObject == o_osd_opacity_fld)
1247         b_osdSettingChanged = YES;
1248     else if (notificationObject == o_video_snap_folder_fld ||
1249             notificationObject == o_video_snap_prefix_fld)
1250         b_videoSettingChanged = YES;
1251     else if (notificationObject == o_intf_luahttppwd_fld)
1252         b_intfSettingChanged = YES;
1253 }
1254
1255 - (IBAction)showFontPicker:(id)sender
1256 {
1257     char * font = config_GetPsz(p_intf, "freetype-font");
1258     NSString * fontName = font ? [NSString stringWithUTF8String:font] : nil;
1259     free(font);
1260     if (fontName) {
1261         NSFont * font = [NSFont fontWithName:fontName size:0.0];
1262         [[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:NO];
1263     }
1264     [[NSFontManager sharedFontManager] setTarget: self];
1265     [[NSFontPanel sharedFontPanel] setDelegate:self];
1266     [[NSFontPanel sharedFontPanel] makeKeyAndOrderFront:self];
1267 }
1268
1269 - (void)changeFont:(id)sender
1270 {
1271     NSFont * font = [sender convertFont:[[NSFontManager sharedFontManager] selectedFont]];
1272     [o_osd_font_fld setStringValue:[font fontName]];
1273     [self osdSettingChanged:self];
1274 }
1275
1276 - (NSUInteger)validModesForFontPanel:(NSFontPanel *)fontPanel
1277 {
1278     return NSFontPanelFaceModeMask | NSFontPanelCollectionModeMask;
1279 }
1280
1281 - (IBAction)inputSettingChanged:(id)sender
1282 {
1283     if (sender == o_input_cachelevel_pop) {
1284         if ([[[o_input_cachelevel_pop selectedItem] title] isEqualToString: _NS("Custom")])
1285             [o_input_cachelevel_custom_txt setHidden: NO];
1286         else
1287             [o_input_cachelevel_custom_txt setHidden: YES];
1288     } else if (sender == o_input_record_btn) {
1289         o_selectFolderPanel = [[NSOpenPanel alloc] init];
1290         [o_selectFolderPanel setCanChooseDirectories: YES];
1291         [o_selectFolderPanel setCanChooseFiles: YES];
1292         [o_selectFolderPanel setResolvesAliases: YES];
1293         [o_selectFolderPanel setAllowsMultipleSelection: NO];
1294         [o_selectFolderPanel setMessage: _NS("Choose the directory or filename where the records will be stored.")];
1295         [o_selectFolderPanel setCanCreateDirectories: YES];
1296         [o_selectFolderPanel setPrompt: _NS("Choose")];
1297         [o_selectFolderPanel beginSheetModalForWindow: o_sprefs_win completionHandler: ^(NSInteger returnCode) {
1298             if (returnCode == NSOKButton)
1299             {
1300                 [o_input_record_fld setStringValue: [[o_selectFolderPanel URL] path]];
1301                 b_inputSettingChanged = YES;
1302             }
1303         }];
1304         [o_selectFolderPanel release];
1305
1306         return;
1307     }
1308
1309     b_inputSettingChanged = YES;
1310 }
1311
1312 - (void)showInputSettings
1313 {
1314     [self showSettingsForCategory: o_input_view];
1315 }
1316
1317 - (NSString *)bundleIdentifierForApplicationName:(NSString *)appName
1318 {
1319     NSWorkspace * workspace = [NSWorkspace sharedWorkspace];
1320     NSString * appPath = [workspace fullPathForApplication:appName];
1321     if (appPath) {
1322         NSBundle * appBundle = [NSBundle bundleWithPath:appPath];
1323         return [appBundle bundleIdentifier];
1324     }
1325     return nil;
1326 }
1327
1328 - (NSString *)applicationNameForBundleIdentifier:(NSString *)bundleIdentifier
1329 {
1330     return [[[NSFileManager defaultManager] displayNameAtPath:[[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:bundleIdentifier]] stringByDeletingPathExtension];
1331 }
1332
1333 - (NSImage *)iconForBundleIdentifier:(NSString *)bundleIdentifier
1334 {
1335     NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
1336     NSSize iconSize = NSMakeSize(16., 16.);
1337     NSImage *icon = [workspace iconForFile:[workspace absolutePathForAppBundleWithIdentifier:bundleIdentifier]];
1338     [icon setSize:iconSize];
1339     return icon;
1340 }
1341
1342 - (IBAction)urlHandlerAction:(id)sender
1343 {
1344     NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
1345
1346     if (sender == o_input_urlhandler_btn) {
1347         NSArray *handlers;
1348         NSString *handler;
1349         NSString *rawhandler;
1350         NSMutableArray *rawHandlers;
1351         NSUInteger count;
1352
1353 #define fillUrlHandlerPopup( protocol, object ) \
1354         handlers = (NSArray *)LSCopyAllHandlersForURLScheme(CFSTR( protocol )); \
1355         rawHandlers = [[NSMutableArray alloc] init]; \
1356         [object removeAllItems]; \
1357         count = [handlers count]; \
1358         for (NSUInteger x = 0; x < count; x++) { \
1359             rawhandler = [handlers objectAtIndex:x]; \
1360             handler = [self applicationNameForBundleIdentifier:rawhandler]; \
1361             if (handler && ![handler isEqualToString:@""]) { \
1362                 [object addItemWithTitle:handler]; \
1363                 [[object lastItem] setImage: [self iconForBundleIdentifier:[handlers objectAtIndex:x]]]; \
1364                 [rawHandlers addObject: rawhandler]; \
1365             } \
1366         } \
1367         [object selectItemAtIndex: [rawHandlers indexOfObject:(id)LSCopyDefaultHandlerForURLScheme(CFSTR( protocol ))]]; \
1368         [rawHandlers release]
1369
1370         fillUrlHandlerPopup( "ftp", o_urlhandler_ftp_pop);
1371         fillUrlHandlerPopup( "mms", o_urlhandler_mms_pop);
1372         fillUrlHandlerPopup( "rtmp", o_urlhandler_rtmp_pop);
1373         fillUrlHandlerPopup( "rtp", o_urlhandler_rtp_pop);
1374         fillUrlHandlerPopup( "rtsp", o_urlhandler_rtsp_pop);
1375         fillUrlHandlerPopup( "sftp", o_urlhandler_sftp_pop);
1376         fillUrlHandlerPopup( "smb", o_urlhandler_smb_pop);
1377         fillUrlHandlerPopup( "udp", o_urlhandler_udp_pop);
1378
1379 #undef fillUrlHandlerPopup
1380
1381         [NSApp beginSheet:o_urlhandler_win modalForWindow:o_sprefs_win modalDelegate:self didEndSelector:NULL contextInfo:nil];
1382     } else {
1383         [o_urlhandler_win orderOut:sender];
1384         [NSApp endSheet: o_urlhandler_win];
1385
1386         if (sender == o_urlhandler_save_btn) {
1387             LSSetDefaultHandlerForURLScheme(CFSTR("ftp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_ftp_pop selectedItem] title]]);
1388             LSSetDefaultHandlerForURLScheme(CFSTR("mms"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_mms_pop selectedItem] title]]);
1389             LSSetDefaultHandlerForURLScheme(CFSTR("mmsh"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_mms_pop selectedItem] title]]);
1390             LSSetDefaultHandlerForURLScheme(CFSTR("rtmp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_rtmp_pop selectedItem] title]]);
1391             LSSetDefaultHandlerForURLScheme(CFSTR("rtp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_rtp_pop selectedItem] title]]);
1392             LSSetDefaultHandlerForURLScheme(CFSTR("rtsp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_rtsp_pop selectedItem] title]]);
1393             LSSetDefaultHandlerForURLScheme(CFSTR("sftp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_sftp_pop selectedItem] title]]);
1394             LSSetDefaultHandlerForURLScheme(CFSTR("smb"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_smb_pop selectedItem] title]]);
1395             LSSetDefaultHandlerForURLScheme(CFSTR("udp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_udp_pop selectedItem] title]]);
1396         }
1397     }
1398 }
1399
1400 #pragma mark -
1401 #pragma mark Hotkey actions
1402
1403 - (void)hotkeyTableDoubleClick:(id)object
1404 {
1405     // -1 is header
1406     if ([o_hotkeys_listbox clickedRow] >= 0)
1407         [self hotkeySettingChanged:o_hotkeys_listbox];
1408 }
1409
1410 - (IBAction)hotkeySettingChanged:(id)sender
1411 {
1412     if (sender == o_hotkeys_change_btn || sender == o_hotkeys_listbox) {
1413         [o_hotkeys_change_lbl setStringValue: [NSString stringWithFormat: _NS("Press new keys for\n\"%@\""),
1414                                                [o_hotkeyDescriptions objectAtIndex:[o_hotkeys_listbox selectedRow]]]];
1415         [o_hotkeys_change_keys_lbl setStringValue: [[VLCStringUtility sharedInstance] OSXStringKeyToString:[o_hotkeySettings objectAtIndex:[o_hotkeys_listbox selectedRow]]]];
1416         [o_hotkeys_change_taken_lbl setStringValue: @""];
1417         [o_hotkeys_change_win setInitialFirstResponder: [o_hotkeys_change_win contentView]];
1418         [o_hotkeys_change_win makeFirstResponder: [o_hotkeys_change_win contentView]];
1419         [NSApp runModalForWindow: o_hotkeys_change_win];
1420     } else if (sender == o_hotkeys_change_cancel_btn) {
1421         [NSApp stopModal];
1422         [o_hotkeys_change_win close];
1423     } else if (sender == o_hotkeys_change_ok_btn) {
1424         NSInteger i_returnValue;
1425         if (! o_keyInTransition) {
1426             [NSApp stopModal];
1427             [o_hotkeys_change_win close];
1428             msg_Err(p_intf, "internal error prevented the hotkey switch");
1429             return;
1430         }
1431
1432         b_hotkeyChanged = YES;
1433
1434         i_returnValue = [o_hotkeySettings indexOfObject: o_keyInTransition];
1435         if (i_returnValue != NSNotFound)
1436             [o_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]];
1437         NSString *tempString;
1438         tempString = [o_keyInTransition stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
1439         i_returnValue = [o_hotkeySettings indexOfObject: tempString];
1440         if (i_returnValue != NSNotFound)
1441             [o_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]];
1442
1443         [o_hotkeySettings replaceObjectAtIndex: [o_hotkeys_listbox selectedRow] withObject: [o_keyInTransition retain]];
1444
1445         [NSApp stopModal];
1446         [o_hotkeys_change_win close];
1447
1448         [o_hotkeys_listbox reloadData];
1449     } else if (sender == o_hotkeys_clear_btn) {
1450         [o_hotkeySettings replaceObjectAtIndex: [o_hotkeys_listbox selectedRow] withObject: [NSString string]];
1451         [o_hotkeys_listbox reloadData];
1452         b_hotkeyChanged = YES;
1453     }
1454
1455     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCMediaKeySupportSettingChanged"
1456                                                         object: nil
1457                                                       userInfo: nil];
1458 }
1459
1460 - (void)showHotkeySettings
1461 {
1462     [self showSettingsForCategory: o_hotkeys_view];
1463 }
1464
1465 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
1466 {
1467     return [o_hotkeySettings count];
1468 }
1469
1470 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
1471 {
1472     NSString * identifier = [aTableColumn identifier];
1473
1474     if ([identifier isEqualToString: @"action"])
1475         return [o_hotkeyDescriptions objectAtIndex:rowIndex];
1476     else if ([identifier isEqualToString: @"shortcut"])
1477         return [[VLCStringUtility sharedInstance] OSXStringKeyToString:[o_hotkeySettings objectAtIndex:rowIndex]];
1478     else {
1479         msg_Err(p_intf, "unknown TableColumn identifier (%s)!", [identifier UTF8String]);
1480         return NULL;
1481     }
1482 }
1483
1484 - (BOOL)changeHotkeyTo: (NSString *)theKey
1485 {
1486     NSInteger i_returnValue, i_returnValue2;
1487     i_returnValue = [o_hotkeysNonUseableKeys indexOfObject: theKey];
1488
1489     if (i_returnValue != NSNotFound || [theKey isEqualToString:@""]) {
1490         [o_hotkeys_change_keys_lbl setStringValue: _NS("Invalid combination")];
1491         [o_hotkeys_change_taken_lbl setStringValue: _NS("Regrettably, these keys cannot be assigned as hotkey shortcuts.")];
1492         [o_hotkeys_change_ok_btn setEnabled: NO];
1493         return NO;
1494     } else {
1495         [o_hotkeys_change_keys_lbl setStringValue: [[VLCStringUtility sharedInstance] OSXStringKeyToString:theKey]];
1496
1497         i_returnValue = [o_hotkeySettings indexOfObject: theKey];
1498         i_returnValue2 = [o_hotkeySettings indexOfObject: [theKey stringByReplacingOccurrencesOfString:@"-" withString:@"+"]];
1499         if (i_returnValue != NSNotFound)
1500             [o_hotkeys_change_taken_lbl setStringValue: [NSString stringWithFormat:
1501                                                          _NS("This combination is already taken by \"%@\"."),
1502                                                          [o_hotkeyDescriptions objectAtIndex:i_returnValue]]];
1503         else if (i_returnValue2 != NSNotFound)
1504             [o_hotkeys_change_taken_lbl setStringValue: [NSString stringWithFormat:
1505                                                          _NS("This combination is already taken by \"%@\"."),
1506                                                          [o_hotkeyDescriptions objectAtIndex:i_returnValue2]]];
1507         else
1508             [o_hotkeys_change_taken_lbl setStringValue: @""];
1509
1510         [o_hotkeys_change_ok_btn setEnabled: YES];
1511         [o_keyInTransition release];
1512         o_keyInTransition = theKey;
1513         [o_keyInTransition retain];
1514         return YES;
1515     }
1516 }
1517
1518 @end
1519
1520 /********************
1521  * hotkeys settings *
1522  ********************/
1523
1524 @implementation VLCHotkeyChangeWindow
1525
1526 - (BOOL)acceptsFirstResponder
1527 {
1528     return YES;
1529 }
1530
1531 - (BOOL)becomeFirstResponder
1532 {
1533     return YES;
1534 }
1535
1536 - (BOOL)resignFirstResponder
1537 {
1538     /* We need to stay the first responder or we'll miss the user's input */
1539     return NO;
1540 }
1541
1542 - (BOOL)performKeyEquivalent:(NSEvent *)o_theEvent
1543 {
1544     NSMutableString *tempString = [[[NSMutableString alloc] init] autorelease];
1545     NSString *keyString = [o_theEvent characters];
1546
1547     unichar key = [keyString characterAtIndex:0];
1548     NSUInteger i_modifiers = [o_theEvent modifierFlags];
1549
1550     /* modifiers */
1551     if (i_modifiers & NSControlKeyMask)
1552         [tempString appendString:@"Ctrl-"];
1553     if (i_modifiers & NSAlternateKeyMask )
1554         [tempString appendString:@"Alt-"];
1555     if (i_modifiers & NSShiftKeyMask)
1556         [tempString appendString:@"Shift-"];
1557     if (i_modifiers & NSCommandKeyMask)
1558         [tempString appendString:@"Command-"];
1559
1560     /* non character keys */
1561     if (key == NSUpArrowFunctionKey)
1562         [tempString appendString:@"Up"];
1563     else if (key == NSDownArrowFunctionKey)
1564         [tempString appendString:@"Down"];
1565     else if (key == NSLeftArrowFunctionKey)
1566         [tempString appendString:@"Left"];
1567     else if (key == NSRightArrowFunctionKey)
1568         [tempString appendString:@"Right"];
1569     else if (key == NSF1FunctionKey)
1570         [tempString appendString:@"F1"];
1571     else if (key == NSF2FunctionKey)
1572         [tempString appendString:@"F2"];
1573     else if (key == NSF3FunctionKey)
1574         [tempString appendString:@"F3"];
1575     else if (key == NSF4FunctionKey)
1576         [tempString appendString:@"F4"];
1577     else if (key == NSF5FunctionKey)
1578         [tempString appendString:@"F5"];
1579     else if (key == NSF6FunctionKey)
1580         [tempString appendString:@"F6"];
1581     else if (key == NSF7FunctionKey)
1582         [tempString appendString:@"F7"];
1583     else if (key == NSF8FunctionKey)
1584         [tempString appendString:@"F8"];
1585     else if (key == NSF9FunctionKey)
1586         [tempString appendString:@"F9"];
1587     else if (key == NSF10FunctionKey)
1588         [tempString appendString:@"F10"];
1589     else if (key == NSF11FunctionKey)
1590         [tempString appendString:@"F11"];
1591     else if (key == NSF12FunctionKey)
1592         [tempString appendString:@"F12"];
1593     else if (key == NSInsertFunctionKey)
1594         [tempString appendString:@"Insert"];
1595     else if (key == NSHomeFunctionKey)
1596         [tempString appendString:@"Home"];
1597     else if (key == NSEndFunctionKey)
1598         [tempString appendString:@"End"];
1599     else if (key == NSPageUpFunctionKey)
1600         [tempString appendString:@"Page Up"];
1601     else if (key == NSPageDownFunctionKey)
1602         [tempString appendString:@"Page Down"];
1603     else if (key == NSMenuFunctionKey)
1604         [tempString appendString:@"Menu"];
1605     else if (key == NSTabCharacter)
1606         [tempString appendString:@"Tab"];
1607     else if (key == NSCarriageReturnCharacter)
1608         [tempString appendString:@"Enter"];
1609     else if (key == NSEnterCharacter)
1610         [tempString appendString:@"Enter"];
1611     else if (key == NSDeleteCharacter)
1612         [tempString appendString:@"Delete"];
1613     else if (key == NSBackspaceCharacter)
1614         [tempString appendString:@"Backspace"];
1615     else if (key == 0x001B)
1616         [tempString appendString:@"Esc"];
1617     else if (key == ' ')
1618         [tempString appendString:@"Space"];
1619     else if (![[[o_theEvent charactersIgnoringModifiers] lowercaseString] isEqualToString:@""]) //plain characters
1620         [tempString appendString:[[o_theEvent charactersIgnoringModifiers] lowercaseString]];
1621     else
1622         return NO;
1623
1624     return [[[VLCMain sharedInstance] simplePreferences] changeHotkeyTo: tempString];
1625 }
1626
1627 @end
1628
1629 @implementation VLCSimplePrefsWindow
1630
1631 - (BOOL)acceptsFirstResponder
1632 {
1633     return YES;
1634 }
1635
1636 - (void)changeFont:(id)sender
1637 {
1638     [[[VLCMain sharedInstance] simplePreferences] changeFont: sender];
1639 }
1640 @end