VLCCoreInteraction.m 34.6 KB
Newer Older
1 2 3
/*****************************************************************************
 * CoreInteraction.m: MacOS X interface module
 *****************************************************************************
4
 * Copyright (C) 2011-2015 Felix Paul Kühne
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * $Id$
 *
 * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

24
#import "VLCCoreInteraction.h"
25
#import "VLCMain.h"
26
#import "VLCOpenWindowController.h"
27
#import "VLCPlaylist.h"
28
#import <math.h>
29 30 31
#import <vlc_playlist.h>
#import <vlc_input.h>
#import <vlc_keys.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
32 33
#import <vlc_vout.h>
#import <vlc_vout_osd.h>
34 35
#import <vlc/vlc.h>
#import <vlc_strings.h>
36
#import <vlc_url.h>
37 38
#import <vlc_modules.h>
#import <vlc_charset.h>
39 40 41
#include <vlc_plugin.h>
#import "SPMediaKeyTap.h"
#import "AppleRemote.h"
42
#import "VLCInputManager.h"
43

44 45
#import "NSSound+VLCAdditions.h"

46 47 48 49 50 51 52 53 54 55 56 57
static int BossCallback(vlc_object_t *p_this, const char *psz_var,
                        vlc_value_t oldval, vlc_value_t new_val, void *param)
{
    @autoreleasepool {
        dispatch_async(dispatch_get_main_queue(), ^{
            [[VLCCoreInteraction sharedInstance] pause];
            [[NSApplication sharedApplication] hide:nil];
        });

        return VLC_SUCCESS;
    }
}
58

59 60 61 62 63 64
@interface VLCCoreInteraction ()
{
    int i_currentPlaybackRate;
    mtime_t timeA, timeB;

    float f_maxVolume;
65 66 67 68 69 70 71 72 73 74 75

    /* media key support */
    BOOL b_mediaKeySupport;
    BOOL b_mediakeyJustJumped;
    SPMediaKeyTap *_mediaKeyController;
    BOOL b_mediaKeyTrapEnabled;

    AppleRemote *_remote;
    BOOL b_remote_button_hold; /* true as long as the user holds the left,right,plus or minus on the remote control */

    NSArray *_usedHotkeys;
76 77
}
@end
78

79 80
@implementation VLCCoreInteraction

81
#pragma mark - Initialization
82

83
+ (VLCCoreInteraction *)sharedInstance
84
{
85 86 87 88 89 90
    static VLCCoreInteraction *sharedInstance = nil;
    static dispatch_once_t pred;

    dispatch_once(&pred, ^{
        sharedInstance = [VLCCoreInteraction new];
    });
91

92
    return sharedInstance;
93 94
}

95 96 97 98
- (instancetype)init
{
    self = [super init];
    if (self) {
99
        intf_thread_t *p_intf = getIntf();
100 101 102 103 104 105 106 107 108

        /* init media key support */
        b_mediaKeySupport = var_InheritBool(p_intf, "macosx-mediakeys");
        if (b_mediaKeySupport) {
            _mediaKeyController = [[SPMediaKeyTap alloc] initWithDelegate:self];
            [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
                                                                     [SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers], kMediaKeyUsingBundleIdentifiersDefaultsKey,
                                                                     nil]];
        }
109
        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(coreChangedMediaKeySupportSetting:) name:VLCMediaKeySupportSettingChangedNotification object: nil];
110 111 112 113 114 115

        /* init Apple Remote support */
        _remote = [[AppleRemote alloc] init];
        [_remote setClickCountEnabledButtons: kRemoteButtonPlay];
        [_remote setDelegate: self];

116
        var_AddCallback(p_intf->obj.libvlc, "intf-boss", BossCallback, (__bridge void *)self);
117 118 119 120
    }
    return self;
}

121 122
- (void)dealloc
{
123
    intf_thread_t *p_intf = getIntf();
124
    var_DelCallback(p_intf->obj.libvlc, "intf-boss", BossCallback, (__bridge void *)self);
125 126 127 128
    [[NSNotificationCenter defaultCenter] removeObserver: self];
}


129
#pragma mark - Playback Controls
130

