controls.m 36.2 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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*****************************************************************************
 * VLCAutoGeneratedMenuContent interface
 *****************************************************************************
 * This holds our data for autogenerated menus
 *****************************************************************************/
@interface VLCAutoGeneratedMenuContent : NSObject
{
    char *psz_name;
    vlc_object_t * _vlc_object;
    vlc_value_t value;
    int i_type;
}

- (id)initWithVariableName: (const char *)name 
           ofObject: (vlc_object_t *)object
           andValue: (vlc_value_t)value 
           ofType: (int)type;
- (const char *)name;
- (vlc_value_t)value;
- (vlc_object_t *)vlcObject;
- (int)type;

@end

#pragma mark -
68
/*****************************************************************************
69
 * VLCControls implementation
70
71
72
 *****************************************************************************/
@implementation VLCControls

73
74
75
76
77
78
79
- (id)init
{
    [super init];
    o_fs_panel = [[VLCFSPanel alloc] init];
    return self;
}

80
81
- (void)awakeFromNib
{
82
    [o_specificTime_mi setTitle: _NS("Jump To Time")];
83
84
85
    [o_specificTime_cancel_btn setTitle: _NS("Cancel")];
    [o_specificTime_ok_btn setTitle: _NS("OK")];
    [o_specificTime_sec_lbl setStringValue: _NS("sec.")];
86
    [o_specificTime_goTo_lbl setStringValue: _NS("Jump to time")];
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

    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];
    
    [o_repeat_single release];
    [o_repeat_all release];
    [o_repeat_off release];
    
    [super dealloc];
141
142
}

143
144
- (IBAction)play:(id)sender
{
hartman's avatar
hartman committed
145
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
146
    playlist_t * p_playlist = pl_Hold( p_intf );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
147
    bool empty;
148

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
149
150
151
    PL_LOCK;
    empty = playlist_IsEmpty( p_playlist );
    PL_UNLOCK;
152
153

    pl_Release( p_intf );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
154
155

    if( empty )
156
157
        [o_main intfOpenFileGeneric: (id)sender];

158
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE );
159
160
}

161
- (id)voutView
162
{
163
164
    id window;
    id voutView = nil;
165
    id embeddedViewList = [[VLCMain sharedInstance] embeddedList];
166
167
    NSEnumerator *enumerator = [[NSApp orderedWindows] objectEnumerator];
    while( !voutView && ( window = [enumerator nextObject] ) )
168
169
    {
        /* We have an embedded vout */
170
        if( [embeddedViewList windowContainsEmbedded: window] )
171
        {
172
            voutView = [embeddedViewList viewForWindow: window];
173
174
        }
        /* We have a detached vout */
175
        else if( [[window className] isEqualToString: @"VLCVoutWindow"] )
176
        {
177
            voutView = [window voutView];
178
179
        }
    }
180
    return [[voutView retain] autorelease];
181
182
}

183
184
- (IBAction)stop:(id)sender
{
hartman's avatar
hartman committed
185
    intf_thread_t * p_intf = VLCIntf;
186
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_STOP );
187
188
    /* Close the window directly, because we do know that there
     * won't be anymore video. It's currently waiting a bit. */
189
    [[[self voutView] window] orderOut:self];
190
191
192
193
}

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

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

204
205
- (IBAction)prev:(id)sender
{
hartman's avatar
hartman committed
206
    intf_thread_t * p_intf = VLCIntf;
207
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PREV );
208
209
210
211
}

- (IBAction)next:(id)sender
{
hartman's avatar
hartman committed
212
    intf_thread_t * p_intf = VLCIntf;
213
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_NEXT );
214
215
}

hartman's avatar
hartman committed
216
- (IBAction)random:(id)sender
217
{
hartman's avatar
hartman committed
218
    vlc_value_t val;
219
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
220
    playlist_t * p_playlist = pl_Hold( p_intf );
hartman's avatar
hartman committed
221
222
223
224

    var_Get( p_playlist, "random", &val );
    val.b_bool = !val.b_bool;
    var_Set( p_playlist, "random", val );
225
226
    if( val.b_bool )
    {
227
        vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Random On" ) );
228
        config_PutInt( p_playlist, "random", 1 );
229
230
231
    }
    else
    {
232
        vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Random Off" ) );
233
        config_PutInt( p_playlist, "random", 0 );
234
    }
hartman's avatar
hartman committed
235

236
237
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_intf_update = true;
238
    pl_Release( p_intf );
hartman's avatar
hartman committed
239
}
240

