1 /*****************************************************************************
2 * embeddedwindow.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2005-2008 the VideoLAN team
7 * Authors: Benjamin Pracht <bigben at videolan dot org>
8 * Felix Paul Kühne <fkuehne at videolan dot org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
29 /* DisableScreenUpdates, SetSystemUIMode, ... */
30 #import <QuickTime/QuickTime.h>
35 #import "embeddedwindow.h"
39 /*****************************************************************************
40 * extension to NSWindow's interface to fix compilation warnings
41 * and let us access this functions properly
42 * this uses a private Apple-API, but works fine on all current OSX releases
43 * keep checking for compatiblity with future releases though
44 *****************************************************************************/
46 @interface NSWindow (UndocumentedWindowProperties)
47 - (void)setBottomCornerRounded: (BOOL)value;
50 /*****************************************************************************
51 * VLCEmbeddedWindow Implementation
52 *****************************************************************************/
54 @implementation VLCEmbeddedWindow
58 [self setDelegate: self];
59 [self setBottomCornerRounded:NO];
62 [o_btn_backward setToolTip: _NS("Rewind")];
63 [o_btn_forward setToolTip: _NS("Fast Forward")];
64 [o_btn_fullscreen setToolTip: _NS("Fullscreen")];
65 [o_btn_play setToolTip: _NS("Play")];
66 [o_timeslider setToolTip: _NS("Position")];
67 [o_btn_prev setToolTip: _NS("Previous")];
68 [o_btn_stop setToolTip: _NS("Stop")];
69 [o_btn_next setToolTip: _NS("Next")];
70 [o_volumeslider setToolTip: _NS("Volume")];
71 [o_btn_playlist setToolTip: _NS("Playlist")];
72 [self setTitle: _NS("VLC media player")];
74 if(MACOS_VERSION < 10.5f) {
75 o_img_play = [NSImage imageNamed: @"play"];
76 o_img_pause = [NSImage imageNamed: @"pause"];
77 [o_btn_play setImage: [NSImage imageNamed: @"play"]];
80 o_img_play = [NSImage imageNamed: @"play_big"];
81 o_img_pause = [NSImage imageNamed: @"pause_big"];
83 [self controlTintChanged];
84 [[NSNotificationCenter defaultCenter] addObserver: self
85 selector: @selector( controlTintChanged )
86 name: NSControlTintDidChangeNotification
89 /* Set color of sidebar to Leopard's "Sidebar Blue" */
90 [o_sidebar_list setBackgroundColor: [NSColor colorWithCalibratedRed:0.820
95 [self setMinSize:NSMakeSize([o_sidebar_list convertRect:[o_sidebar_list bounds]
96 toView: nil].size.width + 551., 114.)];
98 /* Useful to save o_view frame in fullscreen mode */
99 o_temp_view = [[NSView alloc] init];
100 [o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
102 o_fullscreen_window = nil;
103 o_fullscreen_anim1 = o_fullscreen_anim2 = nil;
105 /* Not fullscreen when we wake up */
106 [o_btn_fullscreen setState: NO];
109 /* Make sure setVisible: returns NO */
110 [self orderOut:self];
111 //b_window_is_invisible = YES;
112 videoRatio = NSMakeSize( 0., 0. );
115 - (void)controlTintChanged
118 if( [o_btn_play alternateImage] == o_img_play_pressed )
121 if (MACOS_VERSION < 10.5f) {
122 /* System is running Tiger and should use aqua buttons */
123 [o_btn_backward setImage: [NSImage imageNamed: @"skip_previous_active"]];
124 [o_btn_forward setImage: [NSImage imageNamed: @"skip_forward_active"]];
125 if( [NSColor currentControlTint] == NSGraphiteControlTint )
127 o_img_play_pressed = [NSImage imageNamed: @"play_graphite"];
128 o_img_pause_pressed = [NSImage imageNamed: @"pause_graphite"];
129 [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_graphite"]];
130 [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_graphite"]];
134 o_img_play_pressed = [NSImage imageNamed: @"play_blue"];
135 o_img_pause_pressed = [NSImage imageNamed: @"pause_blue"];
136 [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_blue"]];
137 [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_blue"]];
141 /* System is running Leopard or later and should use metal buttons */
142 o_img_play_pressed = [NSImage imageNamed: @"play_big_down"];
143 o_img_pause_pressed = [NSImage imageNamed: @"pause_big_down"];
147 [o_btn_play setAlternateImage: o_img_play_pressed];
149 [o_btn_play setAlternateImage: o_img_pause_pressed];
154 [[NSNotificationCenter defaultCenter] removeObserver: self];
155 [o_img_play release];
156 [o_img_play_pressed release];
157 [o_img_pause release];
158 [o_img_pause_pressed release];
163 - (void)setTime:(NSString *)o_arg_time position:(float)f_position
165 [o_time setStringValue: o_arg_time];
166 [o_timeslider setFloatValue: f_position];
169 - (void)playStatusUpdated:(int)i_status
171 if( i_status == PLAYING_S )
173 [o_btn_play setImage: o_img_pause];
174 [o_btn_play setAlternateImage: o_img_pause_pressed];
175 [o_btn_play setToolTip: _NS("Pause")];
179 [o_btn_play setImage: o_img_play];
180 [o_btn_play setAlternateImage: o_img_play_pressed];
181 [o_btn_play setToolTip: _NS("Play")];
185 - (void)setSeekable:(BOOL)b_seekable
187 [o_btn_forward setEnabled: b_seekable];
188 [o_btn_backward setEnabled: b_seekable];
189 [o_timeslider setEnabled: b_seekable];
192 - (void)setScrollString:(NSString *)o_string
194 [o_scrollfield setStringValue: o_string];
205 - (void)setStop:(BOOL)b_input
207 [o_btn_stop setEnabled: b_input];
210 - (void)setNext:(BOOL)b_input
212 [o_btn_next setEnabled: b_input];
215 - (void)setPrev:(BOOL)b_input
217 [o_btn_prev setEnabled: b_input];
220 - (void)setVolumeEnabled:(BOOL)b_input
222 [o_volumeslider setEnabled: b_input];
225 - (void)setVolumeSlider:(float)f_level
227 [o_volumeslider setFloatValue: f_level];
230 - (BOOL)windowShouldZoom:(NSWindow *)sender toFrame:(NSRect)newFrame
232 [self setFrame: newFrame display: YES animate: YES];
236 - (BOOL)windowShouldClose:(id)sender
238 playlist_t * p_playlist = pl_Hold( VLCIntf );
240 /* Only want to stop playback if video is playing */
241 if( videoRatio.height != 0. && videoRatio.width != 0. )
242 playlist_Stop( p_playlist );
243 pl_Release( VLCIntf );
249 if (o_fullscreen_window)
255 - (void)setVideoRatio:(NSSize)ratio
260 - (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
262 NSView *playlist_area = [[o_vertical_split subviews] objectAtIndex:1];
263 NSRect newList = [playlist_area frame];
264 if( newList.size.height < 50 && newList.size.height > 0 ) {
265 [self togglePlaylist:self];
268 /* With no video open or with the playlist open the behavior is odd */
269 if( newList.size.height > 50 )
270 return proposedFrameSize;
272 if( videoRatio.height == 0. || videoRatio.width == 0. )
273 return proposedFrameSize;
275 NSRect viewRect = [o_view convertRect:[o_view bounds] toView: nil];
276 NSRect contentRect = [self contentRectForFrameRect:[self frame]];
277 float marginy = viewRect.origin.y + [self frame].size.height - contentRect.size.height;
278 float marginx = contentRect.size.width - viewRect.size.width;
280 proposedFrameSize.height = (proposedFrameSize.width - marginx) * videoRatio.height / videoRatio.width + marginy;
282 return proposedFrameSize;
285 - (void)becomeMainWindow
287 [o_sidebar_list setBackgroundColor: [NSColor colorWithCalibratedRed:0.820
291 [o_status becomeMainWindow];
292 [super becomeMainWindow];
295 - (void)resignMainWindow
297 [o_sidebar_list setBackgroundColor: [NSColor colorWithCalibratedWhite:0.91 alpha:1.0]];
298 [o_status resignMainWindow];
299 [super resignMainWindow];
302 - (float)splitView:(NSSplitView *) splitView constrainSplitPosition:(float) proposedPosition ofSubviewAt:(int) index
304 if([splitView isVertical])
305 return proposedPosition;
307 float bottom = [splitView frame].size.height - [splitView dividerThickness];
308 if(proposedPosition > bottom - 50) {
309 [o_btn_playlist setState: NSOffState];
310 [o_searchfield setHidden:YES];
311 [o_playlist_view setHidden:YES];
315 [o_btn_playlist setState: NSOnState];
316 [o_searchfield setHidden:NO];
317 [o_playlist_view setHidden:NO];
318 [o_playlist swapPlaylists: o_playlist_table];
319 [o_vlc_main togglePlaylist:self];
320 return proposedPosition;
325 - (void)splitViewWillResizeSubviews:(NSNotification *) notification
330 - (float)splitView:(NSSplitView *) splitView constrainMinCoordinate:(float) proposedMin ofSubviewAt:(int) offset
332 if([splitView isVertical])
338 - (float)splitView:(NSSplitView *) splitView constrainMaxCoordinate:(float) proposedMax ofSubviewAt:(int) offset
340 if([splitView isVertical])
341 return MIN([self frame].size.width - 551, 300);
343 return [splitView frame].size.height;
346 - (BOOL)splitView:(NSSplitView *) splitView canCollapseSubview:(NSView *) subview
348 if([splitView isVertical])
354 - (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect
355 ofDividerAtIndex:(NSInteger)dividerIndex
357 if([splitView isVertical]) {
358 drawnRect.origin.x -= 3;
359 drawnRect.size.width += 5;
366 - (IBAction)togglePlaylist:(id)sender
368 NSView *playback_area = [[o_vertical_split subviews] objectAtIndex:0];
369 NSView *playlist_area = [[o_vertical_split subviews] objectAtIndex:1];
370 NSRect newVid = [playback_area frame];
371 NSRect newList = [playlist_area frame];
372 if(newList.size.height < 50 && sender != self && sender != o_vlc_main) {
373 newList.size.height = newVid.size.height/2;
374 newVid.size.height = newVid.size.height/2;
375 newVid.origin.y = newVid.origin.y + newList.size.height;
376 [o_btn_playlist setState: NSOnState];
377 [o_searchfield setHidden:NO];
378 [o_playlist_view setHidden:NO];
379 [o_playlist swapPlaylists: o_playlist_table];
380 [o_vlc_main togglePlaylist:self];
383 newVid.size.height = newVid.size.height + newList.size.height;
384 newList.size.height = 0;
386 [o_btn_playlist setState: NSOffState];
387 [o_searchfield setHidden:YES];
388 [o_playlist_view setHidden:YES];
390 [playback_area setFrame: newVid];
391 [playlist_area setFrame: newList];
394 /*****************************************************************************
403 - (void)lockFullscreenAnimation
405 [o_animation_lock lock];
408 - (void)unlockFullscreenAnimation
410 [o_animation_lock unlock];
413 - (void)enterFullscreen
415 NSMutableDictionary *dict1, *dict2;
419 vout_thread_t *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
420 BOOL blackout_other_displays = config_GetInt( VLCIntf, "macosx-black" );
422 screen = [NSScreen screenWithDisplayID:(CGDirectDisplayID)var_GetInteger( p_vout, "video-device" )];
424 [self lockFullscreenAnimation];
428 msg_Dbg( p_vout, "chosen screen isn't present, using current screen for fullscreen mode" );
429 screen = [self screen];
433 msg_Dbg( p_vout, "Using deepest screen" );
434 screen = [NSScreen deepestScreen];
437 vlc_object_release( p_vout );
439 screen_rect = [screen frame];
441 [o_btn_fullscreen setState: YES];
443 [NSCursor setHiddenUntilMouseMoves: YES];
445 if( blackout_other_displays )
446 [screen blackoutOtherScreens];
448 /* Make sure we don't see the window flashes in float-on-top mode */
449 originalLevel = [self level];
450 [self setLevel:NSNormalWindowLevel];
452 /* Only create the o_fullscreen_window if we are not in the middle of the zooming animation */
453 if (!o_fullscreen_window)
455 /* We can't change the styleMask of an already created NSWindow, so we create an other window, and do eye catching stuff */
457 rect = [[o_view superview] convertRect: [o_view frame] toView: nil]; /* Convert to Window base coord */
458 rect.origin.x += [self frame].origin.x;
459 rect.origin.y += [self frame].origin.y;
460 o_fullscreen_window = [[VLCWindow alloc] initWithContentRect:rect styleMask: NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
461 [o_fullscreen_window setBackgroundColor: [NSColor blackColor]];
462 [o_fullscreen_window setCanBecomeKeyWindow: YES];
464 if (![self isVisible] || [self alphaValue] == 0.0 || MACOS_VERSION < 10.4f)
466 /* We don't animate if we are not visible or if we are running on
467 * Mac OS X <10.4 which doesn't support NSAnimation, instead we
468 * simply fade the display */
469 CGDisplayFadeReservationToken token;
471 CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
472 CGDisplayFade( token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
474 if ([screen isMainScreen])
475 SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
477 [[self contentView] replaceSubview:o_view with:o_temp_view];
478 [o_temp_view setFrame:[o_view frame]];
479 [o_fullscreen_window setContentView:o_view];
481 [o_fullscreen_window makeKeyAndOrderFront:self];
483 [o_fullscreen_window makeKeyAndOrderFront:self];
484 [o_fullscreen_window orderFront:self animate:YES];
486 [o_fullscreen_window setFrame:screen_rect display:YES];
488 CGDisplayFade( token, 0.3, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
489 CGReleaseDisplayFadeReservation( token);
491 /* Will release the lock */
492 [self hasBecomeFullscreen];
497 /* Make sure we don't see the o_view disappearing of the screen during this operation */
498 DisableScreenUpdates();
499 [[self contentView] replaceSubview:o_view with:o_temp_view];
500 [o_temp_view setFrame:[o_view frame]];
501 [o_fullscreen_window setContentView:o_view];
502 [o_fullscreen_window makeKeyAndOrderFront:self];
503 EnableScreenUpdates();
506 if (MACOS_VERSION < 10.4f)
508 /* We were already fullscreen nothing to do when NSAnimation
509 * is not supported */
510 [self unlockFullscreenAnimation];
514 /* We are in fullscreen (and no animation is running) */
517 /* Make sure we are hidden */
518 [super orderOut: self];
519 [self unlockFullscreenAnimation];
523 if (o_fullscreen_anim1)
525 [o_fullscreen_anim1 stopAnimation];
526 [o_fullscreen_anim1 release];
528 if (o_fullscreen_anim2)
530 [o_fullscreen_anim2 stopAnimation];
531 [o_fullscreen_anim2 release];
534 if ([screen isMainScreen])
535 SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
537 dict1 = [[NSMutableDictionary alloc] initWithCapacity:2];
538 dict2 = [[NSMutableDictionary alloc] initWithCapacity:3];
540 [dict1 setObject:self forKey:NSViewAnimationTargetKey];
541 [dict1 setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
543 [dict2 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
544 [dict2 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
545 [dict2 setObject:[NSValue valueWithRect:screen_rect] forKey:NSViewAnimationEndFrameKey];
547 /* Strategy with NSAnimation allocation:
548 - Keep at most 2 animation at a time
549 - leaveFullscreen/enterFullscreen are the only responsible for releasing and alloc-ing
551 o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict1, nil]];
552 o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict2, nil]];
557 [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
558 [o_fullscreen_anim1 setDuration: 0.3];
559 [o_fullscreen_anim1 setFrameRate: 30];
560 [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
561 [o_fullscreen_anim2 setDuration: 0.2];
562 [o_fullscreen_anim2 setFrameRate: 30];
564 [o_fullscreen_anim2 setDelegate: self];
565 [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
567 [o_fullscreen_anim1 startAnimation];
568 /* fullscreenAnimation will be unlocked when animation ends */
571 - (void)hasBecomeFullscreen
573 [o_fullscreen_window makeFirstResponder: [[[VLCMain sharedInstance] controls] voutView]];
575 [o_fullscreen_window makeKeyWindow];
576 [o_fullscreen_window setAcceptsMouseMovedEvents: TRUE];
578 /* tell the fspanel to move itself to front next time it's triggered */
579 [[[[VLCMain sharedInstance] controls] fspanel] setVoutWasUpdated: (int)[[o_fullscreen_window screen] displayID]];
582 [super orderOut: self];
584 [[[[VLCMain sharedInstance] controls] fspanel] setActive: nil];
587 [self unlockFullscreenAnimation];
590 - (void)leaveFullscreen
592 [self leaveFullscreenAndFadeOut: NO];
595 - (void)leaveFullscreenAndFadeOut: (BOOL)fadeout
597 NSMutableDictionary *dict1, *dict2;
600 [self lockFullscreenAnimation];
603 [o_btn_fullscreen setState: NO];
605 /* We always try to do so */
606 [NSScreen unblackoutScreens];
608 /* Don't do anything if o_fullscreen_window is already closed */
609 if (!o_fullscreen_window)
611 [self unlockFullscreenAnimation];
615 if (fadeout || MACOS_VERSION < 10.4f)
617 /* We don't animate if we are not visible or if we are running on
618 * Mac OS X <10.4 which doesn't support NSAnimation, instead we
619 * simply fade the display */
620 CGDisplayFadeReservationToken token;
622 CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
623 CGDisplayFade( token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
625 [[[[VLCMain sharedInstance] controls] fspanel] setNonActive: nil];
626 SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
628 /* Will release the lock */
629 [self hasEndedFullscreen];
631 /* Our window is hidden, and might be faded. We need to workaround that, so note it
633 b_window_is_invisible = YES;
635 CGDisplayFade( token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
636 CGReleaseDisplayFadeReservation( token);
640 [self setAlphaValue: 0.0];
641 [self orderFront: self];
643 [[[[VLCMain sharedInstance] controls] fspanel] setNonActive: nil];
644 SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
646 if (o_fullscreen_anim1)
648 [o_fullscreen_anim1 stopAnimation];
649 [o_fullscreen_anim1 release];
651 if (o_fullscreen_anim2)
653 [o_fullscreen_anim2 stopAnimation];
654 [o_fullscreen_anim2 release];
657 frame = [[o_temp_view superview] convertRect: [o_temp_view frame] toView: nil]; /* Convert to Window base coord */
658 frame.origin.x += [self frame].origin.x;
659 frame.origin.y += [self frame].origin.y;
661 dict2 = [[NSMutableDictionary alloc] initWithCapacity:2];
662 [dict2 setObject:self forKey:NSViewAnimationTargetKey];
663 [dict2 setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
665 o_fullscreen_anim2 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict2, nil]];
668 [o_fullscreen_anim2 setAnimationBlockingMode: NSAnimationNonblocking];
669 [o_fullscreen_anim2 setDuration: 0.3];
670 [o_fullscreen_anim2 setFrameRate: 30];
672 [o_fullscreen_anim2 setDelegate: self];
674 dict1 = [[NSMutableDictionary alloc] initWithCapacity:3];
676 [dict1 setObject:o_fullscreen_window forKey:NSViewAnimationTargetKey];
677 [dict1 setObject:[NSValue valueWithRect:[o_fullscreen_window frame]] forKey:NSViewAnimationStartFrameKey];
678 [dict1 setObject:[NSValue valueWithRect:frame] forKey:NSViewAnimationEndFrameKey];
680 o_fullscreen_anim1 = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict1, nil]];
683 [o_fullscreen_anim1 setAnimationBlockingMode: NSAnimationNonblocking];
684 [o_fullscreen_anim1 setDuration: 0.2];
685 [o_fullscreen_anim1 setFrameRate: 30];
686 [o_fullscreen_anim2 startWhenAnimation: o_fullscreen_anim1 reachesProgress: 1.0];
688 /* Make sure o_fullscreen_window is the frontmost window */
689 [o_fullscreen_window orderFront: self];
691 [o_fullscreen_anim1 startAnimation];
692 /* fullscreenAnimation will be unlocked when animation ends */
695 - (void)hasEndedFullscreen
697 /* This function is private and should be only triggered at the end of the fullscreen change animation */
698 /* Make sure we don't see the o_view disappearing of the screen during this operation */
699 DisableScreenUpdates();
701 [o_view removeFromSuperviewWithoutNeedingDisplay];
702 [[self contentView] replaceSubview:o_temp_view with:o_view];
704 [o_view setFrame:[o_temp_view frame]];
705 [self makeFirstResponder: o_view];
706 if ([self isVisible])
707 [super makeKeyAndOrderFront:self]; /* our version contains a workaround */
708 [o_fullscreen_window orderOut: self];
709 EnableScreenUpdates();
711 [o_fullscreen_window release];
712 o_fullscreen_window = nil;
713 [self setLevel:originalLevel];
715 [self unlockFullscreenAnimation];
718 - (void)animationDidEnd:(NSAnimation*)animation
720 NSArray *viewAnimations;
722 if ([animation currentValue] < 1.0)
725 /* Fullscreen ended or started (we are a delegate only for leaveFullscreen's/enterFullscren's anim2) */
726 viewAnimations = [o_fullscreen_anim2 viewAnimations];
727 if ([viewAnimations count] >=1 &&
728 [[[viewAnimations objectAtIndex: 0] objectForKey: NSViewAnimationEffectKey] isEqualToString:NSViewAnimationFadeInEffect])
730 /* Fullscreen ended */
731 [self hasEndedFullscreen];
735 /* Fullscreen started */
736 [self hasBecomeFullscreen];
740 - (void)orderOut: (id)sender
742 [super orderOut: sender];
744 /* Make sure we leave fullscreen */
745 [self leaveFullscreenAndFadeOut: YES];
748 - (void)makeKeyAndOrderFront: (id)sender
751 * when we exit fullscreen and fade out, we may endup in
752 * having a window that is faded. We can't have it fade in unless we
755 if(!b_window_is_invisible)
757 /* Make sure we don't do it too much */
758 [super makeKeyAndOrderFront: sender];
762 [super setAlphaValue:0.0f];
763 [super makeKeyAndOrderFront: sender];
765 NSMutableDictionary * dict = [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
766 [dict setObject:self forKey:NSViewAnimationTargetKey];
767 [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
769 NSViewAnimation * anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dict]];
771 [anim setAnimationBlockingMode: NSAnimationNonblocking];
772 [anim setDuration: 0.1];
773 [anim setFrameRate: 30];
775 [anim startAnimation];
776 b_window_is_invisible = NO;
778 /* fullscreenAnimation will be unlocked when animation ends */
783 /* Make sure setFrame gets executed on main thread especially if we are animating.
784 * (Thus we won't block the video output thread) */
785 - (void)setFrame:(NSRect)frame display:(BOOL)display animate:(BOOL)animate
787 struct { NSRect frame; BOOL display; BOOL animate;} args;
791 args.display = display;
792 args.animate = animate;
794 packedargs = [NSData dataWithBytes:&args length:sizeof(args)];
796 [self performSelectorOnMainThread:@selector(setFrameOnMainThread:)
797 withObject: packedargs waitUntilDone: YES];
800 - (void)setFrameOnMainThread:(NSData*)packedargs
802 struct args { NSRect frame; BOOL display; BOOL animate; } * args = (struct args*)[packedargs bytes];
806 /* Make sure we don't block too long and set up a non blocking animation */
807 NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:
808 self, NSViewAnimationTargetKey,
809 [NSValue valueWithRect:[self frame]], NSViewAnimationStartFrameKey,
810 [NSValue valueWithRect:args->frame], NSViewAnimationEndFrameKey, nil];
812 NSViewAnimation * anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
814 [anim setAnimationBlockingMode: NSAnimationNonblocking];
815 [anim setDuration: 0.4];
816 [anim setFrameRate: 30];
817 [anim startAnimation];
820 [super setFrame:args->frame display:args->display animate:args->animate];
826 /*****************************************************************************
828 *****************************************************************************/
831 @implementation embeddedbackground
835 [self unregisterDraggedTypes];
841 [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
842 NSFilenamesPboardType, nil]];
843 [self addSubview: o_timeslider];
844 [self addSubview: o_scrollfield];
845 [self addSubview: o_time];
846 [self addSubview: o_main_pgbar];
847 [self addSubview: o_btn_backward];
848 [self addSubview: o_btn_forward];
849 [self addSubview: o_btn_fullscreen];
850 [self addSubview: o_btn_equalizer];
851 [self addSubview: o_btn_playlist];
852 [self addSubview: o_btn_play];
853 [self addSubview: o_btn_prev];
854 [self addSubview: o_btn_stop];
855 [self addSubview: o_btn_next];
856 [self addSubview: o_btn_volume_down];
857 [self addSubview: o_volumeslider];
858 [self addSubview: o_btn_volume_up];
859 [self addSubview: o_searchfield];
862 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
864 if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
865 == NSDragOperationGeneric)
867 return NSDragOperationGeneric;
871 return NSDragOperationNone;
875 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
880 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
882 NSPasteboard *o_paste = [sender draggingPasteboard];
883 NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
884 NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
885 NSData *o_carried_data = [o_paste dataForType:o_desired_type];
886 BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
890 if ([o_desired_type isEqualToString:NSFilenamesPboardType])
893 NSArray *o_array = [NSArray array];
894 NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType]
895 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
897 for( i = 0; i < (int)[o_values count]; i++)
900 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
901 o_array = [o_array arrayByAddingObject: o_dic];
904 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
906 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
910 [self setNeedsDisplay:YES];
914 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
916 [self setNeedsDisplay:YES];
919 - (void)drawRect:(NSRect)rect
921 NSImage *leftImage = [NSImage imageNamed:@"display_left"];
922 NSImage *middleImage = [NSImage imageNamed:@"display_middle"];
923 NSImage *rightImage = [NSImage imageNamed:@"display_right"];
924 [middleImage setSize:NSMakeSize(NSWidth( [self bounds] ) - 134 - [leftImage size].width - [rightImage size].width, [middleImage size].height)];
925 [middleImage setScalesWhenResized:YES];
926 [leftImage compositeToPoint:NSMakePoint( 122., 40. ) operation:NSCompositeSourceOver];
927 [middleImage compositeToPoint:NSMakePoint( 122. + [leftImage size].width, 40. ) operation:NSCompositeSourceOver];
928 [rightImage compositeToPoint:NSMakePoint( NSWidth( [self bounds] ) - 12 - [rightImage size].width, 40. ) operation:NSCompositeSourceOver];
931 - (void)mouseDown:(NSEvent *)event
933 dragStart = [self convertPoint:[event locationInWindow] fromView:nil];
936 - (void)mouseDragged:(NSEvent *)event
938 NSPoint dragLocation = [self convertPoint:[event locationInWindow] fromView:nil];
939 NSPoint winOrigin = [o_window frame].origin;
941 NSPoint newOrigin = NSMakePoint(winOrigin.x + (dragLocation.x - dragStart.x),
942 winOrigin.y + (dragLocation.y - dragStart.y));
943 [o_window setFrameOrigin: newOrigin];
948 /*****************************************************************************
950 *****************************************************************************/
953 @implementation statusbar
956 [self addSubview: o_text];
960 - (void)resignMainWindow
966 - (void)becomeMainWindow
972 - (void)drawRect:(NSRect)rect
975 [[NSColor colorWithCalibratedRed:0.820
980 [[NSColor colorWithCalibratedWhite:0.91 alpha:1.0] set];
982 /*NSRect divider = rect;
983 divider.origin.y += divider.size.height - 1;
984 divider.size.height = 1;
985 [[NSColor colorWithCalibratedWhite:0.65 alpha:1.] set];
986 NSRectFill(divider);*/