vout.m 34.2 KB
Newer Older
1
/*****************************************************************************
2
 * vout.m: MacOS X video output module
3
 *****************************************************************************
4
 * Copyright (C) 2001-2008 the VideoLAN team
bigben's avatar
...    
bigben committed
5
 * $Id$
6
7
8
9
 *
 * Authors: Colin Delacroix <colin@zoy.org>
 *          Florian G. Pflug <fgp@phlo.org>
 *          Jon Lech Johansen <jon-vl@nanocrew.net>
10
 *          Derk-Jan Hartman <hartman at videolan dot org>
11
 *          Eric Petit <titer@m0k.org>
12
 *          Benjamin Pracht <bigben at videolan dot org>
13
 *          Felix Paul Kühne <fkuehne at videolan dot org>
14
15
16
17
18
 *
 * 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.
19
 *
20
21
22
23
24
25
26
 * 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
27
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
28
29
30
31
32
33
34
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <errno.h>                                                 /* ENOMEM */
#include <stdlib.h>                                                /* free() */
35
#include <string.h>
36

Eric Petit's avatar
Eric Petit committed
37
/* BeginFullScreen, EndFullScreen */
38
39
#include <QuickTime/QuickTime.h>

40
41
#include <vlc_keys.h>

42
#include "intf.h"
43
#include "fspanel.h"
44
#include "vout.h"
45
#import "controls.h"
46
#import "embeddedwindow.h"
47
48
49
50
51
52
53
54
55

/*****************************************************************************
 * DeviceCallback: Callback triggered when the video-device variable is changed
 *****************************************************************************/
int DeviceCallback( vlc_object_t *p_this, const char *psz_variable,
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    vlc_value_t val;
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
56

57
    msg_Dbg( p_vout, "set %d", new_val.i_int );
58
59
    var_Create( p_vout->p_libvlc, "video-device", VLC_VAR_INTEGER );
    var_Set( p_vout->p_libvlc, "video-device", new_val );
60

61
    val.b_bool = true;
62
63
64
65
66
    var_Set( p_vout, "intf-change", val );
    return VLC_SUCCESS;
}


67
/*****************************************************************************
68
 * VLCEmbeddedList implementation
69
 *****************************************************************************/
70
@implementation VLCEmbeddedList
71

72
- (id)init
73
{
74
75
    [super init];
    o_embedded_array = [NSMutableArray array];
76
77
78
    return self;
}

79
- (id)getEmbeddedVout
80
{
81
    unsigned int i;
82

83
    for( i = 0; i < [o_embedded_array count]; i++ )
84
    {
85
86
        id o_vout_view = [o_embedded_array objectAtIndex: i];
        if( ![o_vout_view isUsed] )
87
        {
88
89
            [o_vout_view setUsed: YES];
            return o_vout_view;
90
        }
91
92
93
    }
    return nil;
}
94

95
96
97
98
99
- (void)releaseEmbeddedVout: (id)o_vout_view
{
    if( [o_embedded_array containsObject: o_vout_view] )
    {
        [o_vout_view setUsed: NO];
100
    }
101
    else
102
    {
103
        msg_Warn( VLCIntf, "cannot find Video Output");
104
    }
105
}
106

107
108
109
- (void)addEmbeddedVout: (id)o_vout_view
{
    if( ![o_embedded_array containsObject: o_vout_view] )
110
    {
111
        [o_embedded_array addObject: o_vout_view];
112
    }
113
114
115
116
}

- (BOOL)windowContainsEmbedded: (id)o_window
{
117
/*    if( ![[o_window className] isEqualToString: @"VLCVoutWindow"] )
118
    {
119
        NSLog( @"We were not given a VLCVoutWindow" );
120
    }*/
121
    return ([self getViewForWindow: o_window] == nil ? NO : YES );
122
123
124
125
126
127
128
129
}

- (id)getViewForWindow: (id)o_window
{
    id o_enumerator = [o_embedded_array objectEnumerator];
    id o_current_embedded;

    while( (o_current_embedded = [o_enumerator nextObject]) )
130
    {
131
132
133
134
        if( [o_current_embedded getWindow] == o_window )
        {
            return o_current_embedded;
        }
135
    }
136
137
    return nil;
}
138

139
@end
140