241
242
243
/* three little ugly helpers */
- (void)repeatOne
{
244
245
    [o_btn_repeat setImage: o_repeat_single];
    [o_btn_repeat setAlternateImage: o_repeat_all];
246
247
248
}
- (void)repeatAll
{
249
250
    [o_btn_repeat setImage: o_repeat_all];
    [o_btn_repeat setAlternateImage: o_repeat_off];
251
252
253
}
- (void)repeatOff
{
254
255
    [o_btn_repeat setImage: o_repeat_off];
    [o_btn_repeat setAlternateImage: o_repeat_single];
256
257
258
259
}
- (void)shuffle
{
    vlc_value_t val;
dionoea's avatar
dionoea committed
260
    playlist_t *p_playlist = pl_Hold( VLCIntf );
261
262
    var_Get( p_playlist, "random", &val );
    [o_btn_shuffle setState: val.b_bool];
263
    pl_Release( VLCIntf );
264
265
266
267
268
269
}

- (IBAction)repeatButtonAction:(id)sender
{
    vlc_value_t looping,repeating;
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
270
    playlist_t * p_playlist = pl_Hold( p_intf );
271
272
273
274
275
276
277

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

    /* communicate with core and the main intf loop */
    var_Set( p_playlist, "repeat", repeating );
326
    var_Set( p_playlist, "loop", looping );
327
328
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_intf_update = true;
329

330
    pl_Release( p_intf );
331
332
333
}


hartman's avatar
hartman committed
334
335
336
- (IBAction)repeat:(id)sender
{
    vlc_value_t val;
337
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
338
    playlist_t * p_playlist = pl_Hold( p_intf );
339

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

- (IBAction)loop:(id)sender
{
    vlc_value_t val;
366
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
367
    playlist_t * p_playlist = pl_Hold( p_intf );
hartman's avatar
hartman committed
368
369

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

387
388
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_intf_update = true;
389
    pl_Release( p_intf );
390
391
}

392
393
- (IBAction)forward:(id)sender
{
hartman's avatar
hartman committed
394
    intf_thread_t * p_intf = VLCIntf;
395
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_SHORT );
396
397
}

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

405

406
407
- (IBAction)volumeUp:(id)sender
{
hartman's avatar
hartman committed
408
    intf_thread_t * p_intf = VLCIntf;
409
    var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_UP );
410
411
    /* Manage volume status */
    [o_main manageVolumeSlider];
412
413
414
415
}

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

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

430
- (IBAction)volumeSliderUpdated:(id)sender
hartman's avatar
hartman committed
431
{
hartman's avatar
hartman committed
432
    intf_thread_t * p_intf = VLCIntf;
433
    audio_volume_t i_volume = (audio_volume_t)[sender intValue];
434
    int i_volume_step = 0;
435
    i_volume_step = config_GetInt( p_intf->p_libvlc, "volume-step" );
436
    aout_VolumeSet( p_intf, i_volume * i_volume_step );
437
438
    /* Manage volume status */
    [o_main manageVolumeSlider];
439
440
}

441
442
443
444
445
446
447
- (IBAction)showPosition: (id)sender
{
    vout_thread_t *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT,
                                             FIND_ANYWHERE );
    if( p_vout != NULL )
    {
        intf_thread_t * p_intf = VLCIntf;
448
        var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_POSITION );
449
        vlc_object_release( (vlc_object_t *)p_vout );
450
451
452
453
    }
}

- (IBAction)toogleFullscreen:(id)sender {
454
455
    NSMenuItem *o_mi = [[NSMenuItem alloc] initWithTitle: _NS("Fullscreen") action: nil keyEquivalent:@""];
    [self windowAction: [o_mi autorelease]];
456
457
458
}

