controls.m 34.5 KB
Newer Older
1
/*****************************************************************************
2
 * controls.m: MacOS X interface module
3
 *****************************************************************************
4
 * Copyright (C) 2002-2007 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 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
/* FIXME: I want to be Private */
162

163
- (id)getVoutView
164
{
165
166
167
168
169
    id window;
    id voutView = nil;
    id embeddedViewList = [[VLCMain sharedInstance] getEmbeddedList];
    NSEnumerator *enumerator = [[NSApp orderedWindows] objectEnumerator];
    while( !voutView && ( window = [enumerator nextObject] ) )
170
171
    {
        /* We have an embedded vout */
172
        if( [embeddedViewList windowContainsEmbedded: window] )
173
        {
174
            voutView = [embeddedViewList getViewForWindow: window];
175
176
        }
        /* We have a detached vout */
177
        else if( [[window className] isEqualToString: @"VLCVoutWindow"] )
178
179
        {
            msg_Dbg( VLCIntf, "detached vout controls.m call getVoutView" );
180
            voutView = [window getVoutView];
181
182
        }
    }
183
    return [[voutView retain] autorelease];
184
185
}

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

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

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

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

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

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

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

239
240
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_intf_update = true;
hartman's avatar
hartman committed
241
242
    vlc_object_release( p_playlist );
}
243

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

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

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

    vlc_object_release( p_playlist );
}


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

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

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

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

390
391
    p_intf->p_sys->b_playmode_update = true;
    p_intf->p_sys->b_intf_update = true;
392
393
394
    vlc_object_release( p_playlist );
}

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

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

408

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

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

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

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

444
445
446
447
448
449
450
- (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;
451
        var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_POSITION );
452
        vlc_object_release( (vlc_object_t *)p_vout );
453
454
455
456
    }
}

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

- (BOOL) isFullscreen {
462
    id o_vout_view = [self voutView];
463
464
465
466
467
468
469
    if( o_vout_view )
    {
        return [o_vout_view isFullscreen];
    }
    return NO;
}

470
- (IBAction)windowAction:(id)sender
471
{
472
    NSString *o_title = [sender title];
473

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

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

519
        pl_Release( VLCIntf );
bigben's avatar
bigben committed
520
521
    }

hartman's avatar
hartman committed
522
523
}

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

- (IBAction)telxNavLink:(id)sender;
{
    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 );
    }
}

565
566
567
- (void)scrollWheel:(NSEvent *)theEvent
{
    intf_thread_t * p_intf = VLCIntf;
568
569
570
    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;
571
572

    if ([theEvent deltaY] < 0.0f)
573
574
575
576
577
578
        i_yvlckey = KEY_MOUSEWHEELDOWN;
    else
        i_yvlckey = KEY_MOUSEWHEELUP;

    if ([theEvent deltaX] < 0.0f)
        i_xvlckey = KEY_MOUSEWHEELRIGHT;
579
    else
580
        i_xvlckey = KEY_MOUSEWHEELLEFT;
581
582

    /* Send multiple key event, depending on the intensity of the event */
583
584
585
    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
586
587
588
589
590
591
    /* 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 );
    }
592
593
}

594
595
596
597
598
599
600
601
602
603
604
605
606
607
- (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 )
            {
608
                id o_vout_view = [self voutView];
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
                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
626
627
628
629
- (void)setupVarMenuItem:(NSMenuItem *)o_mi
                    target:(vlc_object_t *)p_object
                    var:(const char *)psz_variable
                    selector:(SEL)pf_callback
630
{
hartman's avatar
* ALL:    
hartman committed
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
    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;
    }
646
 
hartman's avatar
* ALL:    
hartman committed
647
648
649
650
651
652
653
654
    /* 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;
    }
655
 
hartman's avatar
* ALL:    
hartman committed
656
657
    /* Get the descriptive name of the variable */
    var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
hartman's avatar
hartman committed
658
    [o_mi setTitle: [[VLCMain sharedInstance] localizedString: text.psz_string ?
hartman's avatar
* ALL:    
hartman committed
659
                                        text.psz_string : strdup( psz_variable ) ]];
660

hartman's avatar
* ALL:    
hartman committed
661
662
    var_Get( p_object, psz_variable, &val );
    if( i_type & VLC_VAR_HASCHOICE )
663
    {
hartman's avatar
* ALL:    
hartman committed
664
665
666
667
        NSMenu *o_menu = [o_mi submenu];

        [self setupVarMenu: o_menu forMenuItem: o_mi target:p_object
                        var:psz_variable selector:pf_callback];
668
 
669
        free( text.psz_string );
hartman's avatar
* ALL:    
hartman committed
670
        return;
671
    }
hartman's avatar
* ALL:    
hartman committed
672

673
    VLCAutoGeneratedMenuContent *o_data;
hartman's avatar
* ALL:    
hartman committed
674
    switch( i_type & VLC_VAR_TYPE )
675
    {
hartman's avatar
* ALL:    
hartman committed
676
    case VLC_VAR_VOID:
677
678
        o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
                andValue: val ofType: i_type];
hartman's avatar
* ALL:    
hartman committed
679
680
681
682
        [o_mi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
        break;

    case VLC_VAR_BOOL:
683
684
        o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
                andValue: val ofType: i_type];
hartman's avatar
* ALL:    
hartman committed
685
        [o_mi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
686
687
        if( !( i_type & VLC_VAR_ISCOMMAND ) )
            [o_mi setState: val.b_bool ? TRUE : FALSE ];
hartman's avatar
* ALL:    
hartman committed
688
689
690
        break;

    default:
691
        free( text.psz_string );
hartman's avatar
* ALL:    
hartman committed
692
        return;
693
    }
hartman's avatar
* ALL:    
hartman committed
694

695
    if( ( i_type & VLC_VAR_TYPE ) == VLC_VAR_STRING ) free( val.psz_string );
696
    free( text.psz_string );
697
}
698