141
142
143
144
145
/*****************************************************************************
 * VLCVoutView implementation
 *****************************************************************************/
@implementation VLCVoutView

146
- (id)initWithFrame: (NSRect)frameRect
147
148
149
150
151
152
153
154
155
156
157
{
    [super initWithFrame: frameRect];
    p_vout = NULL;
    o_view = nil;
    s_frame = &frameRect;

    p_real_vout = NULL;
    o_window = nil;
    return self;
}

Felix Paul Kühne's avatar
typo    
Felix Paul Kühne committed
158
159
- (BOOL)setVout: (vout_thread_t *) vout
        subView: (NSView *) view
160
          frame: (NSRect *) frame
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
{
    int i_device;
    NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
    NSArray *o_screens = [NSScreen screens];

    p_vout  = vout;
    o_view  = view;
    s_frame = frame;

    if( [o_screens count] <= 0 )
    {
        msg_Err( p_vout, "no OSX screens available" );
        return NO;
    }

    p_real_vout = [VLCVoutView getRealVout: p_vout];
177

178
    /* Get the pref value when this is the first time, otherwise retrieve the device from the top level video-device var */
179
    if( var_Type( p_real_vout->p_libvlc, "video-device" ) == 0 )
180
181
182
183
184
    {
        i_device = var_GetInteger( p_vout, "macosx-vdev" );
    }
    else
    {
185
        i_device = var_GetInteger( p_real_vout->p_libvlc, "video-device" );
186
187
188
189
    }

    /* Setup the menuitem for the multiple displays. */
    if( var_Type( p_real_vout, "video-device" ) == 0 )
190
191
    {
        int i = 1;
192
        vlc_value_t val2, text;
193
194
195
196
        NSScreen * o_screen;

        var_Create( p_real_vout, "video-device", VLC_VAR_INTEGER |
                                            VLC_VAR_HASCHOICE );
197
        text.psz_string = _("Fullscreen Video Device");
198
199
200
201
        var_Change( p_real_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );

        NSEnumerator * o_enumerator = [o_screens objectEnumerator];

202
203
204
205
206
207
        val2.i_int = 0;
        text.psz_string = _("Default");
        var_Change( p_real_vout, "video-device",
                        VLC_VAR_ADDCHOICE, &val2, &text );
        var_Set( p_real_vout, "video-device", val2 );

208
209
210
211
212
213
214
215
216
217
        while( (o_screen = [o_enumerator nextObject]) != NULL )
        {
            char psz_temp[255];
            NSRect s_rect = [o_screen frame];

            snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
                      "%s %d (%dx%d)", _("Screen"), i,
                      (int)s_rect.size.width, (int)s_rect.size.height );

            text.psz_string = psz_temp;
218
            val2.i_int = (int)[o_screen displayID];
219
220
            var_Change( p_real_vout, "video-device",
                        VLC_VAR_ADDCHOICE, &val2, &text );
221
            if( (int)[o_screen displayID] == i_device )
222
223
224
225
226
227
            {
                var_Set( p_real_vout, "video-device", val2 );
            }
            i++;
        }

228
        var_AddCallback( p_real_vout, "video-device", DeviceCallback,
229
230
                         NULL );

231
        val2.b_bool = true;
232
233
234
        var_Set( p_real_vout, "intf-change", val2 );
    }

235
    /* Add the view. It's automatically resized to fit the window */
236
237
    [self addSubview: o_view];
    [self setAutoresizesSubviews: YES];
hartman's avatar
-    
hartman committed
238
    [o_pool release];
239

240
    return YES;
241
242
}

243
- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize
244
{
245
246
    [super resizeSubviewsWithOldSize: oldBoundsSize];
    [o_view setFrameSize: [self frame].size];
247
248
}

249
250
251
252
253
254
255
256
257
- (void)drawRect:(NSRect)rect
{
    /* When there is no subview we draw a black background */
    [self lockFocus];
    [[NSColor blackColor] set];
    NSRectFill(rect);
    [self unlockFocus];
}

258
- (void)closeVout
259
{
260
261
    [[[[VLCMain sharedInstance] getControls] getFSPanel] fadeOut];

262
263
    /* Make sure we don't see a white flash */
    [[self window] disableScreenUpdatesUntilFlush];
264
265
266
267
268
    [o_view removeFromSuperview];
    o_view = nil;
    p_vout = NULL;
    s_frame = nil;
    o_window = nil;
269
    p_real_vout = NULL;
Eric Petit's avatar
Eric Petit committed
270
}
271