131
- (void)playOrPause
132
{
133 134
    input_thread_t *p_input = pl_CurrentInput(getIntf());
    playlist_t *p_playlist = pl_Get(getIntf());
135

136
    if (p_input) {
137
        playlist_TogglePause(p_playlist);
138
        vlc_object_release(p_input);
139

140
    } else {
141 142
        PLRootType root = [[[[VLCMain sharedInstance] playlist] model] currentRootType];
        if ([[[VLCMain sharedInstance] playlist] isSelectionEmpty] && (root == ROOT_TYPE_PLAYLIST || root == ROOT_TYPE_MEDIALIBRARY))
143 144 145 146
            [[[VLCMain sharedInstance] open] openFileGeneric];
        else
            [[[VLCMain sharedInstance] playlist] playItem:nil];
    }
147 148
}

149 150
- (void)pause
{
151
    playlist_t *p_playlist = pl_Get(getIntf());
152

153
    playlist_Pause(p_playlist);
154 155
}

156 157
- (void)stop
{
158
    playlist_Stop(pl_Get(getIntf()));
159 160 161 162
}

- (void)faster
{
163
    var_TriggerCallback(pl_Get(getIntf()), "rate-faster");
164 165 166 167
}

- (void)slower
{
168
    var_TriggerCallback(pl_Get(getIntf()), "rate-slower");
169 170 171 172
}

- (void)normalSpeed
{
173
    var_SetFloat(pl_Get(getIntf()), "rate", 1.);
174 175
}

176 177
- (void)toggleRecord
{
178
    intf_thread_t *p_intf = getIntf();
179
    if (!p_intf)
180
        return;
181

182
    input_thread_t * p_input;
183 184 185 186
    p_input = pl_CurrentInput(p_intf);
    if (p_input) {
        var_ToggleBool(p_input, "record");
        vlc_object_release(p_input);
187 188 189
    }
}

190 191
- (void)setPlaybackRate:(int)i_value
{
192
    playlist_t * p_playlist = pl_Get(getIntf());
193

194
    double speed = pow(2, (double)i_value / 17);
195
    int rate = INPUT_RATE_DEFAULT / speed;
196 197
    if (i_currentPlaybackRate != rate)
        var_SetFloat(p_playlist, "rate", (float)INPUT_RATE_DEFAULT / (float)rate);
198 199 200 201 202
    i_currentPlaybackRate = rate;
}

- (int)playbackRate
{
203 204
    float f_rate;

205
    intf_thread_t *p_intf = getIntf();
206
    if (!p_intf)
207
        return 0;
208

209
    input_thread_t * p_input;
210 211 212 213
    p_input = pl_CurrentInput(p_intf);
    if (p_input) {
        f_rate = var_GetFloat(p_input, "rate");
        vlc_object_release(p_input);
214 215 216
    }
    else
    {
217
        playlist_t * p_playlist = pl_Get(getIntf());
218
        f_rate = var_GetFloat(p_playlist, "rate");
219
    }
220

221 222
    double value = 17 * log(f_rate) / log(2.);
    int returnValue = (int) ((value > 0) ? value + .5 : value - .5);
223

224
    if (returnValue < -34)
225
        returnValue = -34;
226
    else if (returnValue > 34)
227
        returnValue = 34;
228

229 230 231 232
    i_currentPlaybackRate = returnValue;
    return returnValue;
}

233 234
- (void)previous
{
235
    playlist_Prev(pl_Get(getIntf()));
236 237 238 239
}

- (void)next
{
240
    playlist_Next(pl_Get(getIntf()));
241 242
}

243 244
- (int)durationOfCurrentPlaylistItem
{
245
    intf_thread_t *p_intf = getIntf();
246
    if (!p_intf)
247
        return 0;
248

249
    input_thread_t * p_input = pl_CurrentInput(p_intf);
250
    int64_t i_duration = -1;
251
    if (!p_input)
252
        return i_duration;
253

254 255
    input_Control(p_input, INPUT_GET_LENGTH, &i_duration);
    vlc_object_release(p_input);
256

257
    return (int)(i_duration / 1000000);
258 259 260 261
}