hartman's avatar
* ALL:    
hartman committed
699
700
701
702
703
704

- (void)setupVarMenu:(NSMenu *)o_menu
                    forMenuItem: (NSMenuItem *)o_parent
                    target:(vlc_object_t *)p_object
                    var:(const char *)psz_variable
                    selector:(SEL)pf_callback
705
{
hartman's avatar
* ALL:    
hartman committed
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
    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 )
733
    {
hartman's avatar
* ALL:    
hartman committed
734
735
736
737
738
739
740
741
742
743
    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;
    }
744

hartman's avatar
* ALL:    
hartman committed
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
    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 )];

    for( i = 0; i < val_list.p_list->i_count; i++ )
    {
        vlc_value_t another_val;
        NSMenuItem * o_lmi;
        NSString *o_title = @"";
765
        VLCAutoGeneratedMenuContent *o_data;
hartman's avatar
* ALL:    
hartman committed
766
767

        switch( i_type & VLC_VAR_TYPE )
768
        {
hartman's avatar
* ALL:    
hartman committed
769
770
771
772
        case VLC_VAR_STRING:
            another_val.psz_string =
                strdup(val_list.p_list->p_values[i].psz_string);

hartman's avatar
hartman committed
773
            o_title = [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string ?
hartman's avatar
* ALL:    
hartman committed
774
775
776
                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: @""];
777
778
            o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: strdup(psz_variable) ofObject: p_object
                    andValue: another_val ofType: i_type];
hartman's avatar
* ALL:    
hartman committed
779
780
            [o_lmi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
            [o_lmi setTarget: self];
781

782
            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
783
784
785
786
787
788
789
                [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
790
                                 [[VLCMain sharedInstance] localizedString: strdup( text_list.p_list->p_values[i].psz_string )] :
hartman's avatar
* ALL:    
hartman committed
791
792
793
794
                                 [NSString stringWithFormat: @"%d",
                                 val_list.p_list->p_values[i].i_int];

            o_lmi = [[o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""] retain ];
795
796
            o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: strdup(psz_variable) ofObject: p_object
                    andValue: val_list.p_list->p_values[i] ofType: i_type];
hartman's avatar
* ALL:    
hartman committed
797
798
799
            [o_lmi setRepresentedObject: [NSValue valueWithPointer:[ o_data retain]]];
            [o_lmi setTarget: self];

800
            if( val_list.p_list->p_values[i].i_int == val.i_int && !( i_type & VLC_VAR_ISCOMMAND ) )
hartman's avatar
* ALL:    
hartman committed
801
802
803
804
805
                [o_lmi setState: TRUE ];
            break;

        default:
          break;
806
807
        }
    }
808

hartman's avatar
* ALL:    
hartman committed
809
    /* clean up everything */
810
    if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
hartman's avatar
* ALL:    
hartman committed
811
812
813
814
815
816
    var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list );
}

- (IBAction)toggleVar:(id)sender
{
    NSMenuItem *o_mi = (NSMenuItem *)sender;
817
    VLCAutoGeneratedMenuContent *o_data = [[o_mi representedObject] pointerValue];
818
819
820
821
822
823
    [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
        toTarget: self withObject: o_data];

    return;
}

824
- (int)toggleVarThread: (id)data
825
{
hartman's avatar
* ALL:    
hartman committed
826
    vlc_object_t *p_object;
827
    NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
828
829
830

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

hartman's avatar
hartman committed
832
    vlc_thread_set_priority( VLCIntf , VLC_THREAD_PRIORITY_LOW );
hartman's avatar
* ALL:    
hartman committed
833

834
    p_object = [menuContent vlcObject];
hartman's avatar
* ALL:    
hartman committed
835

836
837
    if( p_object != NULL )
    {
838
        var_Set( p_object, [menuContent name], [menuContent value] );
839
840
        vlc_object_release( p_object );
        [o_pool release];
841
        return true;
842
843
844
    }
    [o_pool release];
    return VLC_EGENERIC;
845
846
}