272
273
- (void)updateTitle
{
274
275
    NSString * o_title = nil; 
    NSMutableString * o_mrl = nil;
276
277
278
279
280
281
282
283
284
285
286
287
288
289
    input_thread_t * p_input;

    if( p_vout == NULL )
    {
        return;
    }

    p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT );

    if( p_input == NULL )
    {
        return;
    }

290
    char *psz_nowPlaying = input_item_GetNowPlaying ( input_GetItem( p_input ) );
291
292
    char *psz_name = input_item_GetName( input_GetItem( p_input ) );
    char *psz_uri = input_item_GetURI( input_GetItem( p_input ) );
293
294
295
296
297
    if( psz_nowPlaying != NULL )
        o_title = [NSString stringWithUTF8String: psz_nowPlaying];
    else if( psz_name != NULL )
        o_title = [NSString stringWithUTF8String: psz_name];

298
299
    if( psz_uri != NULL )
        o_mrl = [NSMutableString stringWithUTF8String: psz_uri];
300
301
302
303
304

    FREENULL( psz_nowPlaying );
    FREENULL( psz_name );
    FREENULL( psz_uri );

305
306
307
308
309
    if( o_title == nil )
        o_title = o_mrl;

    if( o_mrl != nil )
    {
310
311
312
313
314
315
316
317
        /* FIXME once psz_access is exported, we could check if we are
         * reading from a file in a smarter way. */

        NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
        if( prefix_range.location != NSNotFound )
            [o_mrl deleteCharactersInRange: prefix_range];

        if( [o_mrl characterAtIndex:0] == '/' )
318
        {
319
            /* it's a local file */
320
321
            [o_window setRepresentedFilename: o_mrl];
        }
322
323
324
325
326
327
        else
        {
            /* it's from the network or somewhere else,
             * we clear the previous path */
            [o_window setRepresentedFilename: @""];
        }
328
329
330
331
        [o_window setTitle: o_title];
    }
    else
    {
332
        [o_window setTitle: [NSString stringWithUTF8String: VOUT_TITLE]];
333
334
335
336
337
    }
    vlc_object_release( p_input );
}


hartman's avatar
hartman committed
338
- (void)setOnTop:(BOOL)b_on_top
Eric Petit's avatar
Eric Petit committed
339
340
{
    if( b_on_top )
341
    {
342
        [o_window setLevel: NSStatusWindowLevel];
343
344
345
    }
    else
    {
346
        [o_window setLevel: NSNormalWindowLevel];
347
    }
348
349
}

350
- (void)scaleWindowWithFactor: (float)factor animate: (BOOL)animate
351
352
{
    NSSize newsize;
353
    int i_corrected_height, i_corrected_width;
hartman's avatar
hartman committed
354
355
    NSPoint topleftbase;
    NSPoint topleftscreen;
356

hartman's avatar
hartman committed
357
358
    if ( !p_vout->b_fullscreen )
    {
359
        NSView *mainView;
360
        NSRect new_frame;
hartman's avatar
hartman committed
361
        topleftbase.x = 0;
362
363
364
365
        topleftbase.y = [o_window frame].size.height;
        topleftscreen = [o_window convertBaseToScreen: topleftbase];

        if( p_vout->render.i_height * p_vout->render.i_aspect >
Eric Petit's avatar
Eric Petit committed
366
                        p_vout->render.i_width * VOUT_ASPECT_FACTOR )
367
        {
Eric Petit's avatar
Eric Petit committed
368
            i_corrected_width = p_vout->render.i_height * p_vout->render.i_aspect /
369
370
371
372
373
374
                                            VOUT_ASPECT_FACTOR;
            newsize.width = (int) ( i_corrected_width * factor );
            newsize.height = (int) ( p_vout->render.i_height * factor );
        }
        else
        {
Eric Petit's avatar
Eric Petit committed
375
376
            i_corrected_height = p_vout->render.i_width * VOUT_ASPECT_FACTOR /
                                            p_vout->render.i_aspect;
377
378
379
            newsize.width = (int) ( p_vout->render.i_width * factor );
            newsize.height = (int) ( i_corrected_height * factor );
        }
380

381
382
383
384
385
386
387
        /* In fullscreen mode we need to use a view that is different from
         * ourselves, with the VLCEmbeddedWindow */
        if([o_window isKindOfClass:[VLCEmbeddedWindow class]])
            mainView = [o_window mainView];
        else
            mainView = self;

388
389
        /* Calculate the window's new size */
        new_frame.size.width = [o_window frame].size.width -
390
                                    [mainView frame].size.width + newsize.width;
391
        new_frame.size.height = [o_window frame].size.height -
392
                                    [mainView frame].size.height + newsize.height;
393
394
395
396

        new_frame.origin.x = topleftscreen.x;
        new_frame.origin.y = topleftscreen.y - new_frame.size.height;

397
        [o_window setFrame: new_frame display: animate animate: animate];
398

hartman's avatar
hartman committed
399
400
        p_vout->i_changes |= VOUT_SIZE_CHANGE;
    }
401
402
}