- (NSURL*)URLOfCurrentPlaylistItem
{
262
    intf_thread_t *p_intf = getIntf();
263
    if (!p_intf)
264
        return nil;
265

266 267
    input_thread_t *p_input = pl_CurrentInput(p_intf);
    if (!p_input)
268
        return nil;
269

270 271 272
    input_item_t *p_item = input_GetItem(p_input);
    if (!p_item) {
        vlc_object_release(p_input);
273 274
        return nil;
    }
275

276 277 278
    char *psz_uri = input_item_GetURI(p_item);
    if (!psz_uri) {
        vlc_object_release(p_input);
279 280
        return nil;
    }
281 282

    NSURL *o_url;
283
    o_url = [NSURL URLWithString:toNSStr(psz_uri)];
284
    vlc_object_release(p_input);
285 286

    return o_url;
287 288 289 290
}

- (NSString*)nameOfCurrentPlaylistItem
{
291
    intf_thread_t *p_intf = getIntf();
292
    if (!p_intf)
293
        return nil;
294

295 296
    input_thread_t *p_input = pl_CurrentInput(p_intf);
    if (!p_input)
297
        return nil;
298

299 300 301
    input_item_t *p_item = input_GetItem(p_input);
    if (!p_item) {
        vlc_object_release(p_input);
302 303
        return nil;
    }
304

305 306 307
    char *psz_uri = input_item_GetURI(p_item);
    if (!psz_uri) {
        vlc_object_release(p_input);
308 309
        return nil;
    }
310

311
    NSString *o_name = @"";
312
    char *format = var_InheritString(getIntf(), "input-title-format");
313
    if (format) {
314
        char *formated = vlc_strfinput(p_input, format);
315 316 317 318
        free(format);
        o_name = toNSStr(formated);
        free(formated);
    }
319

320
    NSURL * o_url = [NSURL URLWithString:toNSStr(psz_uri)];
321
    free(psz_uri);
322

323 324
    if ([o_name isEqualToString:@""]) {
        if ([o_url isFileURL])
325
            o_name = [[NSFileManager defaultManager] displayNameAtPath:[o_url path]];
326 327 328
        else
            o_name = [o_url absoluteString];
    }
329
    vlc_object_release(p_input);
330
    return o_name;
331 332
}

333 334
- (void)forward
{
335 336
    //LEGACY SUPPORT
    [self forwardShort];
337 338 339 340
}

- (void)backward
{
341 342
    //LEGACY SUPPORT
    [self backwardShort];
343 344
}

345 346
- (void)jumpWithValue:(char *)p_value forward:(BOOL)b_value
{
347
    input_thread_t *p_input = pl_CurrentInput(getIntf());
348 349 350 351 352 353 354 355
    if (!p_input)
        return;

    int i_interval = var_InheritInteger( p_input, p_value );
    if (i_interval > 0) {
        mtime_t val = CLOCK_FREQ * i_interval;
        if (!b_value)
            val = val * -1;
356
        var_SetInteger( p_input, "time-offset", val );
357 358 359 360
    }
    vlc_object_release(p_input);
}

361
- (void)forwardExtraShort
362
{
363
    [self jumpWithValue:"extrashort-jump-size" forward:YES];
364
}
365

366 367
- (void)backwardExtraShort
{
368
    [self jumpWithValue:"extrashort-jump-size" forward:NO];
369 370 371 372
}

- (void)forwardShort
{
373
    [self jumpWithValue:"short-jump-size" forward:YES];
374 375 376 377
}

- (void)backwardShort
{
378
    [self jumpWithValue:"short-jump-size" forward:NO];
379 380 381 382
}

- (void)forwardMedium
{
383
    [self jumpWithValue:"medium-jump-size" forward:YES];
384 385 386 387
}

- (void)backwardMedium
{
388
    [self jumpWithValue:"medium-jump-size" forward:NO];
389 390 391 392
}

- (void)forwardLong
{
393
    [self jumpWithValue:"long-jump-size" forward:YES];
394 395 396 397
}

- (void)backwardLong
{
398
    [self jumpWithValue:"long-jump-size" forward:NO];
399 400 401 402
}

