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

/*****************************************************************************
 * Preamble
 *****************************************************************************/

29
30
31
32
33
#import "intf.h"
#import "controls.h"
#import "vout.h"
#import "embeddedwindow.h"
#import "fspanel.h"
34
#import "CoreInteraction.h"
35
#import "playlist.h"
36
#import <vlc_url.h>
37

38
39
40
/* SetSystemUIMode, ... */
#import <Carbon/Carbon.h>

41
42
43
44
45
46
/*****************************************************************************
 * VLCEmbeddedWindow Implementation
 *****************************************************************************/

@implementation VLCEmbeddedWindow

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
- (id)initWithContentRect:(NSRect)contentRect styleMask: (NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
{
    BOOL b_useTextured = YES;
    if( [[NSWindow class] instancesRespondToSelector:@selector(setContentBorderThickness:forEdge:)] )
    {
        b_useTextured = NO;
        windowStyle ^= NSTexturedBackgroundWindowMask;
    }
    self = [super initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation];
    if(! b_useTextured )
    {
        [self setContentBorderThickness:28.0 forEdge:NSMinYEdge];
    }
    return self;
}

63
64
- (void)awakeFromNib
{
65
    [self setDelegate: self];
66

67
    /* button strings */
68
69
70
71
    [o_btn_backward setToolTip: _NS("Rewind")];
    [o_btn_forward setToolTip: _NS("Fast Forward")];
    [o_btn_fullscreen setToolTip: _NS("Fullscreen")];
    [o_btn_play setToolTip: _NS("Play")];
72
73
74
75
76
77
78
79
    [o_timeslider setToolTip: _NS("Position")];
    [o_btn_prev setToolTip: _NS("Previous")];
    [o_btn_stop setToolTip: _NS("Stop")];
    [o_btn_next setToolTip: _NS("Next")];
    [o_volumeslider setToolTip: _NS("Volume")];
    [o_btn_playlist setToolTip: _NS("Playlist")];
    [self setTitle: _NS("VLC media player")];

80
81
    o_img_play = [NSImage imageNamed: @"play_embedded"];
    o_img_pause = [NSImage imageNamed: @"pause_embedded"];
82

83
84
85
86
87
    /* Set color of sidebar to Leopard's "Sidebar Blue" */
    [o_sidebar_list setBackgroundColor: [NSColor colorWithCalibratedRed:0.820
                                                                  green:0.843
                                                                   blue:0.886
                                                                  alpha:1.0]];
88

89
90
91
    [self setMinSize:NSMakeSize([o_sidebar_list convertRect:[o_sidebar_list bounds]
                                                     toView: nil].size.width + 551., 114.)];

92
93
94
95
96
    /* Useful to save o_view frame in fullscreen mode */
    o_temp_view = [[NSView alloc] init];
    [o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];

    o_fullscreen_window = nil;
hartman's avatar
hartman committed
97
    o_makekey_anim = o_fullscreen_anim1 = o_fullscreen_anim2 = nil;
98
99
100

    /* Not fullscreen when we wake up */
    [o_btn_fullscreen setState: NO];
101
    b_fullscreen = NO;
102

103
104
105
106
    [self setMovableByWindowBackground:YES];

    [self setDelegate:self];

107
108
    /* Make sure setVisible: returns NO */
    [self orderOut:self];
109
    b_window_is_invisible = YES;
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
110
    videoRatio = NSMakeSize( 0., 0. );
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

    /* enlarge the time slider and move items around in case we have no window resize control */
    if ([self showsResizeIndicator] == NO) {
        NSRect view_rect;
        view_rect = [o_backgroundimg_right frame];
        
        [o_backgroundimg_right setFrame: NSMakeRect( view_rect.origin.x+15,
                                                    view_rect.origin.y,
                                                    view_rect.size.width,
                                                    view_rect.size.height )];
        
        view_rect = [o_backgroundimg_middle frame];
        [o_backgroundimg_middle setFrame: NSMakeRect( view_rect.origin.x,
                                                     view_rect.origin.y,
                                                     view_rect.size.width+15,
                                                     view_rect.size.height )];
        
        view_rect = [o_timeslider frame];
        [o_timeslider setFrame: NSMakeRect( view_rect.origin.x,
                                           view_rect.origin.y,
                                           view_rect.size.width+15,
                                           view_rect.size.height )];
        
        view_rect = [o_time frame];
        [o_time setFrame: NSMakeRect( view_rect.origin.x+15,
                                     view_rect.origin.y,
                                     view_rect.size.width,
                                     view_rect.size.height )];
    }
140
141
142
143

    /* we don't want this window to be restored on relaunch */
    if ([self respondsToSelector:@selector(setRestorable:)])
        [self setRestorable:NO];
144
145
}

146
147
- (void)controlTintChanged
{
148
149
150
    BOOL b_playing = NO;
    if( [o_btn_play alternateImage] == o_img_play_pressed )
        b_playing = YES;
151

152
153
    if( [NSColor currentControlTint] == NSGraphiteControlTint )
    {
154
155
        o_img_play_pressed = [NSImage imageNamed: @"play_embedded_graphite"];
        o_img_pause_pressed = [NSImage imageNamed: @"pause_embedded_graphite"];
156
157
158
        [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_embedded_graphite"]];
        [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_embedded_graphite"]];
        [o_btn_fullscreen setAlternateImage: [NSImage imageNamed: @"fullscreen_graphite"]];
159
    } else {
160
161
162
163
164
        o_img_play_pressed = [NSImage imageNamed: @"play_embedded_blue"];
        o_img_pause_pressed = [NSImage imageNamed: @"pause_embedded_blue"];
        [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_embedded_blue"]];
        [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_embedded_blue"]];
        [o_btn_fullscreen setAlternateImage: [NSImage imageNamed: @"fullscreen_blue"]];
165
166
    }

167
168
169
170
    if( b_playing )
        [o_btn_play setAlternateImage: o_img_play_pressed];
    else
        [o_btn_play setAlternateImage: o_img_pause_pressed];
171
172
173
174
175
176
177
178
179
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver: self];
    [o_img_play release];
    [o_img_play_pressed release];
    [o_img_pause release];
    [o_img_pause_pressed release];
180

181
182
183
    [super dealloc];
}

184
185
186
- (void)setTime:(NSString *)o_arg_time position:(float)f_position
{
    [o_time setStringValue: o_arg_time];
187
    [o_timeslider setFloatValue: f_position];
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
}

- (void)playStatusUpdated:(int)i_status
{
    if( i_status == PLAYING_S )
    {
        [o_btn_play setImage: o_img_pause];
        [o_btn_play setAlternateImage: o_img_pause_pressed];
        [o_btn_play setToolTip: _NS("Pause")];
    }
    else
    {
        [o_btn_play setImage: o_img_play];
        [o_btn_play setAlternateImage: o_img_play_pressed];
        [o_btn_play setToolTip: _NS("Play")];
    }
}

- (void)setSeekable:(BOOL)b_seekable
{
    [o_btn_forward setEnabled: b_seekable];
    [o_btn_backward setEnabled: b_seekable];
210
211
212
213
214
215
216
217
218
219
220
221
    [o_timeslider setEnabled: b_seekable];
}

- (void)setScrollString:(NSString *)o_string
{
    [o_scrollfield setStringValue: o_string];
}

- (id)getPgbar
{
    if( o_main_pgbar )
        return o_main_pgbar;
222

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
    return nil;
}

- (void)setStop:(BOOL)b_input
{
    [o_btn_stop setEnabled: b_input];
}

- (void)setNext:(BOOL)b_input
{
    [o_btn_next setEnabled: b_input];
}

- (void)setPrev:(BOOL)b_input
{
    [o_btn_prev setEnabled: b_input];
}

- (void)setVolumeEnabled:(BOOL)b_input
{
    [o_volumeslider setEnabled: b_input];
}

- (void)setVolumeSlider:(float)f_level
{
    [o_volumeslider setFloatValue: f_level];
249
250
}

251
- (BOOL)windowShouldZoom:(NSWindow *)sender toFrame:(NSRect)newFrame
252
{
253
    [self setFrame: newFrame display: YES animate: YES];
254
    return NO;
255
256
}

257
258
- (BOOL)windowShouldClose:(id)sender
{
259
    playlist_t * p_playlist = pl_Get( VLCIntf );
260
    playlist_Stop( p_playlist );
261
262
263
264

    return YES;
}

265
266
267
268
269
270
271
272
- (NSView *)mainView
{
    if (o_fullscreen_window)
        return o_temp_view;
    else
        return o_view;
}

Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
273
274
275
276
277
278
279
280
281
282
- (void)setVideoRatio:(NSSize)ratio
{
    videoRatio = ratio;
}

- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
{
    if( videoRatio.height == 0. || videoRatio.width == 0. )
        return proposedFrameSize;

283
    if( [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked] )
284
285
286
287
288
289
290
    {
        NSRect viewRect = [o_view convertRect:[o_view bounds] toView: nil];
        NSRect contentRect = [self contentRectForFrameRect:[self frame]];
        float marginy = viewRect.origin.y + [self frame].size.height - contentRect.size.height;
        float marginx = contentRect.size.width - viewRect.size.width;
        proposedFrameSize.height = (proposedFrameSize.width - marginx) * videoRatio.height / videoRatio.width + marginy;
    }
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
291
292
293
294

    return proposedFrameSize;
}

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
- (void)becomeMainWindow
{
    [o_sidebar_list setBackgroundColor: [NSColor colorWithCalibratedRed:0.820
                                                                  green:0.843
                                                                   blue:0.886
                                                                  alpha:1.0]];
	[o_status becomeMainWindow];
    [super becomeMainWindow];
}

- (void)resignMainWindow
{
    [o_sidebar_list setBackgroundColor: [NSColor colorWithCalibratedWhite:0.91 alpha:1.0]];
	[o_status resignMainWindow];
    [super resignMainWindow];
}

312
- (CGFloat)splitView:(NSSplitView *) splitView constrainSplitPosition:(CGFloat) proposedPosition ofSubviewAt:(NSInteger) index
313
314
315
{
	if([splitView isVertical])
		return proposedPosition;
316
317
	else if ( splitView == o_vertical_split )
		return proposedPosition ;
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
	else {
		float bottom = [splitView frame].size.height - [splitView dividerThickness];
		if(proposedPosition > bottom - 50) {
			[o_btn_playlist setState: NSOffState];
			[o_searchfield setHidden:YES];
			[o_playlist_view setHidden:YES];
			return bottom;
		}
		else {
			[o_btn_playlist setState: NSOnState];
			[o_searchfield setHidden:NO];
			[o_playlist_view setHidden:NO];
			[o_playlist swapPlaylists: o_playlist_table];
			[o_vlc_main togglePlaylist:self];
			return proposedPosition;
		}
	}
}

- (void)splitViewWillResizeSubviews:(NSNotification *) notification
{

}

342
- (CGFloat)splitView:(NSSplitView *) splitView constrainMinCoordinate:(CGFloat) proposedMin ofSubviewAt:(NSInteger) offset
343
344
345
346
347
348
349
{
	if([splitView isVertical])
		return 125.;
	else
		return 0.;
}

350
- (CGFloat)splitView:(NSSplitView *) splitView constrainMaxCoordinate:(CGFloat) proposedMax ofSubviewAt:(NSInteger) offset
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
{
    if([splitView isVertical])
		return MIN([self frame].size.width - 551, 300);
	else
		return [splitView frame].size.height;
}

- (BOOL)splitView:(NSSplitView *) splitView canCollapseSubview:(NSView *) subview
{
	if([splitView isVertical])
		return NO;
	else
		return NO;
}

- (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect
   ofDividerAtIndex:(NSInteger)dividerIndex
{
	if([splitView isVertical]) {
		drawnRect.origin.x -= 3;
		drawnRect.size.width += 5;
		return drawnRect;
	}
	else
		return drawnRect;
}

- (IBAction)togglePlaylist:(id)sender
{
	NSView *playback_area = [[o_vertical_split subviews] objectAtIndex:0];
	NSView *playlist_area = [[o_vertical_split subviews] objectAtIndex:1];
	NSRect newVid = [playback_area frame];
	NSRect newList = [playlist_area frame];
	if(newList.size.height < 50 && sender != self && sender != o_vlc_main) {
		newList.size.height = newVid.size.height/2;
		newVid.size.height = newVid.size.height/2;
		newVid.origin.y = newVid.origin.y + newList.size.height;
		[o_btn_playlist setState: NSOnState];
		[o_searchfield setHidden:NO];
		[o_playlist_view setHidden:NO];
		[o_playlist swapPlaylists: o_playlist_table];
		[o_vlc_main togglePlaylist:self];
	}
	else {
		newVid.size.height = newVid.size.height + newList.size.height;
		newList.size.height = 0;
		newVid.origin.y = 0;
		[o_btn_playlist setState: NSOffState];
		[o_searchfield setHidden:YES];
		[o_playlist_view setHidden:YES];
	}
	[playback_area setFrame: newVid];
	[playlist_area setFrame: newList];
}

406
407
408
/*****************************************************************************
 * Fullscreen support
 */
409
410
411
412
413
414

- (BOOL)isFullscreen
{
    return b_fullscreen;
}

415
416
417
418
419
420
421
422
423
424
- (void)lockFullscreenAnimation
{
    [o_animation_lock lock];
}

- (void)unlockFullscreenAnimation
{
    [o_animation_lock unlock];
}

425
426
427
428
429
430
- (void)enterFullscreen
{
    NSMutableDictionary *dict1, *dict2;
    NSScreen *screen;
    NSRect screen_rect;
    NSRect rect;
431
    vout_thread_t *p_vout = getVout();
432
    BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
433

434
435
    if( p_vout )
        screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_GetInteger( p_vout, "video-device" )];
436

437
    [self lockFullscreenAnimation];
438

439
    if (!screen)
Felix Paul Kühne's avatar
Felix Paul Kühne committed
440
    {
441
        msg_Dbg( VLCIntf, "chosen screen isn't present, using current screen for fullscreen mode" );
442
        screen = [self screen];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
443
    }
444
445
    if (!screen)
    {
446
        msg_Dbg( VLCIntf, "Using deepest screen" );
447
448
449
        screen = [NSScreen deepestScreen];
    }

450
451
    if( p_vout )
        vlc_object_release( p_vout );
452

453
454
455
456
457
    screen_rect = [screen frame];

    [o_btn_fullscreen setState: YES];

    [NSCursor setHiddenUntilMouseMoves: YES];
458
459

    if( blackout_other_displays )
460
        [screen blackoutOtherScreens];
461

462
463
464
465
    /* Make sure we don't see the window flashes in float-on-top mode */
    originalLevel = [self level];
    [self setLevel:NSNormalWindowLevel];

466
467
468
    /* Only create the o_fullscreen_window if we are not in the middle of the zooming animation */
    if (!o_fullscreen_window)
    {
ivoire's avatar
ivoire committed
469
        /* We can't change the styleMask of an already created NSWindow, so we create another window, and do eye catching stuff */
470
471
472
473
474
475
476
477

        rect = [[o_view superview] convertRect: [o_view frame] toView: nil]; /* Convert to Window base coord */
        rect.origin.x += [self frame].origin.x;
        rect.origin.y += [self frame].origin.y;
        o_fullscreen_window = [[VLCWindow alloc] initWithContentRect:rect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
        [o_fullscreen_window setBackgroundColor: [NSColor blackColor]];
        [o_fullscreen_window setCanBecomeKeyWindow: YES];

478
        if (![self isVisible] || [self alphaValue] == 0.0)
479
        {
480
            /* We don't animate if we are not visible, instead we
481
482
             * simply fade the display */
            CGDisplayFadeReservationToken token;
483

484
485
486
487
488
            if( blackout_other_displays )
            {
                CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
                CGDisplayFade( token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
            }
489

490
            if ([screen isMainScreen])
491
                SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
492

493
            [[o_view superview] replaceSubview:o_view with:o_temp_view];
494
495
            [o_temp_view setFrame:[o_view frame]];
            [o_fullscreen_window setContentView:o_view];
496

497
            [o_fullscreen_window makeKeyAndOrderFront:self];
498
            [o_fullscreen_window orderFront:self animate:YES];
499

500
501
            [o_fullscreen_window setFrame:screen_rect display:YES];

502
503
504
505
506
            if( blackout_other_displays )
            {
                CGDisplayFade( token, 0.3, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
                CGReleaseDisplayFadeReservation( token );
            }
507
508

            /* Will release the lock */
509
            [self hasBecomeFullscreen];
510

511
512
            return;
        }
513

514
        /* Make sure we don't see the o_view disappearing of the screen during this operation */
515
        NSDisableScreenUpdates();
516
        [[o_view superview] replaceSubview:o_view with:o_temp_view];
517
518
519
        [o_temp_view setFrame:[o_view frame]];
        [o_fullscreen_window setContentView:o_view];
        [o_fullscreen_window makeKeyAndOrderFront:self];
520
        NSEnableScreenUpdates();
521
522
    }

523
524
    /* We are in fullscreen (and no animation is running) */
    if (b_fullscreen)
525
    {
526
527
        /* Make sure we are hidden */
        [super orderOut: self];
528
        [self unlockFullscreenAnimation];
529
        return;
530
    }
531

532
533
534
535
536
537
538
539
540
541
    if (o_fullscreen_anim1)
    {
        [o_fullscreen_anim1 stopAnimation];
        [o_fullscreen_anim1 release];
    }
    if (o_fullscreen_anim2)
    {
        [o_fullscreen_anim2 stopAnimation];
        [o_fullscreen_anim2 release];
    }
542

543
    if ([screen isMainScreen])
544
        SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559

    dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
    dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];

    [dict1 setObject:self forKey:NSViewAnimationTargetKey];
    [dict1 setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];

    [dict2 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
    [dict2 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
    [dict2 setObject:[NSValue valueWithRect:screen_rect] forKey:NSViewAnimationEndFrameKey];

    /* Strategy with NSAnimation allocation:
        - Keep at most 2 animation at a time
        - leaveFullscreen/enterFullscreen are the only responsible for releasing and alloc-ing
    */
hartman's avatar
hartman committed
560
561
    o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict1]];
    o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict2]];
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576

    [dict1 release];
    [dict2 release];

    [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
    [o_fullscreen_anim1 setDuration: 0.3];
    [o_fullscreen_anim1 setFrameRate: 30];
    [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
    [o_fullscreen_anim2 setDuration: 0.2];
    [o_fullscreen_anim2 setFrameRate: 30];

    [o_fullscreen_anim2 setDelegate: self];
    [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];

    [o_fullscreen_anim1 startAnimation];
577
    /* fullscreenAnimation will be unlocked when animation ends */
578
579
580
581
}

- (void)hasBecomeFullscreen
{
582
    [o_fullscreen_window makeFirstResponder: [[[VLCMain sharedInstance] controls] voutView]];
583
584
585
586
587

    [o_fullscreen_window makeKeyWindow];
    [o_fullscreen_window setAcceptsMouseMovedEvents: TRUE];

    /* tell the fspanel to move itself to front next time it's triggered */
588
    [[[[VLCMain sharedInstance] controls] fspanel] setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]];
589
590
591

    if([self isVisible])
        [super orderOut: self];
592

593
    [[[[VLCMain sharedInstance] controls] fspanel] setActive: nil];
594

595
    b_fullscreen = YES;
596
    [self unlockFullscreenAnimation];
597
598
599
}

- (void)leaveFullscreen
600
601
602
603
604
{
    [self leaveFullscreenAndFadeOut: NO];
}

- (void)leaveFullscreenAndFadeOut: (BOOL)fadeout
605
606
607
{
    NSMutableDictionary *dict1, *dict2;
    NSRect frame;
608
    BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
609
610
611

    [self lockFullscreenAnimation];

612
    b_fullscreen = NO;
613
614
    [o_btn_fullscreen setState: NO];

615
616
617
    /* We always try to do so */
    [NSScreen unblackoutScreens];

618
619
    /* Don't do anything if o_fullscreen_window is already closed */
    if (!o_fullscreen_window)
620
    {
621
        [self unlockFullscreenAnimation];
622
        return;
623
    }
624

625
    if (fadeout)
626
    {
627
        /* We don't animate if we are not visible, instead we
628
629
630
        * simply fade the display */
        CGDisplayFadeReservationToken token;

631
632
633
634
635
        if( blackout_other_displays )
        {
            CGAcquireDisplayFadeReservation( kCGMaxDisplayReservationInterval, &token );
            CGDisplayFade( token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
        }
636

637
        [[[[VLCMain sharedInstance] controls] fspanel] setNonActive: nil];
638
        SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
639

640
        /* Will release the lock */
641
642
        [self hasEndedFullscreen];

643
644
645
646
        /* Our window is hidden, and might be faded. We need to workaround that, so note it
         * here */
        b_window_is_invisible = YES;

647
648
649
650
651
652
        if( blackout_other_displays )
        {
            CGDisplayFade( token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
            CGReleaseDisplayFadeReservation( token );
        }

653
654
655
        return;
    }

656
657
658
    [self setAlphaValue: 0.0];
    [self orderFront: self];

659
    [[[[VLCMain sharedInstance] controls] fspanel] setNonActive: nil];
660
    SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
661
662
663
664
665
666
667
668
669
670
671
672
673

    if (o_fullscreen_anim1)
    {
        [o_fullscreen_anim1 stopAnimation];
        [o_fullscreen_anim1 release];
    }
    if (o_fullscreen_anim2)
    {
        [o_fullscreen_anim2 stopAnimation];
        [o_fullscreen_anim2 release];
    }

    frame = [[o_temp_view superview] convertRect: [o_temp_view frame] toView: nil]; /* Convert to Window base coord */
674
    frame.origin.x += [self frame].origin.x;
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
    frame.origin.y += [self frame].origin.y;

    dict2 = [[NSMutableDictionary alloc] initWithCapacity:2];
    [dict2 setObject:self forKey:NSViewAnimationTargetKey];
    [dict2 setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];

    o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict2, nil]];
    [dict2 release];

    [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
    [o_fullscreen_anim2 setDuration: 0.3];
    [o_fullscreen_anim2 setFrameRate: 30];

    [o_fullscreen_anim2 setDelegate: self];

    dict1 = [[NSMutableDictionary alloc] initWithCapacity:3];

    [dict1 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
    [dict1 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
    [dict1 setObject:[NSValue valueWithRect:frame] forKey:NSViewAnimationEndFrameKey];

    o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict1, nil]];
    [dict1 release];

    [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
    [o_fullscreen_anim1 setDuration: 0.2];
    [o_fullscreen_anim1 setFrameRate: 30];
    [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
703
704
705
706

    /* Make sure o_fullscreen_window is the frontmost window */
    [o_fullscreen_window orderFront: self];

707
    [o_fullscreen_anim1 startAnimation];
708
    /* fullscreenAnimation will be unlocked when animation ends */
709
710
711
712
713
714
}

- (void)hasEndedFullscreen
{
    /* This function is private and should be only triggered at the end of the fullscreen change animation */
    /* Make sure we don't see the o_view disappearing of the screen during this operation */
715
    NSDisableScreenUpdates();
716
717
    [o_view retain];
    [o_view removeFromSuperviewWithoutNeedingDisplay];
718
    [[o_temp_view superview] replaceSubview:o_temp_view with:o_view];
719
720
    [o_view release];
    [o_view setFrame:[o_temp_view frame]];
721
    [self makeFirstResponder: o_view];
722
    if ([self isVisible])
723
        [super makeKeyAndOrderFront:self]; /* our version contains a workaround */
724
    [o_fullscreen_window orderOut: self];
725
    NSEnableScreenUpdates();
726
727
728

    [o_fullscreen_window release];
    o_fullscreen_window = nil;
729
730
    [self setLevel:originalLevel];

731
    [self unlockFullscreenAnimation];
732
733
734
735
736
}

- (void)animationDidEnd:(NSAnimation*)animation
{
    NSArray *viewAnimations;
hartman's avatar
hartman committed
737
738
739
740
741
    if( o_makekey_anim == animation )
    {
        [o_makekey_anim release];
        return;
    }
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
    if ([animation currentValue] < 1.0)
        return;

    /* Fullscreen ended or started (we are a delegate only for leaveFullscreen's/enterFullscren's anim2) */
    viewAnimations = [o_fullscreen_anim2 viewAnimations];
    if ([viewAnimations count] >=1 &&
        [[[viewAnimations objectAtIndex: 0] objectForKey: NSViewAnimationEffectKey] isEqualToString:NSViewAnimationFadeInEffect])
    {
        /* Fullscreen ended */
        [self hasEndedFullscreen];
    }
    else
    {
        /* Fullscreen started */
        [self hasBecomeFullscreen];
    }
}

760
761
762
- (void)orderOut: (id)sender
{
    [super orderOut: sender];
763

764
    /* Make sure we leave fullscreen */
765
    [self leaveFullscreenAndFadeOut: YES];
766
767
}

768
769
770
771
772
773
774
- (void)makeKeyAndOrderFront: (id)sender
{
    /* Hack
     * when we exit fullscreen and fade out, we may endup in
     * having a window that is faded. We can't have it fade in unless we
     * animate again. */

775
776
777
778
779
780
781
    if(!b_window_is_invisible)
    {
        /* Make sure we don't do it too much */
        [super makeKeyAndOrderFront: sender];
        return;
    }

782
783
784
    [super setAlphaValue:0.0f];
    [super makeKeyAndOrderFront: sender];

hartman's avatar
hartman committed
785
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] initWithCapacity:2];
786
787
788
    [dict setObject:self forKey:NSViewAnimationTargetKey];
    [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];

hartman's avatar
hartman committed
789
790
    o_makekey_anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict]];
    [dict release];
791

hartman's avatar
hartman committed
792
793
794
795
    [o_makekey_anim setAnimationBlockingMode: NSAnimationNonblocking];
    [o_makekey_anim setDuration: 0.1];
    [o_makekey_anim setFrameRate: 30];
    [o_makekey_anim setDelegate: self];
796

hartman's avatar
hartman committed
797
    [o_makekey_anim startAnimation];
798
799
    b_window_is_invisible = NO;

800
801
802
803
804
    /* fullscreenAnimation will be unlocked when animation ends */
}



805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
/* Make sure setFrame gets executed on main thread especially if we are animating.
 * (Thus we won't block the video output thread) */
- (void)setFrame:(NSRect)frame display:(BOOL)display animate:(BOOL)animate
{
    struct { NSRect frame; BOOL display; BOOL animate;} args;
    NSData *packedargs;

    args.frame = frame;
    args.display = display;
    args.animate = animate;

    packedargs = [NSData dataWithBytes:&args length:sizeof(args)];

    [self performSelectorOnMainThread:@selector(setFrameOnMainThread:)
                    withObject: packedargs waitUntilDone: YES];
}

- (void)setFrameOnMainThread:(NSData*)packedargs
{
    struct args { NSRect frame; BOOL display; BOOL animate; } * args = (struct args*)[packedargs bytes];

826
827
828
829
830
831
832
833
    if( args->animate )
    {
        /* Make sure we don't block too long and set up a non blocking animation */
        NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:
            self, NSViewAnimationTargetKey,
            [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey,
            [NSValue valueWithRect:args->frame], NSViewAnimationEndFrameKey, nil];

hartman's avatar
hartman committed
834
835
        NSViewAnimation * anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict]];
        [dict release];
836
837
838
839
840
841
842
843
844
845

        [anim setAnimationBlockingMode: NSAnimationNonblocking];
        [anim setDuration: 0.4];
        [anim setFrameRate: 30];
        [anim startAnimation];
    }
    else {
        [super setFrame:args->frame display:args->display animate:args->animate];
    }

846
}
847
@end
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909

/*****************************************************************************
 * embeddedbackground
 *****************************************************************************/


@implementation embeddedbackground

- (void)dealloc
{
    [self unregisterDraggedTypes];
    [super dealloc];
}

- (void)awakeFromNib
{
    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
                                   NSFilenamesPboardType, nil]];
    [self addSubview: o_timeslider];
    [self addSubview: o_scrollfield];
    [self addSubview: o_time];
    [self addSubview: o_main_pgbar];
    [self addSubview: o_btn_backward];
    [self addSubview: o_btn_forward];
    [self addSubview: o_btn_fullscreen];
    [self addSubview: o_btn_equalizer];
    [self addSubview: o_btn_playlist];
    [self addSubview: o_btn_play];
    [self addSubview: o_btn_prev];
    [self addSubview: o_btn_stop];
    [self addSubview: o_btn_next];
    [self addSubview: o_btn_volume_down];
    [self addSubview: o_volumeslider];
    [self addSubview: o_btn_volume_up];
    [self addSubview: o_searchfield];
}

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
    if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
        == NSDragOperationGeneric)
    {
        return NSDragOperationGeneric;
    }
    else
    {
        return NSDragOperationNone;
    }
}

- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
    return YES;
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
    NSPasteboard *o_paste = [sender draggingPasteboard];
    NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
    NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
    NSData *o_carried_data = [o_paste dataForType:o_desired_type];
    BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
910

911
912
913
914
915
916
917
918
    if( o_carried_data )
    {
        if ([o_desired_type isEqualToString:NSFilenamesPboardType])
        {
            int i;
            NSArray *o_array = [NSArray array];
            NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType]
                                 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
919

920
921
922
            for( i = 0; i < (int)[o_values count]; i++)
            {
                NSDictionary *o_dic;
923
924
925
926
927
928
929
                char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
                if( !psz_uri )
                    continue;

                o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
                free( psz_uri );

930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
                o_array = [o_array arrayByAddingObject: o_dic];
            }
            if( b_autoplay )
                [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
            else
                [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
            return YES;
        }
    }
    [self setNeedsDisplay:YES];
    return YES;
}

- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
{
    [self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)rect
{
    NSImage *leftImage = [NSImage imageNamed:@"display_left"];
    NSImage *middleImage = [NSImage imageNamed:@"display_middle"];
    NSImage *rightImage = [NSImage imageNamed:@"display_right"];
    [middleImage setSize:NSMakeSize(NSWidth( [self bounds] ) - 134 - [leftImage size].width - [rightImage size].width, [middleImage size].height)];
    [middleImage setScalesWhenResized:YES];
    [leftImage compositeToPoint:NSMakePoint( 122., 40. ) operation:NSCompositeSourceOver];
    [middleImage compositeToPoint:NSMakePoint( 122. + [leftImage size].width, 40. ) operation:NSCompositeSourceOver];
    [rightImage compositeToPoint:NSMakePoint( NSWidth( [self bounds] ) - 12 - [rightImage size].width, 40. ) operation:NSCompositeSourceOver];
}

- (void)mouseDown:(NSEvent *)event
{
    dragStart = [self convertPoint:[event locationInWindow] fromView:nil];
}

- (void)mouseDragged:(NSEvent *)event
{
    NSPoint dragLocation = [self convertPoint:[event locationInWindow] fromView:nil];
    NSPoint winOrigin = [o_window frame].origin;

    NSPoint newOrigin = NSMakePoint(winOrigin.x + (dragLocation.x - dragStart.x),
                                    winOrigin.y + (dragLocation.y - dragStart.y));
    [o_window setFrameOrigin: newOrigin];
}

@end

/*****************************************************************************
 * statusbar
 *****************************************************************************/


@implementation statusbar
- (void)awakeFromNib
{
    [self addSubview: o_text];
	mainwindow = YES;
}

- (void)resignMainWindow
{
	mainwindow = NO;
	[self needsDisplay];
}

- (void)becomeMainWindow
{
	mainwindow = YES;
	[self needsDisplay];
}

- (void)drawRect:(NSRect)rect
{
	if(mainwindow)
		[[NSColor colorWithCalibratedRed:0.820
								   green:0.843
									blue:0.886
								   alpha:1.0] set];
	else
		[[NSColor colorWithCalibratedWhite:0.91 alpha:1.0] set];
	NSRectFill(rect);
	/*NSRect divider = rect;
	divider.origin.y += divider.size.height - 1;
	divider.size.height = 1;
	[[NSColor colorWithCalibratedWhite:0.65 alpha:1.] set];
	NSRectFill(divider);*/
}
@end