hartman's avatar
hartman committed
403
404
- (void)toggleFloatOnTop
{
405
    vlc_value_t val;
406

407
    if( !p_real_vout ) return;
408
    if( var_Get( p_real_vout, "video-on-top", &val )>=0 && val.b_bool)
hartman's avatar
hartman committed
409
    {
410
        val.b_bool = false;
hartman's avatar
hartman committed
411
412
413
    }
    else
    {
414
        val.b_bool = true;
hartman's avatar
hartman committed
415
    }
416
    var_Set( p_real_vout, "video-on-top", val );
hartman's avatar
hartman committed
417
418
}

419
420
- (void)toggleFullscreen
{
421
    vlc_value_t val;
422
    if( !p_real_vout ) return;
423
424
    var_Get( p_real_vout, "fullscreen", &val );
    val.b_bool = !val.b_bool;
425
    var_Set( p_real_vout, "fullscreen", val );
426
427
428
429
}

- (BOOL)isFullscreen
{
430
    vlc_value_t val;
431
    if( !p_real_vout ) return NO;
432
433
    var_Get( p_real_vout, "fullscreen", &val );
    return( val.b_bool );
434
435
}

436
437
- (void)snapshot
{
438
    vout_Control( p_real_vout, VOUT_SNAPSHOT );
439
440
}

441
- (void)manage
442
{
443
    /* Disable Screensaver, when we're playing something, but allow it on pause */
444
445
446
    if( !VLCIntf || !VLCIntf->p_sys || !VLCIntf->p_sys->i_play_status )
        return;

447
448
    if( VLCIntf->p_sys->i_play_status == PLAYING_S )
        UpdateSystemActivity( UsrActivity );
449
}
450

451
- (id)getWindow
452
{
453
454
    return o_window;
}
455

456
457
458
- (void)scrollWheel:(NSEvent *)theEvent
{
    VLCControls * o_controls = (VLCControls *)[[NSApp delegate] getControls];
459
    [o_controls scrollWheel: theEvent];
460
461
}

462
463
464
- (void)keyDown:(NSEvent *)o_event
{
    unichar key = 0;
465
    vlc_value_t val;
466
    unsigned int i_pressed_modifiers = 0;
467
    val.i_int = 0;
468

469
    i_pressed_modifiers = [o_event modifierFlags];
470

471
472
473
474
475
476
477
478
    if( i_pressed_modifiers & NSShiftKeyMask )
        val.i_int |= KEY_MODIFIER_SHIFT;
    if( i_pressed_modifiers & NSControlKeyMask )
        val.i_int |= KEY_MODIFIER_CTRL;
    if( i_pressed_modifiers & NSAlternateKeyMask )
        val.i_int |= KEY_MODIFIER_ALT;
    if( i_pressed_modifiers & NSCommandKeyMask )
        val.i_int |= KEY_MODIFIER_COMMAND;
479

480
    key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
481

482
483
    if( key )
    {
484
485
486
        /* Escape should always get you out of fullscreen */
        if( key == (unichar) 0x1b )
        {
487
             if( p_real_vout && [self isFullscreen] )
488
489
490
491
492
493
             {
                 [self toggleFullscreen];
             }
        }
        else if ( key == ' ' )
        {
494
495
            vlc_value_t val;
            val.i_int = config_GetInt( p_vout, "key-play-pause" );
496
            var_Set( p_vout->p_libvlc, "key-pressed", val );
497
498
499
        }
        else
        {
500
            val.i_int |= CocoaKeyToVLC( key );
501
            var_Set( p_vout->p_libvlc, "key-pressed", val );
502
        }
503
504
505
506
    }
    else
    {
        [super keyDown: o_event];
507
508
509
    }
}