- (BOOL) isFullscreen {
459
    id o_vout_view = [self voutView];
460
461
462
463
464
465
466
    if( o_vout_view )
    {
        return [o_vout_view isFullscreen];
    }
    return NO;
}

467
- (IBAction)windowAction:(id)sender
468
{
469
    NSString *o_title = [sender title];
470

471
    vout_thread_t *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT,
472
473
                                              FIND_ANYWHERE );
    if( p_vout != NULL )
474
    {
475
        id o_vout_view = [self voutView];
476
        if( o_vout_view )
hartman's avatar
hartman committed
477
        {
478
            if( [o_title isEqualToString: _NS("Half Size") ] )
479
                [o_vout_view scaleWindowWithFactor: 0.5 animate: YES];
480
            else if( [o_title isEqualToString: _NS("Normal Size") ] )
481
                [o_vout_view scaleWindowWithFactor: 1.0 animate: YES];
482
            else if( [o_title isEqualToString: _NS("Double Size") ] )
483
                [o_vout_view scaleWindowWithFactor: 2.0 animate: YES];
484
485
486
            else if( [o_title isEqualToString: _NS("Float on Top") ] )
                [o_vout_view toggleFloatOnTop];
            else if( [o_title isEqualToString: _NS("Fit to Screen") ] )
487
            {
488
                id o_window = [o_vout_view voutWindow];
489
490
                if( ![o_window isZoomed] )
                    [o_window performZoom:self];
491
            }
492
            else if( [o_title isEqualToString: _NS("Snapshot") ] )
493
            {
494
                [o_vout_view snapshot];
495
            }
496
            else
497
            {
498
                /* Fullscreen state for next time will be saved here too */
499
                [o_vout_view toggleFullscreen];
500
            }
hartman's avatar
hartman committed
501
        }
502
        vlc_object_release( (vlc_object_t *)p_vout );
hartman's avatar
hartman committed
503
    }
504
    else
bigben's avatar
bigben committed
505
    {
dionoea's avatar
dionoea committed
506
        playlist_t * p_playlist = pl_Hold( VLCIntf );
507

508
509
        if( [o_title isEqualToString: _NS("Fullscreen")] ||
            [sender isKindOfClass:[NSButton class]] )
bigben's avatar
bigben committed
510
511
512
513
514
        {
            vlc_value_t val;
            var_Get( p_playlist, "fullscreen", &val );
            var_Set( p_playlist, "fullscreen", (vlc_value_t)!val.b_bool );
        }
515

516
        pl_Release( VLCIntf );
bigben's avatar
bigben committed
517
518
    }

hartman's avatar
hartman committed
519
520
}

hartman's avatar
hartman committed
521
522
523
524
525
526
527
528
529
530
531
532
533
534
- (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 );
    }
}

535
- (IBAction)telxNavLink:(id)sender
hartman's avatar
hartman committed
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
{
    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 );
    }
}

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
- (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];
        NSLog( @"count: %i", c );
        for (int i = 0; [[openPanel filenames] count] > i ; i++)
        {
            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] );
            i++;
        }
    }
}

599
600
601
- (void)scrollWheel:(NSEvent *)theEvent
{
    intf_thread_t * p_intf = VLCIntf;
602
603
604
    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;
605
606

    if ([theEvent deltaY] < 0.0f)
607
608
609
610
611
612
        i_yvlckey = KEY_MOUSEWHEELDOWN;
    else
        i_yvlckey = KEY_MOUSEWHEELUP;

    if ([theEvent deltaX] < 0.0f)
        i_xvlckey = KEY_MOUSEWHEELRIGHT;
613
    else
614
        i_xvlckey = KEY_MOUSEWHEELLEFT;
615
616

    /* Send multiple key event, depending on the intensity of the event */
617
618
619
    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
620
621
622
623
624
625
    /* 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 );
    }
626
627
}

628
629
630
631
632
633
634
635
636
637
638
639
640
641
- (BOOL)keyEvent:(NSEvent *)o_event
{
    BOOL eventHandled = NO;
    unichar key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];

    if( key )
    {
        vout_thread_t *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT,
                                              FIND_ANYWHERE );
        if( p_vout != NULL )
        {
            /* Escape */
            if( key == (unichar) 0x1b )
            {
642
                id o_vout_view = [self voutView];
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
                if( o_vout_view && [o_vout_view isFullscreen] )
                {
                    [o_vout_view toggleFullscreen];
                    eventHandled = YES;
                }
            }
            else if( key == ' ' )
            {
                [self play:self];
                eventHandled = YES;
            }
            vlc_object_release( (vlc_object_t *)p_vout );
        }
    }
    return eventHandled;
}

