controls.m 37.9 KB
Newer Older
1
/*****************************************************************************
2
 * controls.m: MacOS X interface module
3
 *****************************************************************************
4
 * Copyright (C) 2002-2009 the VideoLAN team
5
 * $Id$
6
7
8
 *
 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
 *          Christophe Massiot <massiot@via.ecp.fr>
hartman's avatar
hartman committed
9
 *          Derk-Jan Hartman <hartman at videolan dot org>
10
 *          Benjamin Pracht <bigben at videolan doit org>
11
 *          Felix Paul Kühne <fkuehne at videolan dot org>
12
13
14
15
16
 *
 * 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.
17
 *
18
19
20
21
22
23
24
 * 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
dionoea's avatar
dionoea committed
25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26
27
28
29
30
31
32
33
34
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
#include <sys/param.h>                                    /* for MAXPATHLEN */
#include <string.h>

35
36
37
38
39
#import "intf.h"
#import "vout.h"
#import "open.h"
#import "controls.h"
#import "playlist.h"
40
#include <vlc_osd.h>
41
#include <vlc_keys.h>
42

43
#pragma mark -
44
/*****************************************************************************
45
 * VLCControls implementation
46
47
48
 *****************************************************************************/
@implementation VLCControls

49
50
51
52
- (id)init
{
    [super init];
    o_fs_panel = [[VLCFSPanel alloc] init];
53
    b_lockAspectRatio = YES;
54
55
56
    return self;
}

57
58
- (void)awakeFromNib
{
59
    [o_specificTime_mi setTitle: _NS("Jump To Time")];
60
61
62
    [o_specificTime_cancel_btn setTitle: _NS("Cancel")];
    [o_specificTime_ok_btn setTitle: _NS("OK")];
    [o_specificTime_sec_lbl setStringValue: _NS("sec.")];
63
    [o_specificTime_goTo_lbl setStringValue: _NS("Jump to time")];
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

    o_repeat_off = [NSImage imageNamed:@"repeat_embedded"];

    [self controlTintChanged];

    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector( controlTintChanged )
                                                 name: NSControlTintDidChangeNotification
                                               object: nil];
}

- (void)controlTintChanged
{
    int i_repeat = 0;
    if( [o_btn_repeat image] == o_repeat_single )
        i_repeat = 1;
    else if( [o_btn_repeat image] == o_repeat_all )
        i_repeat = 2;

    if( [NSColor currentControlTint] == NSGraphiteControlTint )
    {
        o_repeat_single = [NSImage imageNamed:@"repeat_single_embedded_graphite"];
        o_repeat_all = [NSImage imageNamed:@"repeat_embedded_graphite"];
        
        [o_btn_shuffle setAlternateImage: [NSImage imageNamed: @"shuffle_embedded_graphite"]];
        [o_btn_addNode setAlternateImage: [NSImage imageNamed: @"add_embedded_graphite"]];
    }
    else
    {
        o_repeat_single = [NSImage imageNamed:@"repeat_single_embedded_blue"];
        o_repeat_all = [NSImage imageNamed:@"repeat_embedded_blue"];
        
        [o_btn_shuffle setAlternateImage: [NSImage imageNamed: @"shuffle_embedded_blue"]];
        [o_btn_addNode setAlternateImage: [NSImage imageNamed: @"add_embedded_blue"]];
    }
    
    /* update the repeat button, but keep its state */
    if( i_repeat == 1 )
        [self repeatOne];
    else if( i_repeat == 2 )
        [self repeatAll];
    else
        [self repeatOff];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver: self];
    
113
    [o_fs_panel release];
114
115
116
117
118
    [o_repeat_single release];
    [o_repeat_all release];
    [o_repeat_off release];
    
    [super dealloc];
119
120
}

121
122
- (IBAction)play:(id)sender
{
hartman's avatar
hartman committed
123
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
124
    playlist_t * p_playlist = pl_Hold( p_intf );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
125
    bool empty;
126

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
127
128
129
    PL_LOCK;
    empty = playlist_IsEmpty( p_playlist );
    PL_UNLOCK;
130
131

    pl_Release( p_intf );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
132
133

    if( empty )
134
135
        [o_main intfOpenFileGeneric: (id)sender];

136
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE );
137
138
}

139
- (id)voutView
140
{
141
142
143
144
145
    id o_window;
    id o_voutView = nil;
    id o_embeddedViewList = [[VLCMain sharedInstance] embeddedList];
    NSEnumerator *o_enumerator = [[NSApp orderedWindows] objectEnumerator];
    while( !o_voutView && ( o_window = [o_enumerator nextObject] ) )
146
147
    {
        /* We have an embedded vout */
148
        if( [o_embeddedViewList windowContainsEmbedded: o_window] )
149
        {
150
            o_voutView = [o_embeddedViewList viewForWindow: o_window];
151
152
        }
        /* We have a detached vout */
153
        else if( [[o_window className] isEqualToString: @"VLCVoutWindow"] )
154
        {
155
            o_voutView = [o_window voutView];
156
157
        }
    }
158
    return [[o_voutView retain] autorelease];
159
160
}