510
- (void)mouseDown:(NSEvent *)o_event
511
{
512
513
514
    vlc_value_t val;

    if( p_vout )
515
    {
516
517
        if( ( [o_event type] == NSLeftMouseDown ) &&
          ( ! ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
518
        {
519
            if( [o_event clickCount] <= 1 )
520
            {
521
522
523
524
                /* single clicking */
                var_Get( p_vout, "mouse-button-down", &val );
                val.i_int |= 1;
                var_Set( p_vout, "mouse-button-down", val );
525
            }
526
            else
527
            {
528
529
                /* multiple clicking */
                [self toggleFullscreen];
530
            }
531
        }
532
533
534
535
536
537
538
        else if( ( [o_event type] == NSRightMouseDown ) ||
               ( ( [o_event type] == NSLeftMouseDown ) &&
                 ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
        {
            msg_Dbg( p_vout, "received NSRightMouseDown (generic method) or Ctrl clic" );
            [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] getVoutView]];
        }
539
    }
540
541

    [super mouseDown: o_event];
542
543
544
545
546
547
}

- (void)otherMouseDown:(NSEvent *)o_event
{
    vlc_value_t val;

548
    if( p_vout && [o_event type] == NSOtherMouseDown )
549
    {
550
551
552
        var_Get( p_vout, "mouse-button-down", &val );
        val.i_int |= 2;
        var_Set( p_vout, "mouse-button-down", val );
553
    }
554
555

    [super mouseDown: o_event];
556
}
557

558
559
- (void)rightMouseDown:(NSEvent *)o_event
{
560
    if( p_vout && [o_event type] == NSRightMouseDown )
561
    {
562
563
        msg_Dbg( p_vout, "received NSRightMouseDown (specific method)" );
        [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] getVoutView]];
564
    }
565
566

    [super mouseDown: o_event];
567
568
569
570
571
572
}

- (void)mouseUp:(NSEvent *)o_event
{
    vlc_value_t val;

573
    if( p_vout && [o_event type] == NSLeftMouseUp )
574
    {
575
        vlc_value_t b_val;
576
        b_val.b_bool = true;
577
        var_Set( p_vout, "mouse-clicked", b_val );
578

579
580
581
        var_Get( p_vout, "mouse-button-down", &val );
        val.i_int &= ~1;
        var_Set( p_vout, "mouse-button-down", val );
582
    }
583
584

    [super mouseUp: o_event];
585
586
}

587
- (void)otherMouseUp:(NSEvent *)o_event
588
{
589
590
    vlc_value_t val;

591
    if( p_vout && [o_event type] == NSOtherMouseUp )
592
    {
593
594
595
        var_Get( p_vout, "mouse-button-down", &val );
        val.i_int &= ~2;
        var_Set( p_vout, "mouse-button-down", val );
596
    }
597
598

    [super mouseUp: o_event];
599
}
600

601
602
- (void)rightMouseUp:(NSEvent *)o_event
{
603
    if( p_vout && [o_event type] == NSRightMouseUp )
604
    {
605
606
        /* FIXME: this isn't the appropriate place, but we can't receive
         * NSRightMouseDown some how */
607
        msg_Dbg( p_vout, "received NSRightMouseUp" );
608
        [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] getVoutView]];
609
    }
610
611

    [super mouseUp: o_event];
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
}

- (void)mouseDragged:(NSEvent *)o_event
{
    [self mouseMoved: o_event];
}

- (void)otherMouseDragged:(NSEvent *)o_event
{
    [self mouseMoved: o_event];
}

- (void)rightMouseDragged:(NSEvent *)o_event
{
    [self mouseMoved: o_event];
}