- (void)shuffle
{
403
    intf_thread_t *p_intf = getIntf();
404
    if (!p_intf)
405
        return;
406

407
    vlc_value_t val;
408
    playlist_t * p_playlist = pl_Get(p_intf);
409 410
    vout_thread_t *p_vout = getVout();

411
    var_Get(p_playlist, "random", &val);
412
    val.b_bool = !val.b_bool;
413 414 415
    var_Set(p_playlist, "random", val);
    if (val.b_bool) {
        if (p_vout) {
416
            vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s", _("Random On"));
417
            vlc_object_release(p_vout);
418
        }
419
        config_PutInt(p_playlist, "random", 1);
420 421 422
    }
    else
    {
423
        if (p_vout) {
424
            vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s", _("Random Off"));
425
            vlc_object_release(p_vout);
426
        }
427
        config_PutInt(p_playlist, "random", 0);
428
    }
429 430 431 432
}

- (void)repeatAll
{
433
    intf_thread_t *p_intf = getIntf();
434
    if (!p_intf)
435
        return;
436

437
    playlist_t * p_playlist = pl_Get(p_intf);
438

439 440 441 442
    var_SetBool(p_playlist, "repeat", NO);
    var_SetBool(p_playlist, "loop", YES);
    config_PutInt(p_playlist, "repeat", NO);
    config_PutInt(p_playlist, "loop", YES);
443 444

    vout_thread_t *p_vout = getVout();
445
    if (p_vout) {
446
        vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s", _("Repeat All"));
447
        vlc_object_release(p_vout);
448
    }
449 450 451 452
}

- (void)repeatOne
{
453
    intf_thread_t *p_intf = getIntf();
454
    if (!p_intf)
455
        return;
456

457
    playlist_t * p_playlist = pl_Get(p_intf);
458

459 460 461 462
    var_SetBool(p_playlist, "repeat", YES);
    var_SetBool(p_playlist, "loop", NO);
    config_PutInt(p_playlist, "repeat", YES);
    config_PutInt(p_playlist, "loop", NO);
463 464

    vout_thread_t *p_vout = getVout();
465
    if (p_vout) {
466
        vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s", _("Repeat One"));
467
        vlc_object_release(p_vout);
468
    }
469 470 471 472
}

- (void)repeatOff
{
473
    intf_thread_t *p_intf = getIntf();
474
    if (!p_intf)
475
        return;
476

477
    playlist_t * p_playlist = pl_Get(p_intf);
478

479 480 481 482
    var_SetBool(p_playlist, "repeat", NO);
    var_SetBool(p_playlist, "loop", NO);
    config_PutInt(p_playlist, "repeat", NO);
    config_PutInt(p_playlist, "loop", NO);
483 484

    vout_thread_t *p_vout = getVout();
485
    if (p_vout) {
486
        vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s", _("Repeat Off"));
487
        vlc_object_release(p_vout);
488
    }
489 490
}

491 492 493
- (void)setAtoB
{
    if (!timeA) {
494
        input_thread_t * p_input = pl_CurrentInput(getIntf());
495
        if (p_input) {
496
            timeA = var_GetInteger(p_input, "time");
497 498 499
            vlc_object_release(p_input);
        }
    } else if (!timeB) {
500
        input_thread_t * p_input = pl_CurrentInput(getIntf());
501
        if (p_input) {
502
            timeB = var_GetInteger(p_input, "time");
503 504
            vlc_object_release(p_input);
        }
505 506 507 508 509 510 511 512
    } else
        [self resetAtoB];
}

- (void)resetAtoB
{
    timeA = 0;
    timeB = 0;
513 514 515 516 517
}

- (void)updateAtoB
{
    if (timeB) {
518
        input_thread_t * p_input = pl_CurrentInput(getIntf());
519
        if (p_input) {
520
            mtime_t currentTime = var_GetInteger(p_input, "time");
521
            if ( currentTime >= timeB || currentTime < timeA)
522
                var_SetInteger(p_input, "time", timeA);
523 524 525 526 527
            vlc_object_release(p_input);
        }
    }
}