hartman's avatar
* ALL:    
hartman committed
660
661
662
663
- (void)setupVarMenuItem:(NSMenuItem *)o_mi
                    target:(vlc_object_t *)p_object
                    var:(const char *)psz_variable
                    selector:(SEL)pf_callback
664
{
hartman's avatar
* ALL:    
hartman committed
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
    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;
    }
680
 
hartman's avatar
* ALL:    
hartman committed
681
682
683
684
685
686
687
688
    /* 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;
    }
689
 
hartman's avatar
* ALL:    
hartman committed
690
691
    /* Get the descriptive name of the variable */
    var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
hartman's avatar
hartman committed
692
    [o_mi setTitle: [[VLCMain sharedInstance] localizedString: text.psz_string ?
hartman's avatar
* ALL:    
hartman committed
693
                                        text.psz_string : strdup( psz_variable ) ]];
694

hartman's avatar
* ALL:    
hartman committed
695
696
    var_Get( p_object, psz_variable, &val );
    if( i_type & VLC_VAR_HASCHOICE )
697
    {
hartman's avatar
* ALL:    
hartman committed
698
699
700
701
        NSMenu *o_menu = [o_mi submenu];

        [self setupVarMenu: o_menu forMenuItem: o_mi target:p_object
                        var:psz_variable selector:pf_callback];
702
 
703
        free( text.psz_string );
hartman's avatar
* ALL:    
hartman committed
704
        return;
705
    }
hartman's avatar
* ALL:    
hartman committed
706

707
    VLCAutoGeneratedMenuContent *o_data;
hartman's avatar
* ALL:    
hartman committed
708
    switch( i_type & VLC_VAR_TYPE )
709
    {
hartman's avatar
* ALL:    
hartman committed
710
    case VLC_VAR_VOID:
711
712
        o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
                andValue: val ofType: i_type];
713
        [o_mi setRepresentedObject: [o_data autorelease]];
hartman's avatar
* ALL:    
hartman committed
714
715
716
        break;

    case VLC_VAR_BOOL:
717
718
        o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
                andValue: val ofType: i_type];
719
        [o_mi setRepresentedObject: [o_data autorelease]];
720
721
        if( !( i_type & VLC_VAR_ISCOMMAND ) )
            [o_mi setState: val.b_bool ? TRUE : FALSE ];
hartman's avatar
* ALL:    
hartman committed
722
723
724
        break;

    default:
725
        free( text.psz_string );
hartman's avatar
* ALL:    
hartman committed
726
        return;
727
    }
hartman's avatar
* ALL:    
hartman committed
728

729
    if( ( i_type & VLC_VAR_TYPE ) == VLC_VAR_STRING ) free( val.psz_string );
730
    free( text.psz_string );
731
}
732

hartman's avatar
* ALL:    
hartman committed
733
734
735
736
737
738

- (void)setupVarMenu:(NSMenu *)o_menu
                    forMenuItem: (NSMenuItem *)o_parent
                    target:(vlc_object_t *)p_object
                    var:(const char *)psz_variable
                    selector:(SEL)pf_callback
739
{
hartman's avatar
* ALL:    
hartman committed
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
    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 )
767
    {
hartman's avatar
* ALL:    
hartman committed
768
769
770
771
772
773
774
775
776
777
    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;
    }
778

hartman's avatar
* ALL:    
hartman committed
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
    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 )];