161
162
163
164
165
- (BOOL)aspectRatioIsLocked
{
    return b_lockAspectRatio;
}

166
167
- (IBAction)stop:(id)sender
{
hartman's avatar
hartman committed
168
    intf_thread_t * p_intf = VLCIntf;
169
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_STOP );
170
171
    /* Close the window directly, because we do know that there
     * won't be anymore video. It's currently waiting a bit. */
172
    [[[self voutView] window] orderOut:self];
173
174
175
176
}

- (IBAction)faster:(id)sender
{
hartman's avatar
hartman committed
177
    intf_thread_t * p_intf = VLCIntf;
178
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_FASTER );
179
180
181
182
}

- (IBAction)slower:(id)sender
{
hartman's avatar
hartman committed
183
    intf_thread_t * p_intf = VLCIntf;
184
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_SLOWER );
hartman's avatar
hartman committed
185
186
}

187
188
189
190
191
192
- (IBAction)normalSpeed:(id)sender
{
    intf_thread_t * p_intf = VLCIntf;
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_NORMAL );
}

193
194
- (IBAction)prev:(id)sender
{
hartman's avatar
hartman committed
195
    intf_thread_t * p_intf = VLCIntf;
196
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PREV );
197
198
199
200
}

- (IBAction)next:(id)sender
{
hartman's avatar
hartman committed
201
    intf_thread_t * p_intf = VLCIntf;
202
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_NEXT );
203
204
}

hartman's avatar
hartman committed
205
- (IBAction)random:(id)sender
206
{
hartman's avatar
hartman committed
207
    vlc_value_t val;
208
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
209
    playlist_t * p_playlist = pl_Hold( p_intf );
hartman's avatar
hartman committed
210
211
212
213

    var_Get( p_playlist, "random", &val );
    val.b_bool = !val.b_bool;
    var_Set( p_playlist, "random", val );
214
215
    if( val.b_bool )
    {
216
        vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Random On" ) );
217
        config_PutInt( p_playlist, "random", 1 );
218
219
220
    }
    else
    {
221
        vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Random Off" ) );
222
        config_PutInt( p_playlist, "random", 0 );
223
    }
hartman's avatar
hartman committed
224

225
226
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_intf_update = true;
227
    pl_Release( p_intf );
hartman's avatar
hartman committed
228
}
229