528 529
- (void)volumeUp
{
530
    intf_thread_t *p_intf = getIntf();
531
    if (!p_intf)
532
        return;
533

534
    playlist_VolumeUp(pl_Get(p_intf), 1, NULL);
535 536 537 538
}

- (void)volumeDown
{
539
    intf_thread_t *p_intf = getIntf();
540
    if (!p_intf)
541
        return;
542

543
    playlist_VolumeDown(pl_Get(p_intf), 1, NULL);
544 545
}

546 547
- (void)toggleMute
{
548
    intf_thread_t *p_intf = getIntf();
549
    if (!p_intf)
550 551
        return;

552
    playlist_MuteToggle(pl_Get(p_intf));
553 554
}

555
- (BOOL)mute
556
{
557
    intf_thread_t *p_intf = getIntf();
558
    if (!p_intf)
559
        return NO;
560

561
    BOOL b_is_muted = NO;
562
    b_is_muted = playlist_MuteGet(pl_Get(p_intf)) > 0;
563 564

    return b_is_muted;
565 566 567
}

- (int)volume
568
{
569
    intf_thread_t *p_intf = getIntf();
570
    if (!p_intf)
571
        return 0;
572

573
    float volume = playlist_VolumeGet(pl_Get(p_intf));
574

575
    return lroundf(volume * AOUT_VOLUME_DEFAULT);
576
}
577

578 579
- (void)setVolume: (int)i_value
{
580
    intf_thread_t *p_intf = getIntf();
581
    if (!p_intf)
582
        return;
583

584 585 586
    if (i_value >= self.maxVolume)
        i_value = self.maxVolume;

587 588 589
    float f_value = i_value / (float)AOUT_VOLUME_DEFAULT;

    playlist_VolumeSet(pl_Get(p_intf), f_value);
590 591
}

592 593
- (float)maxVolume
{
594
    if (f_maxVolume == 0.) {
595
        f_maxVolume = (float)var_InheritInteger(getIntf(), "macosx-max-volume") / 100. * AOUT_VOLUME_DEFAULT;
596 597 598
    }

    return f_maxVolume;
599 600
}

601 602
- (void)addSubtitlesToCurrentInput:(NSArray *)paths
{
603
    input_thread_t * p_input = pl_CurrentInput(getIntf());
604 605 606 607 608 609 610
    if (!p_input)
        return;

    NSUInteger count = [paths count];

    for (int i = 0; i < count ; i++) {
        const char *path = [[[paths objectAtIndex:i] path] UTF8String];
611
        msg_Dbg(getIntf(), "loading subs from %s", path);
612 613 614

        int i_result = input_AddSubtitleOSD(p_input, path, true, true);
        if (i_result != VLC_SUCCESS)
615
            msg_Warn(getIntf(), "unable to load subtitles from '%s'", path);
616 617 618 619
    }
    vlc_object_release(p_input);
}

620 621
- (void)showPosition
{
622
    input_thread_t *p_input = pl_CurrentInput(getIntf());
623 624 625
    if (p_input != NULL) {
        vout_thread_t *p_vout = input_GetVout(p_input);
        if (p_vout != NULL) {
626
            var_SetInteger(getIntf()->obj.libvlc, "key-action", ACTIONID_POSITION);
627 628 629 630 631 632
            vlc_object_release(p_vout);
        }
        vlc_object_release(p_input);
    }
}

633
#pragma mark - Drop support for files into the video, controls bar or drop box
634

635 636 637
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
{
    NSArray *items = [[[VLCMain sharedInstance] playlist] createItemsFromExternalPasteboard:[sender draggingPasteboard]];
638

639 640
    if (items.count == 0)
        return NO;
641

642
    [[[VLCMain sharedInstance] playlist] addPlaylistItems:items tryAsSubtitle:YES];
643
    return YES;
644 645
}

646
#pragma mark - video output stuff
647

648
- (void)setAspectRatioIsLocked:(BOOL)b_value
649
{
650
    config_PutInt(getIntf(), "macosx-lock-aspect-ratio", b_value);
651 652 653 654
}

- (BOOL)aspectRatioIsLocked
{
655
    return config_GetInt(getIntf(), "macosx-lock-aspect-ratio");
656 657 658 659
}