847
848
849
850
851
852
853
854
855
- (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 )
    {
856
        input_thread_t * p_input = pl_CurrentInput( VLCIntf );
857
858
        if( p_input )
        {
859
860
            unsigned int timeInSec = 0;
            NSString * fieldContent = [o_specificTime_enter_fld stringValue];
861
            if( [[fieldContent componentsSeparatedByString: @":"] count] > 1 &&
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
                [[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));
883
884
            vlc_object_release( p_input );
        }
885

886
887
888
889
890
        [NSApp endSheet: o_specificTime_win];
        [o_specificTime_win close];
    }
    else
    {
891
        input_thread_t * p_input = pl_CurrentInput( VLCIntf );
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
        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 );
        }
    }
}

910
911
912
913
914
915
916
917
918
919
920
- (id)getFSPanel
{
    if( o_fs_panel )
        return o_fs_panel;
    else
    {
        msg_Err( VLCIntf, "FSPanel is nil" );
        return NULL;
    }
}

921
922
923
@end

@implementation VLCControls (NSMenuValidation)
924

925
926
927
- (BOOL)validateMenuItem:(NSMenuItem *)o_mi
{
    BOOL bEnabled = TRUE;
hartman's avatar
hartman committed
928
    vlc_value_t val;
hartman's avatar
hartman committed
929
    intf_thread_t * p_intf = VLCIntf;
dionoea's avatar
dionoea committed
930
    playlist_t * p_playlist = pl_Hold( p_intf );
931
    input_thread_t * p_input = playlist_CurrentInput( p_playlist );
932

hartman's avatar
hartman committed
933
    if( [[o_mi title] isEqualToString: _NS("Faster")] ||
934
935
        [[o_mi title] isEqualToString: _NS("Slower")] )
    {
936
        if( p_input != NULL )
937
        {
938
            bEnabled = p_input->b_can_pace_control;
939
940
941
942
943
944
945
946
        }
        else
        {
            bEnabled = FALSE;
        }
    }
    else if( [[o_mi title] isEqualToString: _NS("Stop")] )
    {
947
        if( p_input == NULL )
948
949
950
        {
            bEnabled = FALSE;
        }
951
        [o_main setupMenus]; /* Make sure input menu is up to date */
952
    }
Jon Lech Johansen's avatar
Jon Lech Johansen committed
953
    else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
954
955
             [[o_mi title] isEqualToString: _NS("Next")] )
    {
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
956
        /** \todo fix i_size use */
957
        PL_LOCK;
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
958
        bEnabled = p_playlist->items.i_size > 1;
959
        PL_UNLOCK;
960
    }
961
    else if( [[o_mi title] isEqualToString: _NS("Random")] )
962
    {
hartman's avatar
hartman committed
963
964
965
966
967
        int i_state;
        var_Get( p_playlist, "random", &val );
        i_state = val.b_bool ? NSOnState : NSOffState;
        [o_mi setState: i_state];
    }
968
    else if( [[o_mi title] isEqualToString: _NS("Repeat One")] )
hartman's avatar
hartman committed
969
970
971
972
973
974
    {
        int i_state;
        var_Get( p_playlist, "repeat", &val );
        i_state = val.b_bool ? NSOnState : NSOffState;
        [o_mi setState: i_state];
    }
975
    else if( [[o_mi title] isEqualToString: _NS("Repeat All")] )
hartman's avatar
hartman committed
976
977
978
979
    {
        int i_state;
        var_Get( p_playlist, "loop", &val );
        i_state = val.b_bool ? NSOnState : NSOffState;
980
981
        [o_mi setState: i_state];
    }
982
    else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
983
984
             [[o_mi title] isEqualToString: _NS("Step Backward")] ||
             [[o_mi title] isEqualToString: _NS("Jump To Time")])
985
    {
986
        if( p_input != NULL )
987
        {
988
            var_Get( p_input, "seekable", &val);
989
            bEnabled = val.b_bool;
990
        }
991
        else bEnabled = FALSE;
992
    }
993
    else if( [[o_mi title] isEqualToString: _NS("Mute")] )
994
995
    {
        [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
996
        [o_main setupMenus]; /* Make sure audio menu is up to date */
997
    }
bigben's avatar
bigben committed
998
    else if( [[o_mi title] isEqualToString: _NS("Half Size")] ||
999
                [[o_mi title] isEqualToString: _NS("Normal Size")] ||
hartman's avatar
hartman committed
1000
                [[o_mi title] isEqualToString: _NS("Double Size")] ||
1001
                [[o_mi title] isEqualToString: _NS("Fit to Screen")] ||
1002
                [[o_mi title] isEqualToString: _NS("Snapshot")] ||
1003
                [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
1004
                [[o_mi title] isEqualToString: _NS("Float on Top")] )
1005
    {
1006
        id o_window;
1007
        NSArray *o_windows = [NSApp orderedWindows];
1008
1009
        NSEnumerator *o_enumerator = [o_windows objectEnumerator];
        bEnabled = FALSE;
1010
 
1011
1012
1013
        vout_thread_t   *p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
                                              FIND_ANYWHERE );
        if( p_vout != NULL )
1014
        {
1015
            if( [[o_mi title] isEqualToString: _NS("Float on Top")] )