230
231
232
/* three little ugly helpers */
- (void)repeatOne
{
233
234
    [o_btn_repeat setImage: o_repeat_single];
    [o_btn_repeat setAlternateImage: o_repeat_all];
235
    [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeatOneOn"]];
236
237
238
}
- (void)repeatAll
{
239
240
    [o_btn_repeat setImage: o_repeat_all];
    [o_btn_repeat setAlternateImage: o_repeat_off];
241
    [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeatOn"]];
242
243
244
}
- (void)repeatOff
{
245
246
    [o_btn_repeat setImage: o_repeat_off];
    [o_btn_repeat setAlternateImage: o_repeat_single];
247
    [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeat"]];
248
249
250
251
}
- (void)shuffle
{
    vlc_value_t val;
dionoea's avatar
dionoea committed
252
    playlist_t *p_playlist = pl_Hold( VLCIntf );
253
254
    var_Get( p_playlist, "random", &val );
    [o_btn_shuffle setState: val.b_bool];
255
256
257
258
	if(val.b_bool)
        [o_btn_shuffle_embed setImage: [NSImage imageNamed:@"sidebarShuffleOn"]];
	else
        [o_btn_shuffle_embed setImage: [NSImage imageNamed:@"sidebarShuffle"]];    
259
    pl_Release( VLCIntf );
260
261
262
263
264
265
}

- (IBAction)repeatButtonAction:(id)sender
{
    vlc_value_t looping,repeating;
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
266
    playlist_t * p_playlist = pl_Hold( p_intf );
267
268
269
270
271
272
273

    var_Get( p_playlist, "repeat", &repeating );
    var_Get( p_playlist, "loop", &looping );

    if( !repeating.b_bool && !looping.b_bool )
    {
        /* was: no repeating at all, switching to Repeat One */
274
 
275
276
        /* set our button's look */
        [self repeatOne];
277
 
278
        /* prepare core communication */
279
280
        repeating.b_bool = true;
        looping.b_bool = false;
281
        config_PutInt( p_playlist, "repeat", 1 );
282
283
        config_PutInt( p_playlist, "loop", 0 );
 
284
        /* show the change */
285
        vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat One" ) );
286
287
288
289
    }
    else if( repeating.b_bool && !looping.b_bool )
    {
        /* was: Repeat One, switching to Repeat All */
290
 
291
292
        /* set our button's look */
        [self repeatAll];
293
 
294
        /* prepare core communication */
295
296
        repeating.b_bool = false;
        looping.b_bool = true;
297
298
299
        config_PutInt( p_playlist, "repeat", 0 );
        config_PutInt( p_playlist, "loop", 1 );
 
300
        /* show the change */
301
        vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat All" ) );
302
303
304
305
    }
    else
    {
        /* was: Repeat All or bug in VLC, switching to Repeat Off */
306
 
307
308
        /* set our button's look */
        [self repeatOff];
309
 
310
        /* prepare core communication */
311
312
        repeating.b_bool = false;
        looping.b_bool = false;
313
314
315
        config_PutInt( p_playlist, "repeat", 0 );
        config_PutInt( p_playlist, "loop", 0 );
 
316
        /* show the change */
317
        vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat Off" ) );
318
319
320
321
    }

    /* communicate with core and the main intf loop */
    var_Set( p_playlist, "repeat", repeating );
322
    var_Set( p_playlist, "loop", looping );
323
324
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_intf_update = true;
325

326
    pl_Release( p_intf );
327
328
329
}


hartman's avatar
hartman committed
330
331
332
- (IBAction)repeat:(id)sender
{
    vlc_value_t val;
333
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
334
    playlist_t * p_playlist = pl_Hold( p_intf );
335

hartman's avatar
hartman committed
336
    var_Get( p_playlist, "repeat", &val );
337
    if (!val.b_bool)
338
    {
339
        var_Set( p_playlist, "loop", val );
340
    }
hartman's avatar
hartman committed
341
342
    val.b_bool = !val.b_bool;
    var_Set( p_playlist, "repeat", val );
343
344
    if( val.b_bool )
    {
345
        vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat One" ) );
346
        config_PutInt( p_playlist, "repeat", 1 );
347
348
349
    }
    else
    {
350
        vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat Off" ) );
351
        config_PutInt( p_playlist, "repeat", 0 );
bigben's avatar
bigben committed
352
    }
353
 
354
355
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_intf_update = true;
356
    pl_Release( p_intf );
hartman's avatar
hartman committed
357
358
359
360
361
}

- (IBAction)loop:(id)sender
{
    vlc_value_t val;
362
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
363
    playlist_t * p_playlist = pl_Hold( p_intf );
hartman's avatar
hartman committed
364
365

    var_Get( p_playlist, "loop", &val );
366
367
368
369
    if (!val.b_bool)
    {
        var_Set( p_playlist, "repeat", val );
    }
hartman's avatar
hartman committed
370
371
    val.b_bool = !val.b_bool;
    var_Set( p_playlist, "loop", val );
372
373
    if( val.b_bool )
    {
374
        vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat All" ) );
375
        config_PutInt( p_playlist, "loop", 1 );
376
377
378
    }
    else
    {
379
        vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat Off" ) );
380
        config_PutInt( p_playlist, "loop", 0 );
381
    }
382

383
384
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_intf_update = true;
385
    pl_Release( p_intf );
386
387
}

388
389
390
391
392
393
394
395
396
397
- (IBAction)quitAfterPlayback:(id)sender
{
    vlc_value_t val;
    playlist_t * p_playlist = pl_Hold( VLCIntf );
    var_Get( p_playlist, "play-and-exit", &val );
    val.b_bool = !val.b_bool;
    var_Set( p_playlist, "play-and-exit", val );
    pl_Release( VLCIntf );
}

398
399
- (IBAction)forward:(id)sender
{
hartman's avatar
hartman committed
400
    intf_thread_t * p_intf = VLCIntf;
401
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_SHORT );
402
403
}

404
405
- (IBAction)backward:(id)sender
{
406
    vlc_value_t val;
hartman's avatar
hartman committed
407
    intf_thread_t * p_intf = VLCIntf;
408
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_SHORT );
409
410
}

411

412
413
- (IBAction)volumeUp:(id)sender
{
hartman's avatar
hartman committed
414
    intf_thread_t * p_intf = VLCIntf;
415
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_UP );
416
417
    /* Manage volume status */
    [o_main manageVolumeSlider];
418
419
420
421
}

- (IBAction)volumeDown:(id)sender
{
hartman's avatar
hartman committed
422
    intf_thread_t * p_intf = VLCIntf;
423
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_DOWN );
424
425
    /* Manage volume status */
    [o_main manageVolumeSlider];
426
427
428
429
}

- (IBAction)mute:(id)sender
{
hartman's avatar
hartman committed
430
    intf_thread_t * p_intf = VLCIntf;
431
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_MUTE );
432
433
    /* Manage volume status */
    [o_main manageVolumeSlider];
hartman's avatar
hartman committed
434
435
}

436
- (IBAction)volumeSliderUpdated:(id)sender
hartman's avatar
hartman committed
437
{
hartman's avatar
hartman committed
438
    intf_thread_t * p_intf = VLCIntf;
439
    playlist_t * p_playlist = pl_Hold( p_intf );
440
    audio_volume_t i_volume = (audio_volume_t)[sender intValue];
441
442
    int i_volume_step;

443
    i_volume_step = config_GetInt( p_intf->p_libvlc, "volume-step" );
444
    aout_VolumeSet( p_playlist, i_volume * i_volume_step );
445
    pl_Release( p_intf );
446
447
    /* Manage volume status */
    [o_main manageVolumeSlider];
448
449
}