- (void)toggleFullscreen
{
660
    intf_thread_t *p_intf = getIntf();
661
    if (!p_intf)
662
        return;
663

664
    vout_thread_t *p_vout = getVoutForActiveWindow();
665
    if (p_vout) {
666 667
        BOOL b_fs = var_ToggleBool(p_vout, "fullscreen");
        var_SetBool(pl_Get(p_intf), "fullscreen", b_fs);
668
        vlc_object_release(p_vout);
669
    } else { // e.g. lion fullscreen toggle
670
        BOOL b_fs = var_ToggleBool(pl_Get(p_intf), "fullscreen");
671
        [[[VLCMain sharedInstance] voutController] setFullscreen:b_fs forWindow:nil withAnimation:YES];
672
    }
673
}
674

675
#pragma mark - uncommon stuff
676 677 678 679 680 681 682 683

- (BOOL)fixPreferences
{
    NSMutableString * o_workString;
    NSRange returnedRange;
    NSRange fullRange;
    BOOL b_needsRestart = NO;

684
    #define fixpref(pref) \
685
    o_workString = [[NSMutableString alloc] initWithFormat:@"%s", config_GetPsz(getIntf(), pref)]; \
686 687 688 689 690 691 692
    if ([o_workString length] > 0) \
    { \
        returnedRange = [o_workString rangeOfString:@"macosx" options: NSCaseInsensitiveSearch]; \
        if (returnedRange.location != NSNotFound) \
        { \
            if ([o_workString isEqualToString:@"macosx"]) \
                [o_workString setString:@""]; \
693
            fullRange = NSMakeRange(0, [o_workString length]); \
694
            [o_workString replaceOccurrencesOfString:@":macosx" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
695
            fullRange = NSMakeRange(0, [o_workString length]); \
696 697
            [o_workString replaceOccurrencesOfString:@"macosx:" withString:@"" options: NSCaseInsensitiveSearch range: fullRange]; \
            \
698
            config_PutPsz(getIntf(), pref, [o_workString UTF8String]); \
699 700
            b_needsRestart = YES; \
        } \
701
    }
702

703 704
    fixpref("control");
    fixpref("extraintf");
705 706 707 708 709
    #undef fixpref

    return b_needsRestart;
}

710 711
#pragma mark - video filter handling

712
- (const char *)getFilterType:(const char *)psz_name
713 714 715 716 717 718 719 720
{
    module_t *p_obj = module_find(psz_name);
    if (!p_obj) {
        return NULL;
    }

    if (module_provides(p_obj, "video splitter")) {
        return "video-splitter";
721
    } else if (module_provides(p_obj, "video filter")) {
722 723 724 725 726 727
        return "video-filter";
    } else if (module_provides(p_obj, "sub source")) {
        return "sub-source";
    } else if (module_provides(p_obj, "sub filter")) {
        return "sub-filter";
    } else {
728
        msg_Err(getIntf(), "Unknown video filter type.");
729 730 731 732
        return NULL;
    }
}

733
- (void)setVideoFilter: (const char *)psz_name on:(BOOL)b_on
734
{
735
    intf_thread_t *p_intf = getIntf();
736 737
    if (!p_intf)
        return;
738
    playlist_t *p_playlist = pl_Get(p_intf);
739 740 741 742 743 744 745 746
    char *psz_string, *psz_parser;

    const char *psz_filter_type = [self getFilterType:psz_name];
    if (!psz_filter_type) {
        msg_Err(p_intf, "Unable to find filter module \"%s\".", psz_name);
        return;
    }

747
    msg_Dbg(p_intf, "will turn filter '%s' %s", psz_name, b_on ? "on" : "off");
748

749
    psz_string = var_InheritString(p_playlist, psz_filter_type);
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779

    if (b_on) {
        if (psz_string == NULL) {
            psz_string = strdup(psz_name);
        } else if (strstr(psz_string, psz_name) == NULL) {
            char *psz_tmp = strdup([[NSString stringWithFormat: @"%s:%s", psz_string, psz_name] UTF8String]);
            free(psz_string);
            psz_string = psz_tmp;
        }
    } else {
        if (!psz_string)
            return;

        psz_parser = strstr(psz_string, psz_name);
        if (psz_parser) {
            if (*(psz_parser + strlen(psz_name)) == ':') {
                memmove(psz_parser, psz_parser + strlen(psz_name) + 1,
                        strlen(psz_parser + strlen(psz_name) + 1) + 1);
            } else {
                *psz_parser = '\0';
            }

            /* Remove trailing : : */
            if (strlen(psz_string) > 0 && *(psz_string + strlen(psz_string) -1) == ':')
                *(psz_string + strlen(psz_string) -1) = '\0';
        } else {
            free(psz_string);
            return;
        }
    }
780
    var_SetString(p_playlist, psz_filter_type, psz_string);
781

782 783
    /* Try to set non splitter filters on the fly */
    if (strcmp(psz_filter_type, "video-splitter")) {
784 785 786 787 788 789 790
        NSArray<NSValue *> *vouts = getVouts();
        if (vouts)
            for (NSValue * val in vouts) {
                vout_thread_t *p_vout = [val pointerValue];
                var_SetString(p_vout, psz_filter_type, psz_string);
                vlc_object_release(p_vout);
            }
791 792 793 794 795
    }

    free(psz_string);
}

796 797 798
- (void)setVideoFilterProperty: (char const *)psz_property
                     forFilter: (char const *)psz_filter
                     withValue: (vlc_value_t)value
799
{
800
    NSArray<NSValue *> *vouts = getVouts();
801
    intf_thread_t *p_intf = getIntf();
802
    playlist_t *p_playlist = pl_Get(p_intf);
803 804
    if (!p_intf)
        return;
805 806 807 808 809 810 811
    int i_type;
    bool b_is_command = false;
    char const *psz_filter_type = [self getFilterType: psz_filter];
    if (!psz_filter_type) {
        msg_Err(p_intf, "Unable to find filter module \"%s\".", psz_filter);
        return;
    }
812

813 814 815 816 817 818
    if (vouts && [vouts count])
    {
        i_type = var_Type((vout_thread_t *)[[vouts firstObject] pointerValue], psz_property);
        b_is_command = i_type & VLC_VAR_ISCOMMAND;
    }
    if (!i_type)
819
        i_type = config_GetType(psz_property);
820 821

    i_type &= VLC_VAR_CLASS;
822
    if (i_type == VLC_VAR_BOOL)
823
        var_SetBool(p_playlist, psz_property, value.b_bool);
824
    else if (i_type == VLC_VAR_INTEGER)
825
        var_SetInteger(p_playlist, psz_property, value.i_int);
826
    else if (i_type == VLC_VAR_FLOAT)
827
        var_SetFloat(p_playlist, psz_property, value.f_float);
828
    else if (i_type == VLC_VAR_STRING)
829
        var_SetString(p_playlist, psz_property, EnsureUTF8(value.psz_string));
830 831 832 833 834
    else
    {
        msg_Err(p_intf,
                "Module %s's %s variable is of an unsupported type ( %d )",
                psz_filter, psz_property, i_type);
835
        b_is_command = false;
836 837
    }

838 839 840 841 842 843 844 845 846 847 848 849
    if (b_is_command)
        if (vouts)
            for (NSValue *ptr in vouts)
            {
                vout_thread_t *p_vout = [ptr pointerValue];
                var_SetChecked(p_vout, psz_property, i_type, value);
#ifndef NDEBUG
                int i_cur_type = var_Type(p_vout, psz_property);
                assert((i_cur_type & VLC_VAR_CLASS) == i_type);
                assert(i_cur_type & VLC_VAR_ISCOMMAND);
#endif
            }
850

851 852 853
    if (vouts)
        for (NSValue *ptr in vouts)
            vlc_object_release((vout_thread_t *)[ptr pointerValue]);
854 855
}

856 857 858 859 860 861 862 863 864 865
#pragma mark -
#pragma mark Media Key support

- (void)resetMediaKeyJump
{
    b_mediakeyJustJumped = NO;
}

- (void)coreChangedMediaKeySupportSetting: (NSNotification *)o_notification
{
David Fuhrmann's avatar