- (void)mouseMoved:(NSEvent *)o_event
{
    NSPoint ml;
    NSRect s_rect;
    BOOL b_inside;

    if( p_vout )
    {
        s_rect = [o_view bounds];
        ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
        b_inside = [o_view mouse: ml inRect: s_rect];

        if( b_inside )
        {
            vlc_value_t val;
            unsigned int i_width, i_height, i_x, i_y;

            vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
                                       (unsigned int)s_rect.size.height,
                                       &i_x, &i_y, &i_width, &i_height );

            val.i_int = ( ((int)ml.x) - i_x ) *
                        p_vout->render.i_width / i_width;
            var_Set( p_vout, "mouse-x", val );

            if( [[o_view className] isEqualToString: @"VLCGLView"] )
            {
                val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
                            p_vout->render.i_height / i_height;
            }
            else
            {
                val.i_int = ( ((int)ml.y) - i_y ) *
                            p_vout->render.i_height / i_height;
            }
            var_Set( p_vout, "mouse-y", val );

666
            val.b_bool = true;
667
668
            var_Set( p_vout, "mouse-moved", val );
        }
669
670
        if( [self isFullscreen] )
            [[[[VLCMain sharedInstance] getControls] getFSPanel] fadeIn];
671
    }
672

673
    [super mouseMoved: o_event];
674
675
}

Eric Petit's avatar
Eric Petit committed
676
677
678
- (BOOL)acceptsFirstResponder
{
    return YES;
679
680
}

Eric Petit's avatar
Eric Petit committed
681
- (BOOL)becomeFirstResponder
682
{
Eric Petit's avatar
Eric Petit committed
683
    return YES;
684
685
}

Eric Petit's avatar
Eric Petit committed
686
- (BOOL)resignFirstResponder
687
{
Eric Petit's avatar
Eric Petit committed
688
689
690
691
    /* We need to stay the first responder or we'll miss some
       events */
    return NO;
}
692

693
/* Class methods used by the different vout modules */
694

695
696
697
698
699
700
+ (vout_thread_t *)getRealVout: (vout_thread_t *)p_vout
{
    /* p_real_vout: the vout we have to use to check for video-on-top
       and a few other things. If we are the QuickTime output, it's us.
       It we are the OpenGL provider, it is our parent. */
    if( p_vout->i_object_type == VLC_OBJECT_OPENGL )
701
    {
702
        return (vout_thread_t *) p_vout->p_parent;
703
    }
704
705
706
707
708
    else
    {
        return p_vout;
    }

709
710
}

711
712
+ (id)getVoutView: (vout_thread_t *)p_vout subView: (NSView *)view
                                    frame: (NSRect *)s_frame