450
451
- (IBAction)showPosition: (id)sender
{
452
453
    input_thread_t * p_input = pl_CurrentInput( VLCIntf );
    if( p_input != NULL )
454
    {
455
456
457
458
459
460
461
        vout_thread_t *p_vout = input_GetVout( p_input );
        if( p_vout != NULL )
        {
            var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_POSITION );
            vlc_object_release( (vlc_object_t *)p_vout );
        }
        vlc_object_release( p_input );
462
463
464
465
    }
}

- (IBAction)toogleFullscreen:(id)sender {
466
467
    NSMenuItem *o_mi = [[NSMenuItem alloc] initWithTitle: _NS("Fullscreen") action: nil keyEquivalent:@""];
    [self windowAction: [o_mi autorelease]];
468
469
470
}

- (BOOL) isFullscreen {
471
    id o_vout_view = [self voutView];
472
473
474
475
476
477
478
    if( o_vout_view )
    {
        return [o_vout_view isFullscreen];
    }
    return NO;
}

479
- (IBAction)windowAction:(id)sender
480
{
481
    NSString *o_title = [sender title];
482
    input_thread_t * p_input = pl_CurrentInput( VLCIntf );
483

484
    if( p_input != NULL )
485
    {
486
487
        vout_thread_t *p_vout = input_GetVout( p_input );
        if( p_vout != NULL )
hartman's avatar
hartman committed
488
        {
489
490
            id o_vout_view = [self voutView];
            if( o_vout_view )
491
            {
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
                if( [o_title isEqualToString: _NS("Half Size") ] )
                    [o_vout_view scaleWindowWithFactor: 0.5 animate: YES];
                else if( [o_title isEqualToString: _NS("Normal Size") ] )
                    [o_vout_view scaleWindowWithFactor: 1.0 animate: YES];
                else if( [o_title isEqualToString: _NS("Double Size") ] )
                    [o_vout_view scaleWindowWithFactor: 2.0 animate: YES];
                else if( [o_title isEqualToString: _NS("Float on Top") ] )
                    [o_vout_view toggleFloatOnTop];
                else if( [o_title isEqualToString: _NS("Fit to Screen") ] )
                {
                    id o_window = [o_vout_view voutWindow];
                    if( ![o_window isZoomed] )
                        [o_window performZoom:self];
                }
                else if( [o_title isEqualToString: _NS("Snapshot") ] )
                {
                    [o_vout_view snapshot];
                }
                else
                {
                    /* Fullscreen state for next time will be saved here too */
                    [o_vout_view toggleFullscreen];
                }
515
            }
516
517
518
519
520
521
522
523
            vlc_object_release( (vlc_object_t *)p_vout );
        }
        else
        {
            playlist_t * p_playlist = pl_Hold( VLCIntf );

            if( [o_title isEqualToString: _NS("Fullscreen")] ||
                [sender isKindOfClass:[NSButton class]] )
524
            {
ivoire's avatar
ivoire committed
525
                var_ToggleBool( p_playlist, "fullscreen" );
526
            }
527

528
            pl_Release( VLCIntf );
bigben's avatar
bigben committed
529
        }
530
        vlc_object_release( p_input );
bigben's avatar
bigben committed
531
    }
hartman's avatar
hartman committed
532
533
}

hartman's avatar
hartman committed
534
535
536
537
538
539
540
541
542
543
544
545
546
547
- (IBAction)telxTransparent:(id)sender
{
    intf_thread_t * p_intf = VLCIntf;
    vlc_object_t *p_vbi;
    p_vbi = (vlc_object_t *) vlc_object_find_name( p_intf,
                    "zvbi", FIND_ANYWHERE );
    if( p_vbi )
    {
        var_SetBool( p_vbi, "vbi-opaque", [sender state] );
        [sender setState: ![sender state]];
        vlc_object_release( p_vbi );
    }
}

548
- (IBAction)telxNavLink:(id)sender
hartman's avatar
hartman committed
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
{
    intf_thread_t * p_intf = VLCIntf;
    vlc_object_t *p_vbi;
    int i_page = 0;

    if( [[sender title] isEqualToString: _NS("Index")] )
        i_page = 'i' << 16;
    else if( [[sender title] isEqualToString: _NS("Red")] )
        i_page = 'r' << 16;
    else if( [[sender title] isEqualToString: _NS("Green")] )
        i_page = 'g' << 16;
    else if( [[sender title] isEqualToString: _NS("Yellow")] )
        i_page = 'y' << 16;
    else if( [[sender title] isEqualToString: _NS("Blue")] )
        i_page = 'b' << 16;
    if( i_page == 0 ) return;

    p_vbi = (vlc_object_t *) vlc_object_find_name( p_intf,
                "zvbi", FIND_ANYWHERE );
    if( p_vbi )
    {
        var_SetInteger( p_vbi, "vbi-page", i_page );
        vlc_object_release( p_vbi );
    }
}

575
576
577
578
579
580
581
582
583
584
- (IBAction)lockVideosAspectRatio:(id)sender
{
    if( [sender state] == NSOffState )
        [sender setState: NSOnState];
    else
        [sender setState: NSOffState];

    b_lockAspectRatio = !b_lockAspectRatio;
}