794
795
796
797
798
799
800
801
802
803
804
    /* 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
805
806
807
808
809
    for( i = 0; i < val_list.p_list->i_count; i++ )
    {
        vlc_value_t another_val;
        NSMenuItem * o_lmi;
        NSString *o_title = @"";
810
        VLCAutoGeneratedMenuContent *o_data;
hartman's avatar
* ALL:    
hartman committed
811
812

        switch( i_type & VLC_VAR_TYPE )
813
        {
hartman's avatar
* ALL:    
hartman committed
814
815
816
817
        case VLC_VAR_STRING:
            another_val.psz_string =
                strdup(val_list.p_list->p_values[i].psz_string);

hartman's avatar
hartman committed
818
            o_title = [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string ?
hartman's avatar
* ALL:    
hartman committed
819
820
821
                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: @""];
822
823
            o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: strdup(psz_variable) ofObject: p_object
                    andValue: another_val ofType: i_type];
824
            [o_lmi setRepresentedObject: [o_data autorelease]];
hartman's avatar
* ALL:    
hartman committed
825
            [o_lmi setTarget: self];
826

827
            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
828
829
830
831
832
833
834
                [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
835
                                 [[VLCMain sharedInstance] localizedString: strdup( text_list.p_list->p_values[i].psz_string )] :
hartman's avatar
* ALL:    
hartman committed
836
837
838
                                 [NSString stringWithFormat: @"%d",
                                 val_list.p_list->p_values[i].i_int];

hartman's avatar
hartman committed
839
            o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
840
841
            o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: strdup(psz_variable) ofObject: p_object
                    andValue: val_list.p_list->p_values[i] ofType: i_type];
842
            [o_lmi setRepresentedObject: [o_data autorelease]];
hartman's avatar
* ALL:    
hartman committed
843
844
            [o_lmi setTarget: self];

845
            if( val_list.p_list->p_values[i].i_int == val.i_int && !( i_type & VLC_VAR_ISCOMMAND ) )
hartman's avatar
* ALL:    
hartman committed
846
847
848
849
850
                [o_lmi setState: TRUE ];
            break;

        default:
          break;
851
852
        }
    }
853

854
855
856
857
858
859
860
861
    /* 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
862
    /* clean up everything */
863
    if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
hartman's avatar
* ALL:    
hartman committed
864
865
866
867
868
869
    var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list );
}

- (IBAction)toggleVar:(id)sender
{
    NSMenuItem *o_mi = (NSMenuItem *)sender;
870
    VLCAutoGeneratedMenuContent *o_data = [o_mi representedObject];
871
872
873
874
875
876
    [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
        toTarget: self withObject: o_data];

    return;
}

877
- (int)toggleVarThread: (id)data
878
{
hartman's avatar
* ALL:    
hartman committed
879
    vlc_object_t *p_object;
880
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
881
882
883

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

hartman's avatar
hartman committed
885
    vlc_thread_set_priority( VLCIntf , VLC_THREAD_PRIORITY_LOW );
hartman's avatar
* ALL:    
hartman committed
886

887
    p_object = [menuContent vlcObject];
hartman's avatar
* ALL:    
hartman committed
888

889
890
    if( p_object != NULL )
    {
891
        var_Set( p_object, [menuContent name], [menuContent value] );
892
893
        vlc_object_release( p_object );
        [o_pool release];
894
        return true;
895
896
897
    }
    [o_pool release];
    return VLC_EGENERIC;
898
899
}

900
901
902
903
904
905
906
907
908
- (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 )
    {
909
        input_thread_t * p_input = pl_CurrentInput( VLCIntf );
910
911
        if( p_input )
        {
912
913
            unsigned int timeInSec = 0;
            NSString * fieldContent = [o_specificTime_enter_fld stringValue];
914
            if( [[fieldContent componentsSeparatedByString: @":"] count] > 1 &&
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
                [[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));
936
937
            vlc_object_release( p_input );
        }
938

939
940
941
942
943
        [NSApp endSheet: o_specificTime_win];
        [o_specificTime_win close];
    }
    else
    {
944
        input_thread_t * p_input = pl_CurrentInput( VLCIntf );
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
        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 );
        }
    }
}

