]> git.sesse.net Git - vlc/blob - modules/gui/macosx/CoreInteraction.m
macosx: avoid possible index out of range problem in bookmarks table view
[vlc] / modules / gui / macosx / CoreInteraction.m
1 /*****************************************************************************
2  * CoreInteraction.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2011-2014 Felix Paul Kühne
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
24 #import "CoreInteraction.h"
25 #import "intf.h"
26 #import "open.h"
27 #import "playlist.h"
28 #import <math.h>
29 #import <vlc_playlist.h>
30 #import <vlc_input.h>
31 #import <vlc_keys.h>
32 #import <vlc_vout.h>
33 #import <vlc_vout_osd.h>
34 #import <vlc/vlc.h>
35 #import <vlc_strings.h>
36 #import <vlc_url.h>
37 #import <vlc_modules.h>
38 #import <vlc_charset.h>
39
40
41 @implementation VLCCoreInteraction
42 static VLCCoreInteraction *_o_sharedInstance = nil;
43
44 + (VLCCoreInteraction *)sharedInstance
45 {
46     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
47 }
48
49 #pragma mark - Initialization
50
51 - (id)init
52 {
53     if (_o_sharedInstance) {
54         [self dealloc];
55         return _o_sharedInstance;
56     } else
57         _o_sharedInstance = [super init];
58
59     return _o_sharedInstance;
60 }
61
62 - (void)dealloc
63 {
64     [[NSNotificationCenter defaultCenter] removeObserver: self];
65     [super dealloc];
66 }
67
68
69 #pragma mark - Playback Controls
70
71 - (void)playOrPause
72 {
73     input_thread_t * p_input;
74     p_input = pl_CurrentInput(VLCIntf);
75     playlist_t * p_playlist = pl_Get(VLCIntf);
76
77     if (p_input) {
78         playlist_Pause(p_playlist);
79         vlc_object_release(p_input);
80     } else {
81         bool empty;
82
83         PL_LOCK;
84         empty = playlist_IsEmpty(p_playlist);
85         PL_UNLOCK;
86
87         if ([[[VLCMain sharedInstance] playlist] isSelectionEmpty] && ([[[VLCMain sharedInstance] playlist] currentPlaylistRoot] == p_playlist->p_local_category || [[[VLCMain sharedInstance] playlist] currentPlaylistRoot] == p_playlist->p_ml_category))
88             [[[VLCMain sharedInstance] open] openFileGeneric];
89         else
90             [[[VLCMain sharedInstance] playlist] playItem:nil];
91     }
92 }
93
94 - (void)pause
95 {
96     playlist_t *p_playlist = pl_Get(VLCIntf);
97
98     PL_LOCK;
99     bool b_playlist_playing = playlist_Status(p_playlist) == PLAYLIST_RUNNING;
100     PL_UNLOCK;
101
102     if (b_playlist_playing)
103         playlist_Pause(p_playlist);
104 }
105
106 - (void)stop
107 {
108     playlist_Stop(pl_Get(VLCIntf));
109 }
110
111 - (void)faster
112 {
113     var_TriggerCallback(pl_Get(VLCIntf), "rate-faster");
114 }
115
116 - (void)slower
117 {
118     var_TriggerCallback(pl_Get(VLCIntf), "rate-slower");
119 }
120
121 - (void)normalSpeed
122 {
123     var_SetFloat(pl_Get(VLCIntf), "rate", 1.);
124 }
125
126 - (void)toggleRecord
127 {
128     intf_thread_t *p_intf = VLCIntf;
129     if (!p_intf)
130         return;
131
132     input_thread_t * p_input;
133     p_input = pl_CurrentInput(p_intf);
134     if (p_input) {
135         var_ToggleBool(p_input, "record");
136         vlc_object_release(p_input);
137     }
138 }
139
140 - (void)setPlaybackRate:(int)i_value
141 {
142     playlist_t * p_playlist = pl_Get(VLCIntf);
143
144     double speed = pow(2, (double)i_value / 17);
145     int rate = INPUT_RATE_DEFAULT / speed;
146     if (i_currentPlaybackRate != rate)
147         var_SetFloat(p_playlist, "rate", (float)INPUT_RATE_DEFAULT / (float)rate);
148     i_currentPlaybackRate = rate;
149 }
150
151 - (int)playbackRate
152 {
153     float f_rate;
154
155     intf_thread_t *p_intf = VLCIntf;
156     if (!p_intf)
157         return 0;
158
159     input_thread_t * p_input;
160     p_input = pl_CurrentInput(p_intf);
161     if (p_input) {
162         f_rate = var_GetFloat(p_input, "rate");
163         vlc_object_release(p_input);
164     }
165     else
166     {
167         playlist_t * p_playlist = pl_Get(VLCIntf);
168         f_rate = var_GetFloat(p_playlist, "rate");
169     }
170
171     double value = 17 * log(f_rate) / log(2.);
172     int returnValue = (int) ((value > 0) ? value + .5 : value - .5);
173
174     if (returnValue < -34)
175         returnValue = -34;
176     else if (returnValue > 34)
177         returnValue = 34;
178
179     i_currentPlaybackRate = returnValue;
180     return returnValue;
181 }
182
183 - (void)previous
184 {
185     playlist_Prev(pl_Get(VLCIntf));
186 }
187
188 - (void)next
189 {
190     playlist_Next(pl_Get(VLCIntf));
191 }
192
193 - (int)durationOfCurrentPlaylistItem
194 {
195     intf_thread_t *p_intf = VLCIntf;
196     if (!p_intf)
197         return 0;
198
199     input_thread_t * p_input = pl_CurrentInput(p_intf);
200     int64_t i_duration = -1;
201     if (!p_input)
202         return i_duration;
203
204     input_Control(p_input, INPUT_GET_LENGTH, &i_duration);
205     vlc_object_release(p_input);
206
207     return (int)(i_duration / 1000000);
208 }
209
210 - (NSURL*)URLOfCurrentPlaylistItem
211 {
212     intf_thread_t *p_intf = VLCIntf;
213     if (!p_intf)
214         return nil;
215
216     input_thread_t *p_input = pl_CurrentInput(p_intf);
217     if (!p_input)
218         return nil;
219
220     input_item_t *p_item = input_GetItem(p_input);
221     if (!p_item) {
222         vlc_object_release(p_input);
223         return nil;
224     }
225
226     char *psz_uri = input_item_GetURI(p_item);
227     if (!psz_uri) {
228         vlc_object_release(p_input);
229         return nil;
230     }
231
232     NSURL *o_url;
233     o_url = [NSURL URLWithString:[NSString stringWithUTF8String:psz_uri]];
234     vlc_object_release(p_input);
235
236     return o_url;
237 }
238
239 - (NSString*)nameOfCurrentPlaylistItem
240 {
241     intf_thread_t *p_intf = VLCIntf;
242     if (!p_intf)
243         return nil;
244
245     input_thread_t *p_input = pl_CurrentInput(p_intf);
246     if (!p_input)
247         return nil;
248
249     input_item_t *p_item = input_GetItem(p_input);
250     if (!p_item) {
251         vlc_object_release(p_input);
252         return nil;
253     }
254
255     char *psz_uri = input_item_GetURI(p_item);
256     if (!psz_uri) {
257         vlc_object_release(p_input);
258         return nil;
259     }
260
261     NSString *o_name;
262     char *format = var_InheritString(VLCIntf, "input-title-format");
263     char *formated = str_format_meta(p_input, format);
264     free(format);
265     o_name = [NSString stringWithUTF8String:formated];
266     free(formated);
267
268     NSURL * o_url = [NSURL URLWithString:[NSString stringWithUTF8String:psz_uri]];
269     free(psz_uri);
270
271     if ([o_name isEqualToString:@""]) {
272         if ([o_url isFileURL])
273             o_name = [[NSFileManager defaultManager] displayNameAtPath:[o_url path]];
274         else
275             o_name = [o_url absoluteString];
276     }
277     vlc_object_release(p_input);
278     return o_name;
279 }
280
281 - (void)forward
282 {
283     //LEGACY SUPPORT
284     [self forwardShort];
285 }
286
287 - (void)backward
288 {
289     //LEGACY SUPPORT
290     [self backwardShort];
291 }
292
293 - (void)jumpWithValue:(char *)p_value forward:(BOOL)b_value
294 {
295     input_thread_t *p_input = pl_CurrentInput(VLCIntf);
296     if (!p_input)
297         return;
298
299     int i_interval = var_InheritInteger( p_input, p_value );
300     if (i_interval > 0) {
301         mtime_t val = CLOCK_FREQ * i_interval;
302         if (!b_value)
303             val = val * -1;
304         var_SetTime( p_input, "time-offset", val );
305     }
306     vlc_object_release(p_input);
307 }
308
309 - (void)forwardExtraShort
310 {
311     [self jumpWithValue:"extrashort-jump-size" forward:YES];
312 }
313
314 - (void)backwardExtraShort
315 {
316     [self jumpWithValue:"extrashort-jump-size" forward:NO];
317 }
318
319 - (void)forwardShort
320 {
321     [self jumpWithValue:"short-jump-size" forward:YES];
322 }
323
324 - (void)backwardShort
325 {
326     [self jumpWithValue:"short-jump-size" forward:NO];
327 }
328
329 - (void)forwardMedium
330 {
331     [self jumpWithValue:"medium-jump-size" forward:YES];
332 }
333
334 - (void)backwardMedium
335 {
336     [self jumpWithValue:"medium-jump-size" forward:NO];
337 }
338
339 - (void)forwardLong
340 {
341     [self jumpWithValue:"long-jump-size" forward:YES];
342 }
343
344 - (void)backwardLong
345 {
346     [self jumpWithValue:"long-jump-size" forward:NO];
347 }
348
349 - (void)shuffle
350 {
351     intf_thread_t *p_intf = VLCIntf;
352     if (!p_intf)
353         return;
354
355     vlc_value_t val;
356     playlist_t * p_playlist = pl_Get(p_intf);
357     vout_thread_t *p_vout = getVout();
358
359     var_Get(p_playlist, "random", &val);
360     val.b_bool = !val.b_bool;
361     var_Set(p_playlist, "random", val);
362     if (val.b_bool) {
363         if (p_vout) {
364             vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random On"));
365             vlc_object_release(p_vout);
366         }
367         config_PutInt(p_playlist, "random", 1);
368     }
369     else
370     {
371         if (p_vout) {
372             vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Random Off"));
373             vlc_object_release(p_vout);
374         }
375         config_PutInt(p_playlist, "random", 0);
376     }
377 }
378
379 - (void)repeatAll
380 {
381     intf_thread_t *p_intf = VLCIntf;
382     if (!p_intf)
383         return;
384
385     playlist_t * p_playlist = pl_Get(p_intf);
386
387     var_SetBool(p_playlist, "repeat", NO);
388     var_SetBool(p_playlist, "loop", YES);
389     config_PutInt(p_playlist, "repeat", NO);
390     config_PutInt(p_playlist, "loop", YES);
391
392     vout_thread_t *p_vout = getVout();
393     if (p_vout) {
394         vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat All"));
395         vlc_object_release(p_vout);
396     }
397 }
398
399 - (void)repeatOne
400 {
401     intf_thread_t *p_intf = VLCIntf;
402     if (!p_intf)
403         return;
404
405     playlist_t * p_playlist = pl_Get(p_intf);
406
407     var_SetBool(p_playlist, "repeat", YES);
408     var_SetBool(p_playlist, "loop", NO);
409     config_PutInt(p_playlist, "repeat", YES);
410     config_PutInt(p_playlist, "loop", NO);
411
412     vout_thread_t *p_vout = getVout();
413     if (p_vout) {
414         vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat One"));
415         vlc_object_release(p_vout);
416     }
417 }
418
419 - (void)repeatOff
420 {
421     intf_thread_t *p_intf = VLCIntf;
422     if (!p_intf)
423         return;
424
425     playlist_t * p_playlist = pl_Get(p_intf);
426
427     var_SetBool(p_playlist, "repeat", NO);
428     var_SetBool(p_playlist, "loop", NO);
429     config_PutInt(p_playlist, "repeat", NO);
430     config_PutInt(p_playlist, "loop", NO);
431
432     vout_thread_t *p_vout = getVout();
433     if (p_vout) {
434         vout_OSDMessage(p_vout, SPU_DEFAULT_CHANNEL, "%s", _("Repeat Off"));
435         vlc_object_release(p_vout);
436     }
437 }
438
439 - (void)setAtoB
440 {
441     if (!timeA) {
442         input_thread_t * p_input = pl_CurrentInput(VLCIntf);
443         if (p_input) {
444             timeA = var_GetTime(p_input, "time");
445             vlc_object_release(p_input);
446         }
447     } else if (!timeB) {
448         input_thread_t * p_input = pl_CurrentInput(VLCIntf);
449         if (p_input) {
450             timeB = var_GetTime(p_input, "time");
451             vlc_object_release(p_input);
452         }
453     } else
454         [self resetAtoB];
455 }
456
457 - (void)resetAtoB
458 {
459     timeA = 0;
460     timeB = 0;
461 }
462
463 - (void)updateAtoB
464 {
465     if (timeB) {
466         input_thread_t * p_input = pl_CurrentInput(VLCIntf);
467         if (p_input) {
468             mtime_t currentTime = var_GetTime(p_input, "time");
469             if ( currentTime >= timeB || currentTime < timeA)
470                 var_SetTime(p_input, "time", timeA);
471             vlc_object_release(p_input);
472         }
473     }
474 }
475
476 - (void)volumeUp
477 {
478     intf_thread_t *p_intf = VLCIntf;
479     if (!p_intf)
480         return;
481
482     playlist_VolumeUp(pl_Get(p_intf), 1, NULL);
483 }
484
485 - (void)volumeDown
486 {
487     intf_thread_t *p_intf = VLCIntf;
488     if (!p_intf)
489         return;
490
491     playlist_VolumeDown(pl_Get(p_intf), 1, NULL);
492 }
493
494 - (void)toggleMute
495 {
496     intf_thread_t *p_intf = VLCIntf;
497     if (!p_intf)
498         return;
499
500     playlist_MuteToggle(pl_Get(p_intf));
501 }
502
503 - (BOOL)mute
504 {
505     intf_thread_t *p_intf = VLCIntf;
506     if (!p_intf)
507         return NO;
508
509     BOOL b_is_muted = NO;
510     b_is_muted = playlist_MuteGet(pl_Get(p_intf)) > 0;
511
512     return b_is_muted;
513 }
514
515 - (int)volume
516 {
517     intf_thread_t *p_intf = VLCIntf;
518     if (!p_intf)
519         return 0;
520
521     float volume = playlist_VolumeGet(pl_Get(p_intf));
522
523     return lroundf(volume * AOUT_VOLUME_DEFAULT);
524 }
525
526 - (void)setVolume: (int)i_value
527 {
528     intf_thread_t *p_intf = VLCIntf;
529     if (!p_intf)
530         return;
531
532     if (i_value >= self.maxVolume)
533         i_value = self.maxVolume;
534
535     float f_value = i_value / (float)AOUT_VOLUME_DEFAULT;
536
537     playlist_VolumeSet(pl_Get(p_intf), f_value);
538 }
539
540 - (float)maxVolume
541 {
542     if (f_maxVolume == 0.) {
543         f_maxVolume = (float)var_InheritInteger(VLCIntf, "macosx-max-volume") / 100. * AOUT_VOLUME_DEFAULT;
544     }
545
546     return f_maxVolume;
547 }
548
549 - (void)addSubtitlesToCurrentInput:(NSArray *)paths
550 {
551     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
552     if (!p_input)
553         return;
554
555     NSUInteger count = [paths count];
556
557     for (int i = 0; i < count ; i++) {
558         const char *path = [[[paths objectAtIndex:i] path] UTF8String];
559         msg_Dbg(VLCIntf, "loading subs from %s", path);
560
561         int i_result = input_AddSubtitleOSD(p_input, path, true, true);
562         if (i_result != VLC_SUCCESS)
563             msg_Warn(VLCIntf, "unable to load subtitles from '%s'", path);
564     }
565     vlc_object_release(p_input);
566 }
567
568 #pragma mark - drag and drop support for VLCVoutView, VLCDragDropView and VLCThreePartDropView
569 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
570 {
571     NSPasteboard *o_paste = [sender draggingPasteboard];
572     NSArray *o_types = [NSArray arrayWithObject:NSFilenamesPboardType];
573     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
574     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
575     BOOL b_autoplay = config_GetInt(VLCIntf, "macosx-autoplay");
576
577     if (o_carried_data) {
578         if ([o_desired_type isEqualToString:NSFilenamesPboardType]) {
579             NSArray *o_array = [NSArray array];
580             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
581             NSUInteger count = [o_values count];
582
583             input_thread_t * p_input = pl_CurrentInput(VLCIntf);
584
585             if (count == 1 && p_input) {
586                 int i_result = input_AddSubtitleOSD(p_input, [[o_values objectAtIndex:0] UTF8String], true, true);
587                 vlc_object_release(p_input);
588                 if (i_result == VLC_SUCCESS)
589                     return YES;
590             }
591             else if (p_input)
592                 vlc_object_release(p_input);
593
594             for (NSUInteger i = 0; i < count; i++) {
595                 NSDictionary *o_dic;
596                 char *psz_uri = vlc_path2uri([[o_values objectAtIndex:i] UTF8String], NULL);
597                 if (!psz_uri)
598                     continue;
599
600                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
601                 free(psz_uri);
602
603                 o_array = [o_array arrayByAddingObject: o_dic];
604             }
605             if (b_autoplay)
606                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
607             else
608                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
609
610             return YES;
611         }
612     }
613     return NO;
614 }
615
616 #pragma mark - video output stuff
617
618 - (void)setAspectRatioIsLocked:(BOOL)b_value
619 {
620     config_PutInt(VLCIntf, "macosx-lock-aspect-ratio", b_value);
621 }
622
623 - (BOOL)aspectRatioIsLocked
624 {
625     return config_GetInt(VLCIntf, "macosx-lock-aspect-ratio");
626 }
627
628 - (void)toggleFullscreen
629 {
630     intf_thread_t *p_intf = VLCIntf;
631     if (!p_intf)
632         return;
633
634     vout_thread_t *p_vout = getVoutForActiveWindow();
635     if (p_vout) {
636         BOOL b_fs = var_ToggleBool(p_vout, "fullscreen");
637         var_SetBool(pl_Get(p_intf), "fullscreen", b_fs);
638         vlc_object_release(p_vout);
639     } else { // e.g. lion fullscreen toggle
640         BOOL b_fs = var_ToggleBool(pl_Get(p_intf), "fullscreen");
641         [[[VLCMain sharedInstance] voutController] setFullscreen:b_fs forWindow:nil withAnimation:YES];
642     }
643 }
644
645 #pragma mark - uncommon stuff
646
647 - (BOOL)fixPreferences
648 {
649     NSMutableString * o_workString;
650     NSRange returnedRange;
651     NSRange fullRange;
652     BOOL b_needsRestart = NO;
653
654     #define fixpref(pref) \
655     o_workString = [[NSMutableString alloc] initWithFormat:@"%s", config_GetPsz(VLCIntf, pref)]; \
656     if ([o_workString length] > 0) \
657     { \
658         returnedRange = [o_workString rangeOfString:@"macosx" options: NSCaseInsensitiveSearch]; \
659         if (returnedRange.location != NSNotFound) \
660         { \
661             if ([o_workString isEqualToString:@"macosx"]) \
662                 [o_workString setString:@""]; \
663             fullRange = NSMakeRange(0, [o_workString length]); \
664             [o_workString replaceOccurrencesOfString:@":macosx" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
665             fullRange = NSMakeRange(0, [o_workString length]); \
666             [o_workString replaceOccurrencesOfString:@"macosx:" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
667             \
668             config_PutPsz(VLCIntf, pref, [o_workString UTF8String]); \
669             b_needsRestart = YES; \
670         } \
671     } \
672     [o_workString release]
673
674     fixpref("control");
675     fixpref("extraintf");
676     #undef fixpref
677
678     return b_needsRestart;
679 }
680
681 #pragma mark - video filter handling
682
683 - (const char *)getFilterType:(const char *)psz_name
684 {
685     module_t *p_obj = module_find(psz_name);
686     if (!p_obj) {
687         return NULL;
688     }
689
690     if (module_provides(p_obj, "video splitter")) {
691         return "video-splitter";
692     } else if (module_provides(p_obj, "video filter2")) {
693         return "video-filter";
694     } else if (module_provides(p_obj, "sub source")) {
695         return "sub-source";
696     } else if (module_provides(p_obj, "sub filter")) {
697         return "sub-filter";
698     } else {
699         msg_Err(VLCIntf, "Unknown video filter type.");
700         return NULL;
701     }
702 }
703
704 - (void)setVideoFilter: (const char *)psz_name on:(BOOL)b_on
705 {
706     intf_thread_t *p_intf = VLCIntf;
707     if (!p_intf)
708         return;
709     char *psz_string, *psz_parser;
710
711     const char *psz_filter_type = [self getFilterType:psz_name];
712     if (!psz_filter_type) {
713         msg_Err(p_intf, "Unable to find filter module \"%s\".", psz_name);
714         return;
715     }
716
717     msg_Dbg(p_intf, "will set filter '%s'", psz_name);
718
719
720     psz_string = config_GetPsz(p_intf, psz_filter_type);
721
722     if (b_on) {
723         if (psz_string == NULL) {
724             psz_string = strdup(psz_name);
725         } else if (strstr(psz_string, psz_name) == NULL) {
726             char *psz_tmp = strdup([[NSString stringWithFormat: @"%s:%s", psz_string, psz_name] UTF8String]);
727             free(psz_string);
728             psz_string = psz_tmp;
729         }
730     } else {
731         if (!psz_string)
732             return;
733
734         psz_parser = strstr(psz_string, psz_name);
735         if (psz_parser) {
736             if (*(psz_parser + strlen(psz_name)) == ':') {
737                 memmove(psz_parser, psz_parser + strlen(psz_name) + 1,
738                         strlen(psz_parser + strlen(psz_name) + 1) + 1);
739             } else {
740                 *psz_parser = '\0';
741             }
742
743             /* Remove trailing : : */
744             if (strlen(psz_string) > 0 && *(psz_string + strlen(psz_string) -1) == ':')
745                 *(psz_string + strlen(psz_string) -1) = '\0';
746         } else {
747             free(psz_string);
748             return;
749         }
750     }
751     config_PutPsz(p_intf, psz_filter_type, psz_string);
752
753     /* Try to set on the fly */
754     if (!strcmp(psz_filter_type, "video-splitter")) {
755         playlist_t *p_playlist = pl_Get(p_intf);
756         var_SetString(p_playlist, psz_filter_type, psz_string);
757     } else {
758         vout_thread_t *p_vout = getVout();
759         if (p_vout) {
760             var_SetString(p_vout, psz_filter_type, psz_string);
761             vlc_object_release(p_vout);
762         }
763     }
764
765     free(psz_string);
766 }
767
768 - (void)restartFilterIfNeeded: (const char *)psz_filter option: (const char *)psz_name
769 {
770     vout_thread_t *p_vout = getVout();
771     intf_thread_t *p_intf = VLCIntf;
772     if (!p_intf)
773         return;
774
775     if (p_vout == NULL)
776         return;
777     else
778         vlc_object_release(p_vout);
779
780     vlc_object_t *p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
781     if (p_filter) {
782
783         /* we cannot rely on the p_filter existence.
784          This filter might be just
785          disabled, but the object still exists. Therefore, the string
786          is checked, additionally.
787          */
788         const char *psz_filter_type = [self getFilterType:psz_filter];
789         if (!psz_filter_type) {
790             msg_Err(p_intf, "Unable to find filter module \"%s\".", psz_name);
791             goto out;
792         }
793
794         char *psz_string = config_GetPsz(p_intf, psz_filter_type);
795         if (!psz_string) {
796             goto out;
797         }
798         if (strstr(psz_string, psz_filter) == NULL) {
799             free(psz_string);
800             goto out;
801         }
802         free(psz_string);
803
804         int i_type;
805         i_type = var_Type(p_filter, psz_name);
806         if (i_type == 0)
807             i_type = config_GetType(p_intf, psz_name);
808
809         if (!(i_type & VLC_VAR_ISCOMMAND)) {
810             msg_Warn(p_intf, "Brute-restarting filter '%s', because the last changed option isn't a command", psz_name);
811
812             [self setVideoFilter: psz_filter on: NO];
813             [self setVideoFilter: psz_filter on: YES];
814         } else
815             msg_Dbg(p_intf, "restart not needed");
816
817         out:
818         vlc_object_release(p_filter);
819     }
820 }
821
822 - (void)setVideoFilterProperty: (const char *)psz_name forFilter: (const char *)psz_filter integer: (int)i_value
823 {
824     vout_thread_t *p_vout = getVout();
825     vlc_object_t *p_filter;
826     intf_thread_t *p_intf = VLCIntf;
827     if (!p_intf)
828         return;
829
830     config_PutInt(p_intf, psz_name, i_value);
831
832     if (p_vout) {
833         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
834
835         if (!p_filter) {
836             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
837             vlc_object_release(p_vout);
838             return;
839         }
840         var_SetInteger(p_filter, psz_name, i_value);
841         vlc_object_release(p_vout);
842         vlc_object_release(p_filter);
843
844         [self restartFilterIfNeeded: psz_filter option: psz_name];
845     }
846 }
847
848 - (void)setVideoFilterProperty: (const char *)psz_name forFilter: (const char *)psz_filter float: (float)f_value
849 {
850     vout_thread_t *p_vout = getVout();
851     vlc_object_t *p_filter;
852     intf_thread_t *p_intf = VLCIntf;
853     if (!p_intf)
854         return;
855
856     config_PutFloat(p_intf, psz_name, f_value);
857
858     if (p_vout) {
859         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
860
861         if (!p_filter) {
862             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
863             vlc_object_release(p_vout);
864             return;
865         }
866         var_SetFloat(p_filter, psz_name, f_value);
867         vlc_object_release(p_vout);
868         vlc_object_release(p_filter);
869
870         [self restartFilterIfNeeded: psz_filter option: psz_name];
871     }
872 }
873
874 - (void)setVideoFilterProperty: (const char *)psz_name forFilter: (const char *)psz_filter string: (const char *)psz_value
875 {
876     char *psz_new_value = strdup(psz_value);
877     vout_thread_t *p_vout = getVout();
878     vlc_object_t *p_filter;
879     intf_thread_t *p_intf = VLCIntf;
880     if (!p_intf)
881         return;
882
883     config_PutPsz(p_intf, psz_name, EnsureUTF8(psz_new_value));
884
885     if (p_vout) {
886         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
887
888         if (!p_filter) {
889             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
890             vlc_object_release(p_vout);
891             return;
892         }
893         var_SetString(p_filter, psz_name, EnsureUTF8(psz_new_value));
894         vlc_object_release(p_vout);
895         vlc_object_release(p_filter);
896
897         [self restartFilterIfNeeded: psz_filter option: psz_name];
898     }
899
900     free(psz_new_value);
901 }
902
903 - (void)setVideoFilterProperty: (const char *)psz_name forFilter: (const char *)psz_filter boolean: (BOOL)b_value
904 {
905     vout_thread_t *p_vout = getVout();
906     vlc_object_t *p_filter;
907     intf_thread_t *p_intf = VLCIntf;
908     if (!p_intf)
909         return;
910
911     config_PutInt(p_intf, psz_name, b_value);
912
913     if (p_vout) {
914         p_filter = vlc_object_find_name(pl_Get(p_intf), psz_filter);
915
916         if (!p_filter) {
917             msg_Warn(p_intf, "filter '%s' isn't enabled", psz_filter);
918             vlc_object_release(p_vout);
919             return;
920         }
921         var_SetBool(p_filter, psz_name, b_value);
922         vlc_object_release(p_vout);
923         vlc_object_release(p_filter);
924     }
925 }
926
927 @end