585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
- (IBAction)addSubtitleFile:(id)sender
{
    NSInteger i_returnValue = 0;
    input_thread_t * p_input = pl_CurrentInput( VLCIntf );
    if( !p_input ) return;

    input_item_t *p_item = input_GetItem( p_input );
    if( !p_item ) return;

    char *path = input_item_GetURI( p_item );
    if( !path ) path = strdup( "" );

    NSOpenPanel * openPanel = [NSOpenPanel openPanel];
    [openPanel setCanChooseFiles: YES];
    [openPanel setCanChooseDirectories: NO];
    [openPanel setAllowsMultipleSelection: YES];
    i_returnValue = [openPanel runModalForDirectory: [NSString stringWithUTF8String: path] file: nil types: [NSArray arrayWithObjects: @"cdg",@"@idx",@"srt",@"sub",@"utf",@"ass",@"ssa",@"aqt",@"jss",@"psb",@"rt",@"smi", nil]];
    free( path );

    if( i_returnValue == NSOKButton )
    {
        NSUInteger c = 0;
        if( !p_input ) return;
        
        c = [[openPanel filenames] count];
hartman's avatar
hartman committed
610
611

        for (int i = 0; i < [[openPanel filenames] count] ; i++)
612
613
614
615
616
617
618
619
620
        {
            msg_Dbg( VLCIntf, "loading subs from %s", [[[openPanel filenames] objectAtIndex: i] UTF8String] );
            if( input_AddSubtitle( p_input, [[[openPanel filenames] objectAtIndex: i] UTF8String], TRUE ) )
                msg_Warn( VLCIntf, "unable to load subtitles from '%s'",
                         [[[openPanel filenames] objectAtIndex: i] UTF8String] );
        }
    }
}

621
622
623
- (void)scrollWheel:(NSEvent *)theEvent
{
    intf_thread_t * p_intf = VLCIntf;
624
625
626
    float f_yabsvalue = [theEvent deltaY] > 0.0f ? [theEvent deltaY] : -[theEvent deltaY];
    float f_xabsvalue = [theEvent deltaX] > 0.0f ? [theEvent deltaX] : -[theEvent deltaX];
    int i, i_yvlckey, i_xvlckey;
627
628

    if ([theEvent deltaY] < 0.0f)
629
630
631
632
633
634
        i_yvlckey = KEY_MOUSEWHEELDOWN;
    else
        i_yvlckey = KEY_MOUSEWHEELUP;

    if ([theEvent deltaX] < 0.0f)
        i_xvlckey = KEY_MOUSEWHEELRIGHT;
635
    else
636
        i_xvlckey = KEY_MOUSEWHEELLEFT;
637
638

    /* Send multiple key event, depending on the intensity of the event */
639
640
641
    for (i = 0; i < (int)(f_yabsvalue/4.+1.) && f_yabsvalue > 0.05 ; i++)
        var_SetInteger( p_intf->p_libvlc, "key-pressed", i_yvlckey );

Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
642
643
644
645
646
647
    /* Prioritize Y event (sound volume) over X event */
    if (f_yabsvalue < 0.05)
    {
        for (i = 0; i < (int)(f_xabsvalue/6.+1.) && f_xabsvalue > 0.05; i++)
         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_xvlckey );
    }
648
649
}

650
651
652
653
654
655
656
- (BOOL)keyEvent:(NSEvent *)o_event
{
    BOOL eventHandled = NO;
    unichar key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];

    if( key )
    {
657
658
        input_thread_t * p_input = pl_CurrentInput( VLCIntf );
        if( p_input != NULL )
659
        {
660
661
662
            vout_thread_t *p_vout = input_GetVout( p_input );

            if( p_vout != NULL )
663
            {
664
665
                /* Escape */
                if( key == (unichar) 0x1b )
666
                {
667
668
669
670
671
672
673
674
675
676
                    id o_vout_view = [self voutView];
                    if( o_vout_view && [o_vout_view isFullscreen] )
                    {
                        [o_vout_view toggleFullscreen];
                        eventHandled = YES;
                    }
                }
                else if( key == ' ' )
                {
                    [self play:self];
677
678
                    eventHandled = YES;
                }
679
                vlc_object_release( (vlc_object_t *)p_vout );
680
            }
681
            vlc_object_release( p_input );
682
683
684
685
686
        }
    }
    return eventHandled;
}

hartman's avatar
* ALL:    
hartman committed
687
688
689
690
- (void)setupVarMenuItem:(NSMenuItem *)o_mi
                    target:(vlc_object_t *)p_object
                    var:(const char *)psz_variable
                    selector:(SEL)pf_callback