713
{
714
715
716
717
    vlc_value_t value_drawable;
    int i_timeout;
    id o_return = nil;

718
    var_Get( p_vout->p_libvlc, "drawable", &value_drawable );
719
720
721
722
723

    var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
    var_Create( p_vout, "macosx-background", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
724
    var_Create( p_vout, "macosx-black", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
725
    var_Create( p_vout, "embedded-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
726
727
728
729
730
731

    /* We only wait for NSApp to initialise if we're not embedded (as in the
     * case of the Mozilla plugin).  We can tell whether we're embedded or not
     * by examining the "drawable" value: if it's zero, we're running in the
     * main Mac intf; if it's non-zero, we're embedded. */
    if( value_drawable.i_int == 0 )
732
    {
733
734
        /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
        for( i_timeout = 20 ; i_timeout-- ; )
Eric Petit's avatar
Eric Petit committed
735
        {
736
737
738
739
740
741
742
743
744
745
746
            if( NSApp == NULL )
            {
                msleep( INTF_IDLE_SLEEP );
            }
        }

        if( NSApp == NULL )
        {
            /* No MacOS X intf, unable to communicate with MT */
            msg_Err( p_vout, "no MacOS X interface present" );
            return nil;
Eric Petit's avatar
Eric Petit committed
747
        }
748
749
750
        else
        {
            if ( VLCIntf && !(p_vout->b_fullscreen) &&
751
                        !(var_GetBool( p_vout, "macosx-background" )) &&
752
                        var_GetBool( p_vout, "embedded-video") )
753
754
755
756
757
758
            {
                o_return = [[[VLCMain sharedInstance] getEmbeddedList]
                                                            getEmbeddedVout];
            }
        }
    }
759

760
761
762
763
764
765
    /* No embedded vout is available */
    if( o_return == nil )
    {
        NSRect null_rect;
        bzero( &null_rect, sizeof( NSRect ) );
        o_return = [[VLCDetachedVoutView alloc] initWithFrame: null_rect ];
766
    }
767
768
    [o_return setVout: p_vout subView: view frame: s_frame];
    return o_return;
769
770
}

771
772
- (void)enterFullscreen
{
773
774
775
776
777
    if( var_GetBool( p_real_vout, "video-on-top" ) )
    {
        [o_window setLevel: NSNormalWindowLevel];
    }

778
    [[o_view class] performSelectorOnMainThread:@selector(resetVout:) withObject:[NSValue valueWithPointer:p_vout] waitUntilDone:YES];
779
780
781
782
783
    [[[[VLCMain sharedInstance] getControls] getFSPanel] setActive: nil];
}

- (void)leaveFullscreen
{
784
785
786
787
788
    if( var_GetBool( p_real_vout, "video-on-top" ) )
    {
        [o_window setLevel: NSStatusWindowLevel];
    }

789
    [[o_view class] performSelectorOnMainThread:@selector(resetVout:) withObject:[NSValue valueWithPointer:p_vout] waitUntilDone:YES];
790
791
792
    [[[[VLCMain sharedInstance] getControls] getFSPanel] setNonActive: nil];
}

793
794
795
796
797
798
799
800
@end

/*****************************************************************************
 * VLCDetachedVoutView implementation
 *****************************************************************************/
@implementation VLCDetachedVoutView

- (id)initWithFrame: (NSRect)frameRect
801
{
802
803
804
805
    [super initWithFrame: frameRect];
    i_time_mouse_last_moved = 0;
    return self;
}
Eric Petit's avatar
Eric Petit committed
806

807
808
809
810
811
- (bool)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
                     frame: (NSRect *) s_arg_frame
{
    BOOL b_return = [super setVout: p_arg_vout subView: view frame:s_arg_frame];
    i_time_mouse_last_moved = mdate();
812
    o_window = [[VLCVoutWindow alloc] initWithVout: p_arg_vout view: self
813
                                                    frame: s_arg_frame];
814
    [self updateTitle];
815
    [view setFrame: [self frame]];
816
817
818
819
820
821
822

    if( var_GetBool( p_real_vout, "video-on-top" ) )
    {
        [o_window setLevel: NSStatusWindowLevel];
    }


823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
    [o_window setAcceptsMouseMovedEvents: TRUE];
    return b_return;
}

- (void)closeVout
{
    [o_window closeWindow];
    [o_window setAcceptsMouseMovedEvents: NO];
    i_time_mouse_last_moved = 0;
    [super closeVout];
}

- (void)mouseMoved:(NSEvent *)o_event
{
    i_time_mouse_last_moved = mdate();
    [super mouseMoved: o_event];
}

- (void)hideMouse:(BOOL)b_hide
{
    BOOL b_inside;
    NSPoint ml;
    NSView *o_contents = [o_window contentView];

    ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
    ml = [o_contents convertPoint:ml fromView:nil];
    b_inside = [o_contents mouse: ml inRect: [o_contents bounds]];

    if( b_hide && b_inside )
    {
        [NSCursor setHiddenUntilMouseMoves: YES];
    }
    else if( !b_hide )
    {
        [NSCursor setHiddenUntilMouseMoves: NO];
    }
}

- (void)manage
{
    [super manage];
864
865
    unsigned int i_mouse_hide_timeout =
        var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
866
    if( p_vout->b_fullscreen )
Eric Petit's avatar
Eric Petit committed
867
    {
868
        if( mdate() - i_time_mouse_last_moved > i_mouse_hide_timeout )
869
        {
870
            [self hideMouse: YES];
871
        }
872
873
874
875
    }
    else
    {
        [self hideMouse: NO];
Eric Petit's avatar
Eric Petit committed
876
    }
877
878
}

879
880
881
882
883
884
885
886
887
@end

/*****************************************************************************
 * VLCEmbeddedVoutView implementation
 *****************************************************************************/

@implementation VLCEmbeddedVoutView

- (id)initWithFrame: (NSRect)frameRect
888
{
889
890
891
892
893
894
895
    [super initWithFrame: frameRect];
    b_used = NO;
    [[[VLCMain sharedInstance] getEmbeddedList] addEmbeddedVout: self];
    return self;
}

- (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
896
                 frame: (NSRect *)s_arg_frame showWindow: (BOOL)b_show_window
897
898
{
    BOOL b_return;
899
900
901

    [NSObject cancelPreviousPerformRequestsWithTarget:o_window];

902
903
    b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame];
    if( b_return )
904
    {
905
        o_window = [self window];
906
907
        if (b_show_window)
            [o_window makeKeyAndOrderFront: self];
908
        [o_window setAcceptsMouseMovedEvents: TRUE];
909
910
911
912
913
914

        if( var_GetBool( p_real_vout, "video-on-top" ) )
        {
            [o_window setLevel: NSStatusWindowLevel];
        }

915
916
917
918
        [view setFrameSize: [self frame].size];
    }
    return b_return;
}
919

920
921
922
923
924
925
926
- (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
                     frame: (NSRect *) s_arg_frame

{
    return [self setVout: p_arg_vout subView: view frame:s_arg_frame showWindow: YES];
}

927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
- (void)setUsed: (BOOL)b_new_used
{
    b_used = b_new_used;
}

- (BOOL)isUsed
{
    return b_used;
}

- (void)closeVout
{
    [super closeVout];
    [o_window setAcceptsMouseMovedEvents: NO];
    [[[VLCMain sharedInstance] getEmbeddedList] releaseEmbeddedVout: self];
}


@end

947
@implementation VLCDetachedEmbeddedVoutView
948
949
950
951
- (void)awakeFromNib
{
    o_embeddedwindow = [self window];
}
952
953
954
955

- (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
                     frame: (NSRect *) s_arg_frame
{
956
    BOOL b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame showWindow: NO];
957

958
959
960
    /* o_window needs to point to our o_embeddedwindow, super might have set it
     * to the fullscreen window that o_embeddedwindow setups during fullscreen */
    o_window = o_embeddedwindow;
961
 
962
963
    if( b_return )
    {
964
965
        [o_window lockFullscreenAnimation];

966
        [o_window setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
967

968
        [self updateTitle];
969

970
971
        [NSObject cancelPreviousPerformRequestsWithTarget:o_window];

972
973
        /* Make the window the front and key window before animating */
        if ([o_window isVisible] && (![o_window isFullscreen]))
974
975
976
            [o_window makeKeyAndOrderFront: self];

        [self scaleWindowWithFactor: 1.0 animate: [o_window isVisible] && (![o_window isFullscreen])];
977

978
979
        [o_window setAspectRatio:NSMakeSize([o_window frame].size.width, [o_window frame].size.height)];

980
981
982
        /* Make sure our window is visible, if we are not in fullscreen */
        if (![o_window isFullscreen])
            [o_window makeKeyAndOrderFront: self];
983
        [o_window unlockFullscreenAnimation];
984

985
986
987
988
989
990
    }
    return b_return;
}

- (void)closeVout
{
991
992
993
994
    /* Don't close the window yet, wait a bit to see if a new input is poping up */
    /* FIXME: Probably fade the window In and Out */
    /* FIXME: fix core */
    [o_window performSelector:@selector(orderOut:) withObject:nil afterDelay:1.5];
995

996
997
998
    [super closeVout];
}

999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
- (void)enterFullscreen
{
    /* We are in a VLCEmbeddedWindow */
    [o_embeddedwindow performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: YES];
}

- (void)leaveFullscreen
{
    /* We are in a VLCEmbeddedWindow */
    [o_embeddedwindow performSelectorOnMainThread: @selector(leaveFullscreen) withObject: NULL waitUntilDone: YES];
}
1010
@end
1011
1012

/*****************************************************************************
1013
 * VLCVoutWindow implementation
1014
 *****************************************************************************/
1015
@implementation VLCVoutWindow
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025

- (id) initWithVout: (vout_thread_t *) vout view: (VLCVoutView *) view
                     frame: (NSRect *) frame
{
    p_vout  = vout;
    o_view  = view;
    s_frame = frame;

    [self performSelectorOnMainThread: @selector(initReal:)
        withObject: NULL waitUntilDone: YES];
1026

1027
1028
1029
    if( !b_init_ok )
    {
        return NULL;
1030
    }