963
- (id)fspanel
964
965
966
967
968
969
970
971
972
973
{
    if( o_fs_panel )
        return o_fs_panel;
    else
    {
        msg_Err( VLCIntf, "FSPanel is nil" );
        return NULL;
    }
}

974
975
976
@end

@implementation VLCControls (NSMenuValidation)
977

978
979
980
- (BOOL)validateMenuItem:(NSMenuItem *)o_mi
{
    BOOL bEnabled = TRUE;
hartman's avatar
hartman committed
981
    vlc_value_t val;
hartman's avatar
hartman committed
982
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
983
    playlist_t * p_playlist = pl_Hold( p_intf );
984
    input_thread_t * p_input = playlist_CurrentInput( p_playlist );
985

hartman's avatar
hartman committed
986
    if( [[o_mi title] isEqualToString: _NS("Faster")] ||
987
988
        [[o_mi title] isEqualToString: _NS("Slower")] )
    {
989
        if( p_input != NULL )
990
        {
991
            bEnabled = var_GetBool( p_input, "can-rate" );
992
993
994
995
996
997
998
999
        }
        else
        {
            bEnabled = FALSE;
        }
    }
    else if( [[o_mi title] isEqualToString: _NS("Stop")] )
    {
1000
        if( p_input == NULL )
1001
1002
1003
        {
            bEnabled = FALSE;
        }
1004
        [o_main setupMenus]; /* Make sure input menu is up to date */
1005
    }
Jon Lech Johansen's avatar
Jon Lech Johansen committed
1006
    else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
1007
1008
             [[o_mi title] isEqualToString: _NS("Next")] )
    {
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
1009
        /** \todo fix i_size use */
1010
        PL_LOCK;
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
1011
        bEnabled = p_playlist->items.i_size > 1;
1012
        PL_UNLOCK;
1013
    }
1014
    else if( [[o_mi title] isEqualToString: _NS("Random")] )
1015
    {
hartman's avatar
hartman committed
1016
1017
1018
1019
1020
        int i_state;
        var_Get( p_playlist, "random", &val );
        i_state = val.b_bool ? NSOnState : NSOffState;
        [o_mi setState: i_state];
    }
1021
    else if( [[o_mi title] isEqualToString: _NS("Repeat One")] )
hartman's avatar
hartman committed
1022
1023
1024
1025
1026
1027
    {
        int i_state;
        var_Get( p_playlist, "repeat", &val );
        i_state = val.b_bool ? NSOnState : NSOffState;
        [o_mi setState: i_state];
    }
1028
    else if( [[o_mi title] isEqualToString: _NS("Repeat All")] )
hartman's avatar
hartman committed
1029
1030
1031
1032
    {
        int i_state;
        var_Get( p_playlist, "loop", &val );
        i_state = val.b_bool ? NSOnState : NSOffState;
1033
1034
        [o_mi setState: i_state];
    }
1035
    else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
1036
1037
             [[o_mi title] isEqualToString: _NS("Step Backward")] ||
             [[o_mi title] isEqualToString: _NS("Jump To Time")])
1038
    {
1039
        if( p_input != NULL )
1040
        {
1041
            var_Get( p_input, "can-seek", &val);
1042
            bEnabled = val.b_bool;
1043
        }
1044
        else bEnabled = FALSE;
1045
    }
1046
    else if( [[o_mi title] isEqualToString: _NS("Mute")] )
1047
1048
    {
        [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
1049
        [o_main setupMenus]; /* Make sure audio menu is up to date */
1050
    }
bigben's avatar
bigben committed
1051
    else if( [[o_mi title] isEqualToString: _NS("Half Size")] ||
1052
                [[o_mi title] isEqualToString: _NS("Normal Size")] ||
hartman's avatar
hartman committed
1053
                [[o_mi title] isEqualToString: _NS("Double Size")] ||
1054
                [[o_mi title] isEqualToString: _NS("Fit to Screen")] ||
1055
                [[o_mi title] isEqualToString: _NS("Snapshot")] ||