691
{
hartman's avatar
* ALL:    
hartman committed
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
    vlc_value_t val, text;
    int i_type = var_Type( p_object, psz_variable );

    switch( i_type & VLC_VAR_TYPE )
    {
    case VLC_VAR_VOID:
    case VLC_VAR_BOOL:
    case VLC_VAR_VARIABLE:
    case VLC_VAR_STRING:
    case VLC_VAR_INTEGER:
        break;
    default:
        /* Variable doesn't exist or isn't handled */
        return;
    }
707
 
hartman's avatar
* ALL:    
hartman committed
708
709
710
711
712
713
714
715
    /* Make sure we want to display the variable */
    if( i_type & VLC_VAR_HASCHOICE )
    {
        var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
        if( val.i_int == 0 ) return;
        if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
            return;
    }
716
 
hartman's avatar
* ALL:    
hartman committed
717
718
    /* Get the descriptive name of the variable */
    var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
hartman's avatar
hartman committed
719
    [o_mi setTitle: [[VLCMain sharedInstance] localizedString: text.psz_string ?
hartman's avatar
hartman committed
720
                                        text.psz_string : psz_variable ]];
721

hartman's avatar
* ALL:    
hartman committed
722
    if( i_type & VLC_VAR_HASCHOICE )
723
    {
hartman's avatar
* ALL:    
hartman committed
724
725
726
727
        NSMenu *o_menu = [o_mi submenu];

        [self setupVarMenu: o_menu forMenuItem: o_mi target:p_object
                        var:psz_variable selector:pf_callback];
728
 
729
        free( text.psz_string );
hartman's avatar
* ALL:    
hartman committed
730
        return;
731
    }
732
733
734
735
    if( var_Get( p_object, psz_variable, &val ) < 0 )
    {
        return;
    }
hartman's avatar
* ALL:    
hartman committed
736

737
    VLCAutoGeneratedMenuContent *o_data;
hartman's avatar
* ALL:    
hartman committed
738
    switch( i_type & VLC_VAR_TYPE )
739
    {
hartman's avatar
* ALL:    
hartman committed
740
    case VLC_VAR_VOID:
741
742
        o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
                andValue: val ofType: i_type];
743
        [o_mi setRepresentedObject: [o_data autorelease]];
hartman's avatar
* ALL:    
hartman committed
744
745
746
        break;

    case VLC_VAR_BOOL:
747
748
        o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
                andValue: val ofType: i_type];
749
        [o_mi setRepresentedObject: [o_data autorelease]];
750
751
        if( !( i_type & VLC_VAR_ISCOMMAND ) )
            [o_mi setState: val.b_bool ? TRUE : FALSE ];
hartman's avatar
* ALL:    
hartman committed
752
753
754
        break;

    default:
755
        break;
756
    }
hartman's avatar
* ALL:    
hartman committed
757

758
    if( ( i_type & VLC_VAR_TYPE ) == VLC_VAR_STRING ) free( val.psz_string );
759
    free( text.psz_string );
760
}
761

hartman's avatar
* ALL:    
hartman committed
762
763
764
765
766
767

- (void)setupVarMenu:(NSMenu *)o_menu
                    forMenuItem: (NSMenuItem *)o_parent
                    target:(vlc_object_t *)p_object
                    var:(const char *)psz_variable
                    selector:(SEL)pf_callback
768
{
hartman's avatar
* ALL:    
hartman committed
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
    vlc_value_t val, val_list, text_list;
    int i_type, i, i_nb_items;

    /* remove previous items */
    i_nb_items = [o_menu numberOfItems];
    for( i = 0; i < i_nb_items; i++ )
    {
        [o_menu removeItemAtIndex: 0];
    }

    /* Check the type of the object variable */
    i_type = var_Type( p_object, psz_variable );

    /* Make sure we want to display the variable */
    if( i_type & VLC_VAR_HASCHOICE )
    {
        var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
        if( val.i_int == 0 ) return;
        if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
            return;
    }
    else
    {
        return;
    }

    switch( i_type & VLC_VAR_TYPE )
796
    {
hartman's avatar
* ALL:    
hartman committed
797
798
799
800
801
802
803
804
805
806
    case VLC_VAR_VOID:
    case VLC_VAR_BOOL:
    case VLC_VAR_VARIABLE:
    case VLC_VAR_STRING:
    case VLC_VAR_INTEGER:
        break;
    default:
        /* Variable doesn't exist or isn't handled */
        return;
    }
807

hartman's avatar
* ALL:    
hartman committed
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
    if( var_Get( p_object, psz_variable, &val ) < 0 )
    {
        return;
    }

    if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST,
                    &val_list, &text_list ) < 0 )
    {
        if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
        return;
    }

    /* make (un)sensitive */
    [o_parent setEnabled: ( val_list.p_list->i_count > 1 )];

823
824
825
826
827
828
829
830
831
832
833
834
    /* Aspect Ratio */
    if( [[o_parent title] isEqualToString: _NS("Aspect-ratio")] == YES )
    {
        NSMenuItem *o_lmi_tmp2;
        o_lmi_tmp2 = [o_menu addItemWithTitle: _NS("Lock Aspect Ratio") action: @selector(lockVideosAspectRatio:) keyEquivalent: @""];
        [o_lmi_tmp2 setTarget: self];
        [o_lmi_tmp2 setEnabled: YES];
        [o_lmi_tmp2 setState: b_lockAspectRatio];
        [o_parent setEnabled: YES];
        [o_menu addItem: [NSMenuItem separatorItem]];
    }

