]> git.sesse.net Git - vlc/blob - modules/gui/macosx/simple_prefs.m
AVI: reverse the height only if it needs to be reversed
[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_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("Control external music players")];
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_skipFrames_ckb setTitle: _NS("Skip frames")];
401     [o_video_snap_box setTitle: _NS("Video snapshots")];
402     [o_video_snap_folder_btn setTitle: _NS("Browse...")];
403     [o_video_snap_folder_txt setStringValue: _NS("Folder")];
404     [o_video_snap_format_txt setStringValue: _NS("Format")];
405     [o_video_snap_prefix_txt setStringValue: _NS("Prefix")];
406     [o_video_snap_seqnum_ckb setTitle: _NS("Sequential numbering")];
407     [o_video_deinterlace_txt setStringValue: _NS("Deinterlace")];
408     [o_video_deinterlace_mode_txt setStringValue: _NS("Deinterlace mode")];
409     [o_video_video_box setTitle: _NS("Video")];
410
411     /* generic stuff */
412     [o_sprefs_showAll_btn setTitle: _NS("Show All")];
413     [o_sprefs_cancel_btn setTitle: _NS("Cancel")];
414     [o_sprefs_reset_btn setTitle: _NS("Reset All")];
415     [o_sprefs_save_btn setTitle: _NS("Save")];
416     [o_sprefs_win setTitle: _NS("Preferences")];
417 }
418
419 /* TODO: move this part to core */
420 #define config_GetLabel(a,b) __config_GetLabel(VLC_OBJECT(a),b)
421 static inline char * __config_GetLabel(vlc_object_t *p_this, const char *psz_name)
422 {
423     module_config_t *p_config;
424
425     p_config = config_FindConfig(p_this, psz_name);
426
427     /* sanity checks */
428     if (!p_config) {
429         msg_Err(p_this, "option %s does not exist", psz_name);
430         return NULL;
431     }
432
433     if (p_config->psz_longtext)
434         return p_config->psz_longtext;
435     else if (p_config->psz_text)
436         return p_config->psz_text;
437     else
438         msg_Warn(p_this, "option %s does not include any help", psz_name);
439
440     return NULL;
441 }
442
443 #pragma mark -
444 #pragma mark Setup controls
445
446 - (void)setupButton: (NSPopUpButton *)object forStringList: (const char *)name
447 {
448     module_config_t *p_item;
449
450     [object removeAllItems];
451     p_item = config_FindConfig(VLC_OBJECT(p_intf), name);
452     /* serious problem, if no item found */
453     assert(p_item);
454
455     char **values, **texts;
456     ssize_t count = config_GetPszChoices(VLC_OBJECT(VLCIntf), name,
457                                          &values, &texts);
458     if (count < 0) {
459         msg_Err(p_intf, "Cannot get choices for %s", name);
460         return;
461     }
462     for (ssize_t i = 0; i < count && texts; i++) {
463         if (texts[i] == NULL || values[i] == NULL)
464             continue;
465
466         if (strcmp(texts[i], "") != 0) {
467             NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""];
468             [mi setRepresentedObject: toNSStr(values[i])];
469             [[object menu] addItem: [mi autorelease]];
470
471             if (p_item->value.psz && !strcmp(p_item->value.psz, values[i]))
472                 [object selectItem: [object lastItem]];
473             
474         } else {
475             [[object menu] addItem: [NSMenuItem separatorItem]];
476         }
477
478         free(texts[i]);
479         free(values[i]);
480     }
481
482     free(texts);
483     free(values);
484
485     if (p_item->psz_longtext)
486         [object setToolTip: _NS(p_item->psz_longtext)];
487 }
488
489 // just for clarification that this is a module list
490 - (void)setupButton: (NSPopUpButton *)object forModuleList: (const char *)name
491 {
492     [self setupButton: object forStringList: name];
493 }
494
495 - (void)setupButton: (NSPopUpButton *)object forIntList: (const char *)name
496 {
497     module_config_t *p_item;
498
499     [object removeAllItems];
500     p_item = config_FindConfig(VLC_OBJECT(p_intf), name);
501
502     /* serious problem, if no item found */
503     assert(p_item);
504
505     int64_t *values;
506     char **texts;
507     ssize_t count = config_GetIntChoices(VLC_OBJECT(VLCIntf), name, &values, &texts);
508     for (ssize_t i = 0; i < count; i++) {
509         NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""];
510         [mi setRepresentedObject:[NSNumber numberWithInt:values[i]]];
511         [[object menu] addItem: [mi autorelease]];
512
513         if (p_item->value.i == values[i])
514             [object selectItem:[object lastItem]];
515
516         free(texts[i]);
517     }
518     free(texts);
519
520     if (p_item->psz_longtext)
521         [object setToolTip: _NS(p_item->psz_longtext)];
522 }
523
524 - (void)setupButton: (NSButton *)object forBoolValue: (const char *)name
525 {
526     [object setState: config_GetInt(p_intf, name)];
527     [object setToolTip: _NS(config_GetLabel(p_intf, name))];
528 }
529
530 - (void)setupField:(NSTextField *)o_object forOption:(const char *)psz_option
531 {
532     char *psz_tmp = config_GetPsz(p_intf, psz_option);
533     [o_object setStringValue: [NSString stringWithUTF8String:psz_tmp ?: ""]];
534     [o_object setToolTip: _NS(config_GetLabel(p_intf, psz_option))];
535     free(psz_tmp);
536 }
537
538 - (void)resetControls
539 {
540     module_config_t *p_item;
541     int i, y = 0;
542     char *psz_tmp;
543
544     /**********************
545      * interface settings *
546      **********************/
547     NSUInteger sel = 0;
548     const char *pref = NULL;
549     pref = [[[NSUserDefaults standardUserDefaults] objectForKey:@"language"] UTF8String];
550     for (int x = 0; ppsz_language[x] != NULL; x++) {
551         [o_intf_language_pop addItemWithTitle:[NSString stringWithUTF8String:ppsz_language_text[x]]];
552         if (pref) {
553             if (!strcmp(ppsz_language[x], pref))
554                 sel = x;
555         }
556     }
557     [o_intf_language_pop selectItemAtIndex:sel];
558
559     [self setupButton: o_intf_art_pop forIntList: "album-art"];
560
561     [self setupButton: o_intf_fspanel_ckb forBoolValue: "macosx-fspanel"];
562
563     [self setupButton: o_intf_nativefullscreen_ckb forBoolValue: "macosx-nativefullscreenmode"];
564     BOOL b_correct_sdk = NO;
565 #ifdef MAC_OS_X_VERSION_10_7
566     b_correct_sdk = YES;
567 #endif
568     if (!(b_correct_sdk && !OSX_SNOW_LEOPARD)) {
569         [o_intf_nativefullscreen_ckb setState: NSOffState];
570         [o_intf_nativefullscreen_ckb setEnabled: NO];
571     }
572
573     [self setupButton: o_intf_embedded_ckb forBoolValue: "embedded-video"];
574
575     [self setupButton: o_intf_appleremote_ckb forBoolValue: "macosx-appleremote"];
576     [self setupButton: o_intf_appleremote_sysvol_ckb forBoolValue: "macosx-appleremote-sysvol"];
577
578     [self setupButton: o_intf_mediakeys_ckb forBoolValue: "macosx-mediakeys"];
579     if ([[SUUpdater sharedUpdater] lastUpdateCheckDate] != NULL)
580         [o_intf_last_update_lbl setStringValue: [NSString stringWithFormat: _NS("Last check on: %@"), [[[SUUpdater sharedUpdater] lastUpdateCheckDate] descriptionWithLocale: [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]]];
581     else
582         [o_intf_last_update_lbl setStringValue: _NS("No check was performed yet.")];
583     psz_tmp = config_GetPsz(p_intf, "control");
584     if (psz_tmp) {
585         [o_intf_enableGrowl_ckb setState: (NSInteger)strstr(psz_tmp, "growl")];
586         free(psz_tmp);
587     } else
588         [o_intf_enableGrowl_ckb setState: NSOffState];
589     if (config_GetInt(p_intf, "macosx-interfacestyle")) {
590         [o_intf_style_dark_bcell setState: YES];
591         [o_intf_style_bright_bcell setState: NO];
592     } else {
593         [o_intf_style_dark_bcell setState: NO];
594         [o_intf_style_bright_bcell setState: YES];
595     }
596     [self setupButton: o_intf_autoresize_ckb forBoolValue: "macosx-video-autoresize"];
597     [self setupButton: o_intf_pauseminimized_ckb forBoolValue: "macosx-pause-minimized"];
598     [self setupField: o_intf_luahttppwd_fld forOption: "http-password"];
599     [self setupButton: o_intf_pauseitunes_pop forIntList: "macosx-control-itunes"];
600
601     /******************
602      * audio settings *
603      ******************/
604     [self setupButton: o_audio_enable_ckb forBoolValue: "audio"];
605
606     if (config_GetInt(p_intf, "volume-save")) {
607         [o_audio_autosavevol_yes_bcell setState: NSOnState];
608         [o_audio_autosavevol_no_bcell setState: NSOffState];
609         [o_audio_vol_fld setEnabled: NO];
610         [o_audio_vol_sld setEnabled: NO];
611
612         [o_audio_vol_sld setIntValue: 100];
613         [o_audio_vol_fld setIntValue: 100];
614     } else {
615         [o_audio_autosavevol_yes_bcell setState: NSOffState];
616         [o_audio_autosavevol_no_bcell setState: NSOnState];
617         [o_audio_vol_fld setEnabled: YES];
618         [o_audio_vol_sld setEnabled: YES];
619
620         i = var_InheritInteger(p_intf, "auhal-volume");
621         i = i * 200. / AOUT_VOLUME_MAX;
622         [o_audio_vol_sld setIntValue: i];
623         [o_audio_vol_fld setIntValue: i];
624     }
625
626     [self setupButton: o_audio_spdif_ckb forBoolValue: "spdif"];
627
628     [self setupButton: o_audio_dolby_pop forIntList: "force-dolby-surround"];
629     [self setupField: o_audio_lang_fld forOption: "audio-language"];
630
631     [self setupButton: o_audio_visual_pop forModuleList: "audio-visual"];
632
633     /* Last.FM is optional */
634     if (module_exists("audioscrobbler")) {
635         [self setupField: o_audio_lastuser_fld forOption:"lastfm-username"];
636         [self setupField: o_audio_lastpwd_sfld forOption:"lastfm-password"];
637
638         if (config_ExistIntf(VLC_OBJECT(p_intf), "audioscrobbler")) {
639             [o_audio_last_ckb setState: NSOnState];
640             [o_audio_lastuser_fld setEnabled: YES];
641             [o_audio_lastpwd_sfld setEnabled: YES];
642         } else {
643             [o_audio_last_ckb setState: NSOffState];
644             [o_audio_lastuser_fld setEnabled: NO];
645             [o_audio_lastpwd_sfld setEnabled: NO];
646         }
647     } else
648         [o_audio_last_ckb setEnabled: NO];
649
650     /******************
651      * video settings *
652      ******************/
653     [self setupButton: o_video_enable_ckb forBoolValue: "video"];
654     [self setupButton: o_video_fullscreen_ckb forBoolValue: "fullscreen"];
655     [self setupButton: o_video_onTop_ckb forBoolValue: "video-on-top"];
656     [self setupButton: o_video_skipFrames_ckb forBoolValue: "skip-frames"];
657     [self setupButton: o_video_black_ckb forBoolValue: "macosx-black"];
658     [self setupButton: o_video_videodeco_ckb forBoolValue: "video-deco"];
659
660     [o_video_device_pop removeAllItems];
661     i = 0;
662     y = [[NSScreen screens] count];
663     [o_video_device_pop addItemWithTitle: _NS("Default")];
664     [[o_video_device_pop lastItem] setTag: 0];
665     while (i < y) {
666         NSRect s_rect = [[[NSScreen screens] objectAtIndex:i] frame];
667         [o_video_device_pop addItemWithTitle:
668          [NSString stringWithFormat: @"%@ %i (%ix%i)", _NS("Screen"), i+1,
669                    (int)s_rect.size.width, (int)s_rect.size.height]];
670         [[o_video_device_pop lastItem] setTag: (int)[[[NSScreen screens] objectAtIndex:i] displayID]];
671         i++;
672     }
673     [o_video_device_pop selectItemAtIndex: 0];
674     [o_video_device_pop selectItemWithTag: config_GetInt(p_intf, "macosx-vdev")];
675
676     [self setupField: o_video_snap_folder_fld forOption:"snapshot-path"];
677     [self setupField: o_video_snap_prefix_fld forOption:"snapshot-prefix"];
678     [self setupButton: o_video_snap_seqnum_ckb forBoolValue: "snapshot-sequential"];
679     [self setupButton: o_video_snap_format_pop forStringList: "snapshot-format"];
680     [self setupButton: o_video_deinterlace_pop forIntList: "deinterlace"];
681     [self setupButton: o_video_deinterlace_mode_pop forStringList: "deinterlace-mode"];
682
683     // set lion fullscreen mode restrictions
684     [self enableLionFullscreenMode: [o_intf_nativefullscreen_ckb state]];
685
686     /***************************
687      * input & codecs settings *
688      ***************************/
689     [self setupField: o_input_record_fld forOption:"input-record-path"];
690     [o_input_postproc_fld setIntValue: config_GetInt(p_intf, "postproc-q")];
691     [o_input_postproc_fld setToolTip: _NS(config_GetLabel(p_intf, "postproc-q"))];
692     [self setupButton: o_input_avcodec_hw_pop forModuleList: "avcodec-hw"];
693
694     [self setupButton: o_input_avi_pop forIntList: "avi-index"];
695
696     [self setupButton: o_input_rtsp_ckb forBoolValue: "rtsp-tcp"];
697     [self setupButton: o_input_skipLoop_pop forIntList: "avcodec-skiploopfilter"];
698
699     [self setupButton: o_input_mkv_preload_dir_ckb forBoolValue: "mkv-preload-local-dir"];
700
701     [o_input_cachelevel_pop removeAllItems];
702     [o_input_cachelevel_pop addItemsWithTitles: [NSArray arrayWithObjects:_NS("Custom"), _NS("Lowest latency"),
703      _NS("Low latency"), _NS("Normal"), _NS("High latency"), _NS("Higher latency"), nil]];
704     [[o_input_cachelevel_pop itemAtIndex: 0] setTag: 0];
705     [[o_input_cachelevel_pop itemAtIndex: 1] setTag: 100];
706     [[o_input_cachelevel_pop itemAtIndex: 2] setTag: 200];
707     [[o_input_cachelevel_pop itemAtIndex: 3] setTag: 300];
708     [[o_input_cachelevel_pop itemAtIndex: 4] setTag: 500];
709     [[o_input_cachelevel_pop itemAtIndex: 5] setTag: 1000];
710
711     #define TestCaC(name, factor) \
712     b_cache_equal =  b_cache_equal && \
713     (i_cache * factor == config_GetInt(p_intf, name));
714
715     /* Select the accurate value of the PopupButton */
716     bool b_cache_equal = true;
717     int i_cache = config_GetInt(p_intf, "file-caching");
718
719     TestCaC("network-caching", 10/3);
720     TestCaC("disc-caching", 1);
721     TestCaC("live-caching", 1);
722     if (b_cache_equal) {
723         [o_input_cachelevel_pop selectItemWithTag: i_cache];
724         [o_input_cachelevel_custom_txt setHidden: YES];
725     } else {
726         [o_input_cachelevel_pop selectItemWithTitle: _NS("Custom")];
727         [o_input_cachelevel_custom_txt setHidden: NO];
728     }
729     #undef TestCaC
730
731     /*********************
732      * subtitle settings *
733      *********************/
734     [self setupButton: o_osd_osd_ckb forBoolValue: "osd"];
735
736     [self setupButton: o_osd_encoding_pop forStringList: "subsdec-encoding"];
737     [self setupField: o_osd_lang_fld forOption: "sub-language" ];
738
739     [self setupField: o_osd_font_fld forOption: "freetype-font"];
740     [self setupButton: o_osd_font_color_pop forIntList: "freetype-color"];
741     [self setupButton: o_osd_font_size_pop forIntList: "freetype-rel-fontsize"];
742     i = config_GetInt(p_intf, "freetype-opacity") * 100.0 / 255.0 + 0.5;
743     [o_osd_opacity_fld setIntValue: i];
744     [o_osd_opacity_sld setIntValue: i];
745     [o_osd_opacity_sld setToolTip: _NS(config_GetLabel(p_intf, "freetype-opacity"))];
746     [o_osd_opacity_fld setToolTip: [o_osd_opacity_sld toolTip]];
747     [self setupButton: o_osd_forcebold_ckb forBoolValue: "freetype-bold"];
748     [self setupButton: o_osd_outline_color_pop forIntList: "freetype-outline-color"];
749     [self setupButton: o_osd_outline_thickness_pop forIntList: "freetype-outline-thickness"];
750
751     /********************
752      * hotkeys settings *
753      ********************/
754     const struct hotkey *p_hotkeys = p_intf->p_libvlc->p_hotkeys;
755     [o_hotkeySettings release];
756     o_hotkeySettings = [[NSMutableArray alloc] init];
757     NSMutableArray *o_tempArray_desc = [[NSMutableArray alloc] init];
758     NSMutableArray *o_tempArray_names = [[NSMutableArray alloc] init];
759
760     /* Get the main Module */
761     module_t *p_main = module_get_main();
762     assert(p_main);
763     unsigned confsize;
764     module_config_t *p_config;
765
766     p_config = module_config_get (p_main, &confsize);
767
768     for (size_t i = 0; i < confsize; i++) {
769         module_config_t *p_item = p_config + i;
770
771         if (CONFIG_ITEM(p_item->i_type) && p_item->psz_name != NULL
772            && !strncmp(p_item->psz_name , "key-", 4)
773            && !EMPTY_STR(p_item->psz_text)) {
774             [o_tempArray_desc addObject: _NS(p_item->psz_text)];
775             [o_tempArray_names addObject: [NSString stringWithUTF8String:p_item->psz_name]];
776             if (p_item->value.psz)
777                 [o_hotkeySettings addObject: [NSString stringWithUTF8String:p_item->value.psz]];
778             else
779                 [o_hotkeySettings addObject: [NSString string]];
780         }
781     }
782     module_config_free (p_config);
783
784     [o_hotkeyDescriptions release];
785     o_hotkeyDescriptions = [[NSArray alloc] initWithArray: o_tempArray_desc copyItems: YES];
786     [o_tempArray_desc release];
787     [o_hotkeyNames release];
788     o_hotkeyNames = [[NSArray alloc] initWithArray: o_tempArray_names copyItems: YES];
789     [o_tempArray_names release];
790     [o_hotkeys_listbox reloadData];
791 }
792
793 #pragma mark -
794 #pragma mark General actions
795
796 - (void)showSimplePrefs
797 {
798     /* we want to show the interface settings, if no category was chosen */
799     if ([[o_sprefs_win toolbar] selectedItemIdentifier] == nil) {
800         [[o_sprefs_win toolbar] setSelectedItemIdentifier: VLCIntfSettingToolbarIdentifier];
801         [self showInterfaceSettings];
802     }
803
804     [self resetControls];
805
806     [o_sprefs_win center];
807     [o_sprefs_win makeKeyAndOrderFront: self];
808 }
809
810 - (void)showSimplePrefsWithLevel:(NSInteger)i_window_level
811 {
812     [o_sprefs_win setLevel: i_window_level];
813     [self showSimplePrefs];
814 }
815
816 - (IBAction)buttonAction:(id)sender
817 {
818     if (sender == o_sprefs_cancel_btn) {
819         [[NSFontPanel sharedFontPanel] close];
820         [o_sprefs_win orderOut: sender];
821     } else if (sender == o_sprefs_save_btn) {
822         [self saveChangedSettings];
823         [[NSFontPanel sharedFontPanel] close];
824         [o_sprefs_win orderOut: sender];
825     } else if (sender == o_sprefs_showAll_btn) {
826         [o_sprefs_win orderOut: self];
827         [[[VLCMain sharedInstance] preferences] showPrefsWithLevel:[o_sprefs_win level]];
828     } else
829         msg_Warn(p_intf, "unknown buttonAction sender");
830 }
831
832 - (IBAction)resetPreferences:(NSControl *)sender
833 {
834     NSBeginInformationalAlertSheet(_NS("Reset Preferences"), _NS("Cancel"),
835                                    _NS("Continue"), nil, [sender window], self,
836                                    @selector(sheetDidEnd: returnCode: contextInfo:), NULL, nil, @"%@",
837                                    _NS("This will reset VLC media player's preferences.\n\n"
838                                        "Note that VLC will restart during the process, so your current "
839                                        "playlist will be emptied and eventual playback, streaming or "
840                                        "transcoding activities will stop immediately.\n\n"
841                                        "The Media Library will not be affected.\n\n"
842                                        "Are you sure you want to continue?"));
843 }
844
845 - (void)sheetDidEnd:(NSWindow *)o_sheet
846          returnCode:(int)i_return
847         contextInfo:(void *)o_context
848 {
849     if (i_return == NSAlertAlternateReturn) {
850         /* reset VLC's config */
851         config_ResetAll(p_intf);
852         [self resetControls];
853
854         /* force config file creation, since libvlc won't exit normally */
855         config_SaveConfigFile(p_intf);
856
857         /* reset OS X defaults */
858         [[VLCMain sharedInstance] resetAndReinitializeUserDefaults];
859
860         /* Relaunch now */
861         const char * path = [[[NSBundle mainBundle] executablePath] UTF8String];
862
863         /* For some reason we need to fork(), not just execl(), which reports a ENOTSUP then. */
864         if (fork() != 0) {
865             exit(0);
866             return;
867         }
868         execl(path, path, NULL);
869     }
870 }
871
872 static inline void save_int_list(intf_thread_t * p_intf, id object, const char * name)
873 {
874     NSNumber *p_valueobject = (NSNumber *)[[object selectedItem] representedObject];
875     if (p_valueobject) {
876         assert([p_valueobject isKindOfClass:[NSNumber class]]);
877         config_PutInt(p_intf, name, [p_valueobject intValue]);
878     }
879 }
880
881 static inline void save_string_list(intf_thread_t * p_intf, id object, const char * name)
882 {
883     NSString *p_stringobject = (NSString *)[[object selectedItem] representedObject];
884     if (p_stringobject) {
885         assert([p_stringobject isKindOfClass:[NSString class]]);
886         config_PutPsz(p_intf, name, [p_stringobject UTF8String]);
887     }
888 }
889
890 - (void)saveChangedSettings
891 {
892     NSString *tmpString;
893     NSRange tmpRange;
894
895 #define SaveIntList(object, name) save_int_list(p_intf, object, name)
896
897 #define SaveStringList(object, name) save_string_list(p_intf, object, name)
898 #define SaveModuleList(object, name) SaveStringList(object, name)
899
900 #define getString(name) [NSString stringWithFormat:@"%s", config_GetPsz(p_intf, name)]
901
902     /**********************
903      * interface settings *
904      **********************/
905     if (b_intfSettingChanged) {
906         NSUInteger index = [o_intf_language_pop indexOfSelectedItem];
907         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
908         [defaults setObject:[NSString stringWithUTF8String:ppsz_language[index]] forKey:@"language"];
909         [defaults synchronize];
910
911         SaveIntList(o_intf_art_pop, "album-art");
912
913         config_PutInt(p_intf, "macosx-fspanel", [o_intf_fspanel_ckb state]);
914         config_PutInt(p_intf, "embedded-video", [o_intf_embedded_ckb state]);
915
916         config_PutInt(p_intf, "macosx-appleremote", [o_intf_appleremote_ckb state]);
917         config_PutInt(p_intf, "macosx-appleremote-sysvol", [o_intf_appleremote_sysvol_ckb state]);
918         config_PutInt(p_intf, "macosx-mediakeys", [o_intf_mediakeys_ckb state]);
919         config_PutInt(p_intf, "macosx-interfacestyle", [o_intf_style_dark_bcell state]);
920         config_PutInt(p_intf, "macosx-nativefullscreenmode", [o_intf_nativefullscreen_ckb state]);
921         config_PutInt(p_intf, "macosx-pause-minimized", [o_intf_pauseminimized_ckb state]);
922         config_PutInt(p_intf, "macosx-video-autoresize", [o_intf_autoresize_ckb state]);
923         if ([o_intf_enableGrowl_ckb state] == NSOnState) {
924             tmpString = getString("control");
925             tmpRange = [tmpString rangeOfString:@"growl"];
926             if ([tmpString length] > 0 && tmpRange.location == NSNotFound)
927             {
928                 tmpString = [tmpString stringByAppendingString: @":growl"];
929                 config_PutPsz(p_intf, "control", [tmpString UTF8String]);
930             }
931             else
932                 config_PutPsz(p_intf, "control", "growl");
933         } else {
934             tmpString = getString("control");
935             if (! [tmpString isEqualToString:@""])
936             {
937                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@":growl"]];
938                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"growl:"]];
939                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"growl"]];
940                 config_PutPsz(p_intf, "control", [tmpString UTF8String]);
941             }
942         }
943         config_PutPsz(p_intf, "http-password", [[o_intf_luahttppwd_fld stringValue] UTF8String]);
944
945         SaveIntList(o_intf_pauseitunes_pop, "macosx-control-itunes");
946
947         /* activate stuff without restart */
948         if ([o_intf_appleremote_ckb state] == YES)
949             [[[VLCMain sharedInstance] appleRemoteController] startListening: [VLCMain sharedInstance]];
950         else
951             [[[VLCMain sharedInstance] appleRemoteController] stopListening: [VLCMain sharedInstance]];
952         b_intfSettingChanged = NO;
953     }
954
955     /******************
956      * audio settings *
957      ******************/
958     if (b_audioSettingChanged) {
959         config_PutInt(p_intf, "audio", [o_audio_enable_ckb state]);
960         config_PutInt(p_intf, "volume-save", [o_audio_autosavevol_yes_bcell state]);
961         var_SetBool(p_intf, "volume-save", [o_audio_autosavevol_yes_bcell state]);
962         config_PutInt(p_intf, "spdif", [o_audio_spdif_ckb state]);
963         if ([o_audio_vol_fld isEnabled])
964             config_PutInt(p_intf, "auhal-volume", ([o_audio_vol_fld intValue] * AOUT_VOLUME_MAX) / 200);
965
966         SaveIntList(o_audio_dolby_pop, "force-dolby-surround");
967
968         config_PutPsz(p_intf, "audio-language", [[o_audio_lang_fld stringValue] UTF8String]);
969
970         SaveModuleList(o_audio_visual_pop, "audio-visual");
971
972         /* Last.FM is optional */
973         if (module_exists("audioscrobbler")) {
974             [o_audio_last_ckb setEnabled: YES];
975             if ([o_audio_last_ckb state] == NSOnState)
976                 config_AddIntf(p_intf, "audioscrobbler");
977             else
978                 config_RemoveIntf(p_intf, "audioscrobbler");
979
980             config_PutPsz(p_intf, "lastfm-username", [[o_audio_lastuser_fld stringValue] UTF8String]);
981             config_PutPsz(p_intf, "lastfm-password", [[o_audio_lastpwd_sfld stringValue] UTF8String]);
982         }
983         else
984             [o_audio_last_ckb setEnabled: NO];
985         b_audioSettingChanged = NO;
986     }
987
988     /******************
989      * video settings *
990      ******************/
991     if (b_videoSettingChanged) {
992         config_PutInt(p_intf, "video", [o_video_enable_ckb state]);
993         config_PutInt(p_intf, "fullscreen", [o_video_fullscreen_ckb state]);
994         config_PutInt(p_intf, "video-deco", [o_video_videodeco_ckb state]);
995         config_PutInt(p_intf, "video-on-top", [o_video_onTop_ckb state]);
996         config_PutInt(p_intf, "skip-frames", [o_video_skipFrames_ckb state]);
997         config_PutInt(p_intf, "macosx-black", [o_video_black_ckb state]);
998
999         config_PutInt(p_intf, "macosx-vdev", [[o_video_device_pop selectedItem] tag]);
1000
1001         config_PutPsz(p_intf, "snapshot-path", [[o_video_snap_folder_fld stringValue] UTF8String]);
1002         config_PutPsz(p_intf, "snapshot-prefix", [[o_video_snap_prefix_fld stringValue] UTF8String]);
1003         config_PutInt(p_intf, "snapshot-sequential", [o_video_snap_seqnum_ckb state]);
1004         SaveStringList(o_video_snap_format_pop, "snapshot-format");
1005         SaveIntList(o_video_deinterlace_pop, "deinterlace");
1006         SaveStringList(o_video_deinterlace_mode_pop, "deinterlace-mode");
1007         b_videoSettingChanged = NO;
1008     }
1009
1010     /***************************
1011      * input & codecs settings *
1012      ***************************/
1013     if (b_inputSettingChanged) {
1014         config_PutPsz(p_intf, "input-record-path", [[o_input_record_fld stringValue] UTF8String]);
1015         config_PutInt(p_intf, "postproc-q", [o_input_postproc_fld intValue]);
1016
1017         SaveIntList(o_input_avi_pop, "avi-index");
1018
1019         config_PutInt(p_intf, "rtsp-tcp", [o_input_rtsp_ckb state]);
1020         SaveModuleList(o_input_avcodec_hw_pop, "avcodec-hw");
1021         SaveIntList(o_input_skipLoop_pop, "avcodec-skiploopfilter");
1022
1023         config_PutInt(p_intf, "mkv-preload-local-dir", [o_input_mkv_preload_dir_ckb state]);
1024
1025         #define CaC(name, factor) config_PutInt(p_intf, name, [[o_input_cachelevel_pop selectedItem] tag] * factor)
1026         if ([[o_input_cachelevel_pop selectedItem] tag] == 0) {
1027             msg_Dbg(p_intf, "Custom chosen, not adjusting cache values");
1028         } else {
1029             msg_Dbg(p_intf, "Adjusting all cache values to: %i", (int)[[o_input_cachelevel_pop selectedItem] tag]);
1030             CaC("file-caching", 1);
1031             CaC("network-caching", 10/3);
1032             CaC("disc-caching", 1);
1033             CaC("live-caching", 1);
1034         }
1035         #undef CaC
1036         b_inputSettingChanged = NO;
1037     }
1038
1039     /**********************
1040      * subtitles settings *
1041      **********************/
1042     if (b_osdSettingChanged) {
1043         config_PutInt(p_intf, "osd", [o_osd_osd_ckb state]);
1044
1045         if ([o_osd_encoding_pop indexOfSelectedItem] >= 0)
1046             SaveStringList(o_osd_encoding_pop, "subsdec-encoding");
1047         else
1048             config_PutPsz(p_intf, "subsdec-encoding", "");
1049
1050         config_PutPsz(p_intf, "sub-language", [[o_osd_lang_fld stringValue] UTF8String]);
1051
1052         config_PutPsz(p_intf, "freetype-font", [[o_osd_font_fld stringValue] UTF8String]);
1053         SaveIntList(o_osd_font_color_pop, "freetype-color");
1054         SaveIntList(o_osd_font_size_pop, "freetype-rel-fontsize");
1055         config_PutInt(p_intf, "freetype-opacity", [o_osd_opacity_fld intValue] * 255.0 / 100.0 + 0.5);
1056         config_PutInt(p_intf, "freetype-bold", [o_osd_forcebold_ckb state]);
1057         SaveIntList(o_osd_outline_color_pop, "freetype-outline-color");
1058         SaveIntList(o_osd_outline_thickness_pop, "freetype-outline-thickness");
1059         b_osdSettingChanged = NO;
1060     }
1061
1062     /********************
1063      * hotkeys settings *
1064      ********************/
1065     if (b_hotkeyChanged) {
1066         NSUInteger hotKeyCount = [o_hotkeySettings count];
1067         for (NSUInteger i = 0; i < hotKeyCount; i++)
1068             config_PutPsz(p_intf, [[o_hotkeyNames objectAtIndex:i] UTF8String], [[o_hotkeySettings objectAtIndex:i]UTF8String]);
1069         b_hotkeyChanged = NO;
1070     }
1071
1072     [[VLCCoreInteraction sharedInstance] fixPreferences];
1073
1074     /* okay, let's save our changes to vlcrc */
1075     config_SaveConfigFile(p_intf);
1076
1077     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCMediaKeySupportSettingChanged"
1078                                                             object: nil
1079                                                           userInfo: nil];
1080 }
1081
1082 - (void)showSettingsForCategory: (id)o_new_category_view
1083 {
1084     NSRect o_win_rect, o_view_rect, o_old_view_rect;
1085     o_win_rect = [o_sprefs_win frame];
1086     o_view_rect = [o_new_category_view frame];
1087
1088     if (o_currentlyShownCategoryView != nil) {
1089         /* restore our window's height, if we've shown another category previously */
1090         o_old_view_rect = [o_currentlyShownCategoryView frame];
1091         o_win_rect.size.height = o_win_rect.size.height - o_old_view_rect.size.height;
1092         o_win_rect.origin.y = (o_win_rect.origin.y + o_old_view_rect.size.height) - o_view_rect.size.height;
1093     }
1094
1095     o_win_rect.size.height = o_win_rect.size.height + o_view_rect.size.height;
1096
1097     [o_new_category_view setFrame: NSMakeRect(0,
1098                                                [o_sprefs_controls_box frame].size.height,
1099                                                o_view_rect.size.width,
1100                                                o_view_rect.size.height)];
1101     [o_new_category_view setAutoresizesSubviews: YES];
1102     if (o_currentlyShownCategoryView) {
1103         [[[o_sprefs_win contentView] animator] replaceSubview: o_currentlyShownCategoryView with: o_new_category_view];
1104         [o_currentlyShownCategoryView release];
1105         [[o_sprefs_win animator] setFrame: o_win_rect display:YES];
1106     } else {
1107         [[o_sprefs_win contentView] addSubview: o_new_category_view];
1108         [o_sprefs_win setFrame: o_win_rect display:YES animate:NO];
1109     }
1110
1111     /* keep our current category for further reference */
1112     o_currentlyShownCategoryView = o_new_category_view;
1113     [o_currentlyShownCategoryView retain];
1114 }
1115
1116 #pragma mark -
1117 #pragma mark Specific actions
1118
1119 // disables some video settings which do not work in lion mode
1120 - (void)enableLionFullscreenMode: (BOOL)b_value
1121 {
1122     [o_video_videodeco_ckb setEnabled: !b_value];
1123     [o_video_black_ckb setEnabled: !b_value];
1124
1125     if (b_value) {
1126         [o_video_videodeco_ckb setState: NSOnState];
1127         [o_video_black_ckb setState: NSOffState];
1128
1129         NSString *o_tooltipText = _NS("This setting cannot be changed because the native fullscreen mode is enabled.");
1130         [o_video_videodeco_ckb setToolTip: o_tooltipText];
1131         [o_video_black_ckb setToolTip: o_tooltipText];
1132     } else {
1133         [self setupButton: o_video_videodeco_ckb forBoolValue: "video-deco"];
1134         [self setupButton: o_video_black_ckb forBoolValue: "macosx-black"];
1135     }
1136 }
1137
1138 - (IBAction)interfaceSettingChanged:(id)sender
1139 {
1140     if (sender == o_intf_nativefullscreen_ckb)
1141         [self enableLionFullscreenMode:[sender state]];
1142
1143     b_intfSettingChanged = YES;
1144 }
1145
1146 - (void)showInterfaceSettings
1147 {
1148     [self showSettingsForCategory: o_intf_view];
1149 }
1150
1151 - (IBAction)audioSettingChanged:(id)sender
1152 {
1153     if (sender == o_audio_vol_sld)
1154         [o_audio_vol_fld setIntValue: [o_audio_vol_sld intValue]];
1155
1156     if (sender == o_audio_vol_fld)
1157         [o_audio_vol_sld setIntValue: [o_audio_vol_fld intValue]];
1158
1159     if (sender == o_audio_last_ckb) {
1160         if ([o_audio_last_ckb state] == NSOnState) {
1161             [o_audio_lastpwd_sfld setEnabled: YES];
1162             [o_audio_lastuser_fld setEnabled: YES];
1163         } else {
1164             [o_audio_lastpwd_sfld setEnabled: NO];
1165             [o_audio_lastuser_fld setEnabled: NO];
1166         }
1167     }
1168
1169     if (sender == o_audio_autosavevol_matrix) {
1170         BOOL enableVolumeSlider = [o_audio_autosavevol_matrix selectedTag] == 1;
1171         [o_audio_vol_fld setEnabled: enableVolumeSlider];
1172         [o_audio_vol_sld setEnabled: enableVolumeSlider];
1173     }
1174
1175     b_audioSettingChanged = YES;
1176 }
1177
1178 - (void)showAudioSettings
1179 {
1180     [self showSettingsForCategory: o_audio_view];
1181 }
1182
1183 - (IBAction)videoSettingChanged:(id)sender
1184 {
1185     if (sender == o_video_snap_folder_btn) {
1186         o_selectFolderPanel = [[NSOpenPanel alloc] init];
1187         [o_selectFolderPanel setCanChooseDirectories: YES];
1188         [o_selectFolderPanel setCanChooseFiles: NO];
1189         [o_selectFolderPanel setResolvesAliases: YES];
1190         [o_selectFolderPanel setAllowsMultipleSelection: NO];
1191         [o_selectFolderPanel setMessage: _NS("Choose the folder to save your video snapshots to.")];
1192         [o_selectFolderPanel setCanCreateDirectories: YES];
1193         [o_selectFolderPanel setPrompt: _NS("Choose")];
1194         [o_selectFolderPanel beginSheetModalForWindow: o_sprefs_win completionHandler: ^(NSInteger returnCode) {
1195             if (returnCode == NSOKButton)
1196             {
1197                 [o_video_snap_folder_fld setStringValue: [[o_selectFolderPanel URL] path]];
1198                 b_videoSettingChanged = YES;
1199             }
1200         }];
1201         [o_selectFolderPanel release];
1202     } else
1203         b_videoSettingChanged = YES;
1204 }
1205
1206 - (void)showVideoSettings
1207 {
1208     [self showSettingsForCategory: o_video_view];
1209 }
1210
1211 - (IBAction)osdSettingChanged:(id)sender
1212 {
1213     if (sender == o_osd_opacity_fld)
1214         [o_osd_opacity_sld setIntValue: [o_osd_opacity_fld intValue]];
1215
1216     if (sender == o_osd_opacity_sld)
1217         [o_osd_opacity_fld setIntValue: [o_osd_opacity_sld intValue]];
1218
1219     b_osdSettingChanged = YES;
1220 }
1221
1222 - (void)showOSDSettings
1223 {
1224     [self showSettingsForCategory: o_osd_view];
1225 }
1226
1227 - (void)controlTextDidChange:(NSNotification *)o_notification
1228 {
1229     id notificationObject = [o_notification object];
1230     if (notificationObject == o_audio_lang_fld ||
1231        notificationObject ==  o_audio_lastpwd_sfld ||
1232        notificationObject ==  o_audio_lastuser_fld ||
1233        notificationObject == o_audio_vol_fld)
1234         b_audioSettingChanged = YES;
1235     else if (notificationObject == o_input_record_fld ||
1236             notificationObject == o_input_postproc_fld)
1237         b_inputSettingChanged = YES;
1238     else if (notificationObject == o_osd_font_fld ||
1239             notificationObject == o_osd_lang_fld ||
1240             notificationObject == o_osd_opacity_fld)
1241         b_osdSettingChanged = YES;
1242     else if (notificationObject == o_video_snap_folder_fld ||
1243             notificationObject == o_video_snap_prefix_fld)
1244         b_videoSettingChanged = YES;
1245     else if (notificationObject == o_intf_luahttppwd_fld)
1246         b_intfSettingChanged = YES;
1247 }
1248
1249 - (IBAction)showFontPicker:(id)sender
1250 {
1251     char * font = config_GetPsz(p_intf, "freetype-font");
1252     NSString * fontName = font ? [NSString stringWithUTF8String:font] : nil;
1253     free(font);
1254     if (fontName) {
1255         NSFont * font = [NSFont fontWithName:fontName size:0.0];
1256         [[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:NO];
1257     }
1258     [[NSFontManager sharedFontManager] setTarget: self];
1259     [[NSFontPanel sharedFontPanel] orderFront:self];
1260 }
1261
1262 - (void)changeFont:(id)sender
1263 {
1264     NSFont * font = [sender convertFont:[[NSFontManager sharedFontManager] selectedFont]];
1265     [o_osd_font_fld setStringValue:[font fontName]];
1266     [self osdSettingChanged:self];
1267 }
1268
1269 - (IBAction)inputSettingChanged:(id)sender
1270 {
1271     if (sender == o_input_cachelevel_pop) {
1272         if ([[[o_input_cachelevel_pop selectedItem] title] isEqualToString: _NS("Custom")])
1273             [o_input_cachelevel_custom_txt setHidden: NO];
1274         else
1275             [o_input_cachelevel_custom_txt setHidden: YES];
1276     } else if (sender == o_input_record_btn) {
1277         o_selectFolderPanel = [[NSOpenPanel alloc] init];
1278         [o_selectFolderPanel setCanChooseDirectories: YES];
1279         [o_selectFolderPanel setCanChooseFiles: YES];
1280         [o_selectFolderPanel setResolvesAliases: YES];
1281         [o_selectFolderPanel setAllowsMultipleSelection: NO];
1282         [o_selectFolderPanel setMessage: _NS("Choose the directory or filename where the records will be stored.")];
1283         [o_selectFolderPanel setCanCreateDirectories: YES];
1284         [o_selectFolderPanel setPrompt: _NS("Choose")];
1285         [o_selectFolderPanel beginSheetModalForWindow: o_sprefs_win completionHandler: ^(NSInteger returnCode) {
1286             if (returnCode == NSOKButton)
1287             {
1288                 [o_input_record_fld setStringValue: [[o_selectFolderPanel URL] path]];
1289                 b_inputSettingChanged = YES;
1290             }
1291         }];
1292         [o_selectFolderPanel release];
1293
1294         return;
1295     }
1296
1297     b_inputSettingChanged = YES;
1298 }
1299
1300 - (void)showInputSettings
1301 {
1302     [self showSettingsForCategory: o_input_view];
1303 }
1304
1305 - (NSString *)bundleIdentifierForApplicationName:(NSString *)appName
1306 {
1307     NSWorkspace * workspace = [NSWorkspace sharedWorkspace];
1308     NSString * appPath = [workspace fullPathForApplication:appName];
1309     if (appPath) {
1310         NSBundle * appBundle = [NSBundle bundleWithPath:appPath];
1311         return [appBundle bundleIdentifier];
1312     }
1313     return nil;
1314 }
1315
1316 - (NSString *)applicationNameForBundleIdentifier:(NSString *)bundleIdentifier
1317 {
1318     return [[[NSFileManager defaultManager] displayNameAtPath:[[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:bundleIdentifier]] stringByDeletingPathExtension];
1319 }
1320
1321 - (NSImage *)iconForBundleIdentifier:(NSString *)bundleIdentifier
1322 {
1323     NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
1324     NSSize iconSize = NSMakeSize(16., 16.);
1325     NSImage *icon = [workspace iconForFile:[workspace absolutePathForAppBundleWithIdentifier:bundleIdentifier]];
1326     [icon setSize:iconSize];
1327     return icon;
1328 }
1329
1330 - (IBAction)urlHandlerAction:(id)sender
1331 {
1332     NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
1333
1334     if (sender == o_input_urlhandler_btn) {
1335         NSArray *handlers;
1336         NSString *handler;
1337         NSString *rawhandler;
1338         NSMutableArray *rawHandlers;
1339         NSUInteger count;
1340
1341 #define fillUrlHandlerPopup( protocol, object ) \
1342         handlers = (NSArray *)LSCopyAllHandlersForURLScheme(CFSTR( protocol )); \
1343         rawHandlers = [[NSMutableArray alloc] init]; \
1344         [object removeAllItems]; \
1345         count = [handlers count]; \
1346         for (NSUInteger x = 0; x < count; x++) { \
1347             rawhandler = [handlers objectAtIndex:x]; \
1348             handler = [self applicationNameForBundleIdentifier:rawhandler]; \
1349             if (handler && ![handler isEqualToString:@""]) { \
1350                 [object addItemWithTitle:handler]; \
1351                 [[object lastItem] setImage: [self iconForBundleIdentifier:[handlers objectAtIndex:x]]]; \
1352                 [rawHandlers addObject: rawhandler]; \
1353             } \
1354         } \
1355         [object selectItemAtIndex: [rawHandlers indexOfObject:(id)LSCopyDefaultHandlerForURLScheme(CFSTR( protocol ))]]; \
1356         [rawHandlers release]
1357
1358         fillUrlHandlerPopup( "ftp", o_urlhandler_ftp_pop);
1359         fillUrlHandlerPopup( "mms", o_urlhandler_mms_pop);
1360         fillUrlHandlerPopup( "rtmp", o_urlhandler_rtmp_pop);
1361         fillUrlHandlerPopup( "rtp", o_urlhandler_rtp_pop);
1362         fillUrlHandlerPopup( "rtsp", o_urlhandler_rtsp_pop);
1363         fillUrlHandlerPopup( "sftp", o_urlhandler_sftp_pop);
1364         fillUrlHandlerPopup( "smb", o_urlhandler_smb_pop);
1365         fillUrlHandlerPopup( "udp", o_urlhandler_udp_pop);
1366
1367 #undef fillUrlHandlerPopup
1368
1369         [NSApp beginSheet:o_urlhandler_win modalForWindow:o_sprefs_win modalDelegate:self didEndSelector:NULL contextInfo:nil];
1370     } else {
1371         [o_urlhandler_win orderOut:sender];
1372         [NSApp endSheet: o_urlhandler_win];
1373
1374         if (sender == o_urlhandler_save_btn) {
1375             LSSetDefaultHandlerForURLScheme(CFSTR("ftp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_ftp_pop selectedItem] title]]);
1376             LSSetDefaultHandlerForURLScheme(CFSTR("mms"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_mms_pop selectedItem] title]]);
1377             LSSetDefaultHandlerForURLScheme(CFSTR("mmsh"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_mms_pop selectedItem] title]]);
1378             LSSetDefaultHandlerForURLScheme(CFSTR("rtmp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_rtmp_pop selectedItem] title]]);
1379             LSSetDefaultHandlerForURLScheme(CFSTR("rtp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_rtp_pop selectedItem] title]]);
1380             LSSetDefaultHandlerForURLScheme(CFSTR("rtsp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_rtsp_pop selectedItem] title]]);
1381             LSSetDefaultHandlerForURLScheme(CFSTR("sftp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_sftp_pop selectedItem] title]]);
1382             LSSetDefaultHandlerForURLScheme(CFSTR("smb"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_smb_pop selectedItem] title]]);
1383             LSSetDefaultHandlerForURLScheme(CFSTR("udp"), (CFStringRef)[self bundleIdentifierForApplicationName:[[o_urlhandler_udp_pop selectedItem] title]]);
1384         }
1385     }
1386 }
1387
1388 #pragma mark -
1389 #pragma mark Hotkey actions
1390
1391 - (void)hotkeyTableDoubleClick:(id)object
1392 {
1393     // -1 is header
1394     if ([o_hotkeys_listbox clickedRow] >= 0)
1395         [self hotkeySettingChanged:o_hotkeys_listbox];
1396 }
1397
1398 - (IBAction)hotkeySettingChanged:(id)sender
1399 {
1400     if (sender == o_hotkeys_change_btn || sender == o_hotkeys_listbox) {
1401         [o_hotkeys_change_lbl setStringValue: [NSString stringWithFormat: _NS("Press new keys for\n\"%@\""),
1402                                                [o_hotkeyDescriptions objectAtIndex:[o_hotkeys_listbox selectedRow]]]];
1403         [o_hotkeys_change_keys_lbl setStringValue: [[VLCStringUtility sharedInstance] OSXStringKeyToString:[o_hotkeySettings objectAtIndex:[o_hotkeys_listbox selectedRow]]]];
1404         [o_hotkeys_change_taken_lbl setStringValue: @""];
1405         [o_hotkeys_change_win setInitialFirstResponder: [o_hotkeys_change_win contentView]];
1406         [o_hotkeys_change_win makeFirstResponder: [o_hotkeys_change_win contentView]];
1407         [NSApp runModalForWindow: o_hotkeys_change_win];
1408     } else if (sender == o_hotkeys_change_cancel_btn) {
1409         [NSApp stopModal];
1410         [o_hotkeys_change_win close];
1411     } else if (sender == o_hotkeys_change_ok_btn) {
1412         NSInteger i_returnValue;
1413         if (! o_keyInTransition) {
1414             [NSApp stopModal];
1415             [o_hotkeys_change_win close];
1416             msg_Err(p_intf, "internal error prevented the hotkey switch");
1417             return;
1418         }
1419
1420         b_hotkeyChanged = YES;
1421
1422         i_returnValue = [o_hotkeySettings indexOfObject: o_keyInTransition];
1423         if (i_returnValue != NSNotFound)
1424             [o_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]];
1425         NSString *tempString;
1426         tempString = [o_keyInTransition stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
1427         i_returnValue = [o_hotkeySettings indexOfObject: tempString];
1428         if (i_returnValue != NSNotFound)
1429             [o_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]];
1430
1431         [o_hotkeySettings replaceObjectAtIndex: [o_hotkeys_listbox selectedRow] withObject: [o_keyInTransition retain]];
1432
1433         [NSApp stopModal];
1434         [o_hotkeys_change_win close];
1435
1436         [o_hotkeys_listbox reloadData];
1437     } else if (sender == o_hotkeys_clear_btn) {
1438         [o_hotkeySettings replaceObjectAtIndex: [o_hotkeys_listbox selectedRow] withObject: [NSString string]];
1439         [o_hotkeys_listbox reloadData];
1440         b_hotkeyChanged = YES;
1441     }
1442
1443     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCMediaKeySupportSettingChanged"
1444                                                         object: nil
1445                                                       userInfo: nil];
1446 }
1447
1448 - (void)showHotkeySettings
1449 {
1450     [self showSettingsForCategory: o_hotkeys_view];
1451 }
1452
1453 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
1454 {
1455     return [o_hotkeySettings count];
1456 }
1457
1458 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
1459 {
1460     NSString * identifier = [aTableColumn identifier];
1461
1462     if ([identifier isEqualToString: @"action"])
1463         return [o_hotkeyDescriptions objectAtIndex:rowIndex];
1464     else if ([identifier isEqualToString: @"shortcut"])
1465         return [[VLCStringUtility sharedInstance] OSXStringKeyToString:[o_hotkeySettings objectAtIndex:rowIndex]];
1466     else {
1467         msg_Err(p_intf, "unknown TableColumn identifier (%s)!", [identifier UTF8String]);
1468         return NULL;
1469     }
1470 }
1471
1472 - (BOOL)changeHotkeyTo: (NSString *)theKey
1473 {
1474     NSInteger i_returnValue, i_returnValue2;
1475     i_returnValue = [o_hotkeysNonUseableKeys indexOfObject: theKey];
1476
1477     if (i_returnValue != NSNotFound || [theKey isEqualToString:@""]) {
1478         [o_hotkeys_change_keys_lbl setStringValue: _NS("Invalid combination")];
1479         [o_hotkeys_change_taken_lbl setStringValue: _NS("Regrettably, these keys cannot be assigned as hotkey shortcuts.")];
1480         [o_hotkeys_change_ok_btn setEnabled: NO];
1481         return NO;
1482     } else {
1483         [o_hotkeys_change_keys_lbl setStringValue: [[VLCStringUtility sharedInstance] OSXStringKeyToString:theKey]];
1484
1485         i_returnValue = [o_hotkeySettings indexOfObject: theKey];
1486         i_returnValue2 = [o_hotkeySettings indexOfObject: [theKey stringByReplacingOccurrencesOfString:@"-" withString:@"+"]];
1487         if (i_returnValue != NSNotFound)
1488             [o_hotkeys_change_taken_lbl setStringValue: [NSString stringWithFormat:
1489                                                          _NS("This combination is already taken by \"%@\"."),
1490                                                          [o_hotkeyDescriptions objectAtIndex:i_returnValue]]];
1491         else if (i_returnValue2 != NSNotFound)
1492             [o_hotkeys_change_taken_lbl setStringValue: [NSString stringWithFormat:
1493                                                          _NS("This combination is already taken by \"%@\"."),
1494                                                          [o_hotkeyDescriptions objectAtIndex:i_returnValue2]]];
1495         else
1496             [o_hotkeys_change_taken_lbl setStringValue: @""];
1497
1498         [o_hotkeys_change_ok_btn setEnabled: YES];
1499         [o_keyInTransition release];
1500         o_keyInTransition = theKey;
1501         [o_keyInTransition retain];
1502         return YES;
1503     }
1504 }
1505
1506 @end
1507
1508 /********************
1509  * hotkeys settings *
1510  ********************/
1511
1512 @implementation VLCHotkeyChangeWindow
1513
1514 - (BOOL)acceptsFirstResponder
1515 {
1516     return YES;
1517 }
1518
1519 - (BOOL)becomeFirstResponder
1520 {
1521     return YES;
1522 }
1523
1524 - (BOOL)resignFirstResponder
1525 {
1526     /* We need to stay the first responder or we'll miss the user's input */
1527     return NO;
1528 }
1529
1530 - (BOOL)performKeyEquivalent:(NSEvent *)o_theEvent
1531 {
1532     NSMutableString *tempString = [[[NSMutableString alloc] init] autorelease];
1533     NSString *keyString = [o_theEvent characters];
1534
1535     unichar key = [keyString characterAtIndex:0];
1536     NSUInteger i_modifiers = [o_theEvent modifierFlags];
1537
1538     /* modifiers */
1539     if (i_modifiers & NSControlKeyMask)
1540         [tempString appendString:@"Ctrl-"];
1541     if (i_modifiers & NSAlternateKeyMask )
1542         [tempString appendString:@"Alt-"];
1543     if (i_modifiers & NSShiftKeyMask)
1544         [tempString appendString:@"Shift-"];
1545     if (i_modifiers & NSCommandKeyMask)
1546         [tempString appendString:@"Command-"];
1547
1548     /* non character keys */
1549     if (key == NSUpArrowFunctionKey)
1550         [tempString appendString:@"Up"];
1551     else if (key == NSDownArrowFunctionKey)
1552         [tempString appendString:@"Down"];
1553     else if (key == NSLeftArrowFunctionKey)
1554         [tempString appendString:@"Left"];
1555     else if (key == NSRightArrowFunctionKey)
1556         [tempString appendString:@"Right"];
1557     else if (key == NSF1FunctionKey)
1558         [tempString appendString:@"F1"];
1559     else if (key == NSF2FunctionKey)
1560         [tempString appendString:@"F2"];
1561     else if (key == NSF3FunctionKey)
1562         [tempString appendString:@"F3"];
1563     else if (key == NSF4FunctionKey)
1564         [tempString appendString:@"F4"];
1565     else if (key == NSF5FunctionKey)
1566         [tempString appendString:@"F5"];
1567     else if (key == NSF6FunctionKey)
1568         [tempString appendString:@"F6"];
1569     else if (key == NSF7FunctionKey)
1570         [tempString appendString:@"F7"];
1571     else if (key == NSF8FunctionKey)
1572         [tempString appendString:@"F8"];
1573     else if (key == NSF9FunctionKey)
1574         [tempString appendString:@"F9"];
1575     else if (key == NSF10FunctionKey)
1576         [tempString appendString:@"F10"];
1577     else if (key == NSF11FunctionKey)
1578         [tempString appendString:@"F11"];
1579     else if (key == NSF12FunctionKey)
1580         [tempString appendString:@"F12"];
1581     else if (key == NSInsertFunctionKey)
1582         [tempString appendString:@"Insert"];
1583     else if (key == NSHomeFunctionKey)
1584         [tempString appendString:@"Home"];
1585     else if (key == NSEndFunctionKey)
1586         [tempString appendString:@"End"];
1587     else if (key == NSPageUpFunctionKey)
1588         [tempString appendString:@"Page Up"];
1589     else if (key == NSPageDownFunctionKey)
1590         [tempString appendString:@"Page Down"];
1591     else if (key == NSMenuFunctionKey)
1592         [tempString appendString:@"Menu"];
1593     else if (key == NSTabCharacter)
1594         [tempString appendString:@"Tab"];
1595     else if (key == NSCarriageReturnCharacter)
1596         [tempString appendString:@"Enter"];
1597     else if (key == NSEnterCharacter)
1598         [tempString appendString:@"Enter"];
1599     else if (key == NSDeleteCharacter)
1600         [tempString appendString:@"Delete"];
1601     else if (key == NSBackspaceCharacter)
1602         [tempString appendString:@"Backspace"];
1603     else if (key == 0x001B)
1604         [tempString appendString:@"Esc"];
1605     else if (key == ' ')
1606         [tempString appendString:@"Space"];
1607     else if (![[[o_theEvent charactersIgnoringModifiers] lowercaseString] isEqualToString:@""]) //plain characters
1608         [tempString appendString:[[o_theEvent charactersIgnoringModifiers] lowercaseString]];
1609     else
1610         return NO;
1611
1612     return [[[VLCMain sharedInstance] simplePreferences] changeHotkeyTo: tempString];
1613 }
1614
1615 @end
1616
1617 @implementation VLCSimplePrefsWindow
1618
1619 - (BOOL)acceptsFirstResponder
1620 {
1621     return YES;
1622 }
1623
1624 - (void)changeFont:(id)sender
1625 {
1626     [[[VLCMain sharedInstance] simplePreferences] changeFont: sender];
1627 }
1628 @end