835
836
837
838
839
840
841
842
843
844
845
    /* special case for the subtitles items */
    if( [[o_parent title] isEqualToString: _NS("Subtitles Track")] == YES )
    {
        NSMenuItem * o_lmi_tmp;
        o_lmi_tmp = [o_menu addItemWithTitle: _NS("Open File...") action: @selector(addSubtitleFile:) keyEquivalent: @""];
        [o_lmi_tmp setTarget: self];
        [o_lmi_tmp setEnabled: YES];
        [o_parent setEnabled: YES];
        [o_menu addItem: [NSMenuItem separatorItem]];
    }

hartman's avatar
* ALL:    
hartman committed
846
847
848
849
    for( i = 0; i < val_list.p_list->i_count; i++ )
    {
        NSMenuItem * o_lmi;
        NSString *o_title = @"";
850
        VLCAutoGeneratedMenuContent *o_data;
hartman's avatar
* ALL:    
hartman committed
851
852

        switch( i_type & VLC_VAR_TYPE )
853
        {
hartman's avatar
* ALL:    
hartman committed
854
855
        case VLC_VAR_STRING:

hartman's avatar
hartman committed
856
            o_title = [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string ?
hartman's avatar
* ALL:    
hartman committed
857
858
859
                text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];

            o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
860
            o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
861
                    andValue: val_list.p_list->p_values[i] ofType: i_type];
862
            [o_lmi setRepresentedObject: [o_data autorelease]];
hartman's avatar
* ALL:    
hartman committed
863
            [o_lmi setTarget: self];
864

865
            if( !strcmp( val.psz_string, val_list.p_list->p_values[i].psz_string ) && !( i_type & VLC_VAR_ISCOMMAND ) )
hartman's avatar
* ALL:    
hartman committed
866
867
868
869
870
871
872
                [o_lmi setState: TRUE ];

            break;

        case VLC_VAR_INTEGER:

             o_title = text_list.p_list->p_values[i].psz_string ?
hartman's avatar
hartman committed
873
                                 [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string] :
hartman's avatar
* ALL:    
hartman committed
874
875
876
                                 [NSString stringWithFormat: @"%d",
                                 val_list.p_list->p_values[i].i_int];

hartman's avatar
hartman committed
877
            o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
878
            o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
879
                    andValue: val_list.p_list->p_values[i] ofType: i_type];
880
            [o_lmi setRepresentedObject: [o_data autorelease]];
hartman's avatar
* ALL:    
hartman committed
881
882
            [o_lmi setTarget: self];

883
            if( val_list.p_list->p_values[i].i_int == val.i_int && !( i_type & VLC_VAR_ISCOMMAND ) )
hartman's avatar
* ALL:    
hartman committed
884
885
886
887
888
                [o_lmi setState: TRUE ];
            break;

        default:
          break;
889
890
        }
    }
891

892
893
894
895
896
897
898
899
    /* special case for the subtitles sub-menu
     * In case that we don't have any subs, we don't want a separator item at the end */
    if( [[o_parent title] isEqualToString: _NS("Subtitles Track")] == YES )
    {
        if( [o_menu numberOfItems] == 2 )
            [o_menu removeItemAtIndex: 1];
    }

hartman's avatar
* ALL:    
hartman committed
900
    /* clean up everything */
901
    if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
902
    var_FreeList( &val_list, &text_list );
hartman's avatar
* ALL:    
hartman committed
903
904
905
906
907
}

- (IBAction)toggleVar:(id)sender
{
    NSMenuItem *o_mi = (NSMenuItem *)sender;
908
    VLCAutoGeneratedMenuContent *o_data = [o_mi representedObject];
909
910
911
912
913
914
    [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
        toTarget: self withObject: o_data];

    return;
}

915
- (int)toggleVarThread: (id)data
916
{
hartman's avatar
* ALL:    
hartman committed
917
    vlc_object_t *p_object;
918
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
919
920
921

    assert([data isKindOfClass:[VLCAutoGeneratedMenuContent class]]);
    VLCAutoGeneratedMenuContent *menuContent = (VLCAutoGeneratedMenuContent *)data;
922

hartman's avatar
hartman committed
923
    vlc_thread_set_priority( VLCIntf , VLC_THREAD_PRIORITY_LOW );
hartman's avatar
* ALL:    
hartman committed
924

925
    p_object = [menuContent vlcObject];
hartman's avatar
* ALL:    
hartman committed
926

927
928
    if( p_object != NULL )
    {
929
        var_Set( p_object, [menuContent name], [menuContent value] );
930
931
        vlc_object_release( p_object );
        [o_pool release];
932
        return true;
933
934
935
    }
    [o_pool release];
    return VLC_EGENERIC;
936
937
}

938
939
940
941
942
943
944
945
946
- (IBAction)goToSpecificTime:(id)sender
{
    if( sender == o_specificTime_cancel_btn )
    {
        [NSApp endSheet: o_specificTime_win];
        [o_specificTime_win close];
    }
    else if( sender == o_specificTime_ok_btn )
    {
947
        input_thread_t * p_input = pl_CurrentInput( VLCIntf );
948
949
        if( p_input )
        {
950
951
            unsigned int timeInSec = 0;
            NSString * fieldContent = [o_specificTime_enter_fld stringValue];
952
            if( [[fieldContent componentsSeparatedByString: @":"] count] > 1 &&
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
                [[fieldContent componentsSeparatedByString: @":"] count] <= 3 )
            {
                NSArray * ourTempArray = \
                    [fieldContent componentsSeparatedByString: @":"];

                if( [[fieldContent componentsSeparatedByString: @":"] count] == 3 )
                {
                    timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 3600); //h
                    timeInSec += ([[ourTempArray objectAtIndex: 1] intValue] * 60); //m
                    timeInSec += [[ourTempArray objectAtIndex: 2] intValue];        //s
                }
                else
                {
                    timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 60); //m
                    timeInSec += [[ourTempArray objectAtIndex: 1] intValue]; //s
                }
            }
            else
                timeInSec = [fieldContent intValue];

            input_Control( p_input, INPUT_SET_TIME, (int64_t)(timeInSec * 1000000));
974
975
            vlc_object_release( p_input );
        }
976

977
978
979
980
981
        [NSApp endSheet: o_specificTime_win];
        [o_specificTime_win close];
    }
    else
    {
982
        input_thread_t * p_input = pl_CurrentInput( VLCIntf );
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
        if( p_input )
        {
            /* we can obviously only do that if an input is available */
            vlc_value_t pos, length;
            var_Get( p_input, "time", &pos );
            [o_specificTime_enter_fld setIntValue: (pos.i_time / 1000000)];
            var_Get( p_input, "length", &length );
            [o_specificTime_stepper setMaxValue: (length.i_time / 1000000)];

            [NSApp beginSheet: o_specificTime_win modalForWindow: \
                [NSApp mainWindow] modalDelegate: self didEndSelector: nil \
                contextInfo: nil];
            [o_specificTime_win makeKeyWindow];
            vlc_object_release( p_input );
        }
    }
}

1001
- (id)fspanel
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
{
    if( o_fs_panel )
        return o_fs_panel;
    else
    {
        msg_Err( VLCIntf, "FSPanel is nil" );
        return NULL;
    }
}

1012
1013
1014
@end

@implementation VLCControls (NSMenuValidation)
1015

1016
1017
1018
- (BOOL)validateMenuItem:(NSMenuItem *)o_mi
{
    BOOL bEnabled = TRUE;
hartman's avatar
hartman committed
1019
    vlc_value_t val;
hartman's avatar
hartman committed
1020
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
1021
    playlist_t * p_playlist = pl_Hold( p_intf );
1022
    input_thread_t * p_input = playlist_CurrentInput( p_playlist );
1023

hartman's avatar
hartman committed
1024
    if( [[o_mi title] isEqualToString: _NS("Faster")] ||
1025
1026
        [[o_mi title] isEqualToString: _NS("Slower")] ||
        [[o_mi title] isEqualToString: _NS("Normal rate")] )
1027
    {
1028
        if( p_input != NULL )
1029
        {
1030
            bEnabled = var_GetBool( p_input, "can-rate" );
1031
1032
1033
1034
1035
1036
1037
1038
        }
        else
        {
            bEnabled = FALSE;
        }
    }
    else if( [[o_mi title] isEqualToString: _NS("Stop")] )
    {
1039
        if( p_input == NULL )
1040
1041
1042
        {
            bEnabled = FALSE;
        }
1043
        [o_main setupMenus]; /* Make sure input menu is up to date */
1044
    }
Jon Lech Johansen's avatar
Jon Lech Johansen committed
1045
    else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
1046
1047
             [[o_mi title] isEqualToString: _NS("Next")] )
    {
1048
        PL_LOCK;
1049
        bEnabled = playlist_CurrentSize( p_playlist ) > 1;
1050
        PL_UNLOCK;
1051
    }
1052
    else if( [[o_mi title] isEqualToString: _NS("Random")] )
1053
    {
hartman's avatar
hartman committed
1054
1055
1056
1057
1058
        int i_state;
        var_Get( p_playlist, "random", &val );
        i_state = val.b_bool ? NSOnState : NSOffState;
        [o_mi setState: i_state];
    }
1059
    else if( [[o_mi title] isEqualToString: _NS("Repeat One")] )
hartman's avatar
hartman committed
1060
1061
1062
1063
1064
1065
    {
        int i_state;
        var_Get( p_playlist, "repeat", &val );
        i_state = val.b_bool ? NSOnState : NSOffState;
        [o_mi setState: i_state];
    }
1066
    else if( [[o_mi title] isEqualToString: _NS("Repeat All")] )
hartman's avatar
hartman committed
1067
1068
1069
1070
    {
        int i_state;
        var_Get( p_playlist, "loop", &val );
        i_state = val.b_bool ? NSOnState : NSOffState;
1071
1072
        [o_mi setState: i_state];
    }
1073
1074
1075
1076
1077
1078
1079