1 /*****************************************************************************
2 * vout.m: MacOS X video output module
3 *****************************************************************************
4 * Copyright (C) 2001-2008 the VideoLAN team
7 * Authors: Colin Delacroix <colin@zoy.org>
8 * Florian G. Pflug <fgp@phlo.org>
9 * 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>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
28 *****************************************************************************/
30 /*****************************************************************************
32 *****************************************************************************/
33 #include <errno.h> /* ENOMEM */
34 #include <stdlib.h> /* free() */
37 /* BeginFullScreen, EndFullScreen */
38 #include <QuickTime/QuickTime.h>
40 /* prevent system sleep */
41 #import <CoreServices/CoreServices.h>
49 #import "embeddedwindow.h"
51 /*****************************************************************************
52 * DeviceCallback: Callback triggered when the video-device variable is changed
53 *****************************************************************************/
54 int DeviceCallback( vlc_object_t *p_this, const char *psz_variable,
55 vlc_value_t old_val, vlc_value_t new_val, void *param )
58 vout_thread_t *p_vout = (vout_thread_t *)p_this;
60 msg_Dbg( p_vout, "set %d", new_val.i_int );
61 var_Create( p_vout->p_libvlc, "video-device", VLC_VAR_INTEGER );
62 var_Set( p_vout->p_libvlc, "video-device", new_val );
65 var_Set( p_vout, "intf-change", val );
70 /*****************************************************************************
71 * VLCEmbeddedList implementation
72 *****************************************************************************/
73 @implementation VLCEmbeddedList
78 o_embedded_array = [NSMutableArray array];
86 for( i = 0; i < [o_embedded_array count]; i++ )
88 id o_vout_view = [o_embedded_array objectAtIndex: i];
89 if( ![o_vout_view isUsed] )
91 [o_vout_view setUsed: YES];
98 - (void)releaseEmbeddedVout: (id)o_vout_view
100 if( [o_embedded_array containsObject: o_vout_view] )
102 [o_vout_view setUsed: NO];
106 msg_Warn( VLCIntf, "cannot find Video Output");
110 - (void)addEmbeddedVout: (id)o_vout_view
112 if( ![o_embedded_array containsObject: o_vout_view] )
114 [o_embedded_array addObject: o_vout_view];
118 - (BOOL)windowContainsEmbedded: (id)o_window
120 /* if( ![[o_window className] isEqualToString: @"VLCVoutWindow"] )
122 NSLog( @"We were not given a VLCVoutWindow" );
124 return ([self getViewForWindow: o_window] == nil ? NO : YES );
127 - (id)getViewForWindow: (id)o_window
129 id o_enumerator = [o_embedded_array objectEnumerator];
130 id o_current_embedded;
132 while( (o_current_embedded = [o_enumerator nextObject]) )
134 if( [o_current_embedded getWindow] == o_window )
136 return o_current_embedded;
144 /*****************************************************************************
145 * VLCVoutView implementation
146 *****************************************************************************/
147 @implementation VLCVoutView
149 - (id)initWithFrame: (NSRect)frameRect
151 self = [super initWithFrame: frameRect];
154 s_frame = &frameRect;
161 - (BOOL)setVout: (vout_thread_t *) vout
162 subView: (NSView *) view
163 frame: (NSRect *) frame
166 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
167 NSArray *o_screens = [NSScreen screens];
173 if( [o_screens count] <= 0 )
175 msg_Err( p_vout, "no OSX screens available" );
179 p_real_vout = [VLCVoutView getRealVout: p_vout];
181 /* Get the pref value when this is the first time, otherwise retrieve the device from the top level video-device var */
182 if( var_Type( p_real_vout->p_libvlc, "video-device" ) == 0 )
184 i_device = var_GetInteger( p_vout, "macosx-vdev" );
188 i_device = var_GetInteger( p_real_vout->p_libvlc, "video-device" );
191 /* Setup the menuitem for the multiple displays. */
192 if( var_Type( p_real_vout, "video-device" ) == 0 )
195 vlc_value_t val2, text;
198 var_Create( p_real_vout, "video-device", VLC_VAR_INTEGER |
200 text.psz_string = _("Fullscreen Video Device");
201 var_Change( p_real_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
203 NSEnumerator * o_enumerator = [o_screens objectEnumerator];
206 text.psz_string = _("Default");
207 var_Change( p_real_vout, "video-device",
208 VLC_VAR_ADDCHOICE, &val2, &text );
209 var_Set( p_real_vout, "video-device", val2 );
211 while( (o_screen = [o_enumerator nextObject]) != NULL )
214 NSRect s_rect = [o_screen frame];
216 snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
217 "%s %d (%dx%d)", _("Screen"), i,
218 (int)s_rect.size.width, (int)s_rect.size.height );
220 text.psz_string = psz_temp;
221 val2.i_int = (int)[o_screen displayID];
222 var_Change( p_real_vout, "video-device",
223 VLC_VAR_ADDCHOICE, &val2, &text );
224 if( (int)[o_screen displayID] == i_device )
226 var_Set( p_real_vout, "video-device", val2 );
231 var_AddCallback( p_real_vout, "video-device", DeviceCallback,
235 var_Set( p_real_vout, "intf-change", val2 );
238 /* Add the view. It's automatically resized to fit the window */
239 [self addSubview: o_view];
240 [self setAutoresizesSubviews: YES];
246 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize
248 [super resizeSubviewsWithOldSize: oldBoundsSize];
249 [o_view setFrameSize: [self frame].size];
252 - (void)drawRect:(NSRect)rect
254 /* When there is no subview we draw a black background */
256 [[NSColor blackColor] set];
263 [[[[VLCMain sharedInstance] getControls] getFSPanel] fadeOut];
265 /* Make sure we don't see a white flash */
266 [[self window] disableScreenUpdatesUntilFlush];
267 [o_view removeFromSuperview];
277 NSString * o_title = nil;
278 NSMutableString * o_mrl = nil;
279 input_thread_t * p_input;
282 if( !p_vout ) return;
284 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT );
286 if( !p_input ) return;
288 input_item_t * p_item = input_GetItem( p_input );
290 psz_title = input_item_GetNowPlaying ( p_item );
292 psz_title = input_item_GetName( p_item );
295 o_title = [NSString stringWithUTF8String: psz_title];
297 char *psz_uri = input_item_GetURI( p_item );
299 o_mrl = [NSMutableString stringWithUTF8String: psz_uri];
309 /* FIXME once psz_access is exported, we could check if we are
310 * reading from a file in a smarter way. */
312 NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
313 if( prefix_range.location != NSNotFound )
314 [o_mrl deleteCharactersInRange: prefix_range];
316 if( [o_mrl characterAtIndex:0] == '/' )
318 /* it's a local file */
319 [o_window setRepresentedFilename: o_mrl];
323 /* it's from the network or somewhere else,
324 * we clear the previous path */
325 [o_window setRepresentedFilename: @""];
327 [o_window setTitle: o_title];
331 [o_window setTitle: [NSString stringWithUTF8String: VOUT_TITLE]];
333 vlc_object_release( p_input );
337 - (void)setOnTop:(BOOL)b_on_top
341 [o_window setLevel: NSStatusWindowLevel];
345 [o_window setLevel: NSNormalWindowLevel];
349 - (NSSize)voutSizeForFactor: (float)factor
351 int i_corrected_height, i_corrected_width;
354 if( p_vout->render.i_height * p_vout->render.i_aspect >
355 p_vout->render.i_width * VOUT_ASPECT_FACTOR )
357 i_corrected_width = p_vout->render.i_height * p_vout->render.i_aspect /
359 newsize.width = (int) ( i_corrected_width * factor );
360 newsize.height = (int) ( p_vout->render.i_height * factor );
364 i_corrected_height = p_vout->render.i_width * VOUT_ASPECT_FACTOR /
365 p_vout->render.i_aspect;
366 newsize.width = (int) ( p_vout->render.i_width * factor );
367 newsize.height = (int) ( i_corrected_height * factor );
373 - (void)scaleWindowWithFactor: (float)factor animate: (BOOL)animate
375 if ( !p_vout->b_fullscreen )
379 NSPoint topleftscreen;
383 topleftbase.y = [o_window frame].size.height;
384 topleftscreen = [o_window convertBaseToScreen: topleftbase];
386 newsize = [self voutSizeForFactor:factor];
388 /* In fullscreen mode we need to use a view that is different from
389 * ourselves, with the VLCEmbeddedWindow */
390 if([o_window isKindOfClass:[VLCEmbeddedWindow class]])
391 mainView = [o_window mainView];
395 /* Calculate the window's new size */
396 new_frame.size.width = [o_window frame].size.width -
397 [mainView frame].size.width + newsize.width;
398 new_frame.size.height = [o_window frame].size.height -
399 [mainView frame].size.height + newsize.height;
401 new_frame.origin.x = topleftscreen.x;
402 new_frame.origin.y = topleftscreen.y - new_frame.size.height;
404 [o_window setFrame:new_frame display:animate animate:animate];
405 p_vout->i_changes |= VOUT_SIZE_CHANGE;
409 - (void)toggleFloatOnTop
413 if( !p_real_vout ) return;
414 if( var_Get( p_real_vout, "video-on-top", &val )>=0 && val.b_bool)
422 var_Set( p_real_vout, "video-on-top", val );
425 - (void)toggleFullscreen
428 if( !p_real_vout ) return;
429 var_Get( p_real_vout, "fullscreen", &val );
430 val.b_bool = !val.b_bool;
431 var_Set( p_real_vout, "fullscreen", val );
437 if( !p_real_vout ) return NO;
438 var_Get( p_real_vout, "fullscreen", &val );
439 return( val.b_bool );
444 vout_Control( p_real_vout, VOUT_SNAPSHOT );
449 /* Disable Screensaver, when we're playing something, but allow it on pause */
450 if( !VLCIntf || !VLCIntf->p_sys )
454 if( VLCIntf->p_sys->i_play_status == PLAYING_S )
455 UpdateSystemActivity( UsrActivity );
463 - (void)scrollWheel:(NSEvent *)theEvent
465 VLCControls * o_controls = (VLCControls *)[[NSApp delegate] getControls];
466 [o_controls scrollWheel: theEvent];
469 - (void)keyDown:(NSEvent *)o_event
473 unsigned int i_pressed_modifiers = 0;
476 i_pressed_modifiers = [o_event modifierFlags];
478 if( i_pressed_modifiers & NSShiftKeyMask )
479 val.i_int |= KEY_MODIFIER_SHIFT;
480 if( i_pressed_modifiers & NSControlKeyMask )
481 val.i_int |= KEY_MODIFIER_CTRL;
482 if( i_pressed_modifiers & NSAlternateKeyMask )
483 val.i_int |= KEY_MODIFIER_ALT;
484 if( i_pressed_modifiers & NSCommandKeyMask )
485 val.i_int |= KEY_MODIFIER_COMMAND;
487 key = [[[o_event charactersIgnoringModifiers] lowercaseString] characterAtIndex: 0];
491 /* Escape should always get you out of fullscreen */
492 if( key == (unichar) 0x1b )
494 if( p_real_vout && [self isFullscreen] )
496 [self toggleFullscreen];
502 val.i_int = config_GetInt( p_vout, "key-play-pause" );
504 val.i_int |= (int)CocoaKeyToVLC( key );
505 var_Set( p_vout->p_libvlc, "key-pressed", val );
507 else NSLog( @"Could not send keyevent to VLC core" );
510 [super keyDown: o_event];
513 - (void)mouseDown:(NSEvent *)o_event
518 if( ( [o_event type] == NSLeftMouseDown ) &&
519 ( ! ( [o_event modifierFlags] & NSControlKeyMask ) ) )
521 if( [o_event clickCount] <= 1 )
523 /* single clicking */
524 var_Get( p_vout, "mouse-button-down", &val );
526 var_Set( p_vout, "mouse-button-down", val );
530 /* multiple clicking */
531 [self toggleFullscreen];
534 else if( ( [o_event type] == NSRightMouseDown ) ||
535 ( ( [o_event type] == NSLeftMouseDown ) &&
536 ( [o_event modifierFlags] & NSControlKeyMask ) ) )
538 msg_Dbg( p_vout, "received NSRightMouseDown (generic method) or Ctrl clic" );
539 [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] voutView]];
543 [super mouseDown: o_event];
546 - (void)otherMouseDown:(NSEvent *)o_event
550 if( p_vout && [o_event type] == NSOtherMouseDown )
552 var_Get( p_vout, "mouse-button-down", &val );
554 var_Set( p_vout, "mouse-button-down", val );
557 [super mouseDown: o_event];
560 - (void)rightMouseDown:(NSEvent *)o_event
562 if( p_vout && [o_event type] == NSRightMouseDown )
564 msg_Dbg( p_vout, "received NSRightMouseDown (specific method)" );
565 [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] voutView]];
568 [super mouseDown: o_event];
571 - (void)mouseUp:(NSEvent *)o_event
575 if( p_vout && [o_event type] == NSLeftMouseUp )
579 var_Set( p_vout, "mouse-clicked", b_val );
581 var_Get( p_vout, "mouse-button-down", &val );
583 var_Set( p_vout, "mouse-button-down", val );
586 [super mouseUp: o_event];
589 - (void)otherMouseUp:(NSEvent *)o_event
593 if( p_vout && [o_event type] == NSOtherMouseUp )
595 var_Get( p_vout, "mouse-button-down", &val );
597 var_Set( p_vout, "mouse-button-down", val );
600 [super mouseUp: o_event];
603 - (void)rightMouseUp:(NSEvent *)o_event
605 if( p_vout && [o_event type] == NSRightMouseUp )
607 /* FIXME: this isn't the appropriate place, but we can't receive
608 * NSRightMouseDown some how */
609 msg_Dbg( p_vout, "received NSRightMouseUp" );
610 [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] voutView]];
613 [super mouseUp: o_event];
616 - (void)mouseDragged:(NSEvent *)o_event
618 [self mouseMoved: o_event];
621 - (void)otherMouseDragged:(NSEvent *)o_event
623 [self mouseMoved: o_event];
626 - (void)rightMouseDragged:(NSEvent *)o_event
628 [self mouseMoved: o_event];
631 - (void)mouseMoved:(NSEvent *)o_event
639 s_rect = [o_view bounds];
640 ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
641 b_inside = [o_view mouse: ml inRect: s_rect];
646 unsigned int i_width, i_height, i_x, i_y;
648 vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
649 (unsigned int)s_rect.size.height,
650 &i_x, &i_y, &i_width, &i_height );
652 val.i_int = ( ((int)ml.x) - i_x ) *
653 p_vout->render.i_width / i_width;
654 var_Set( p_vout, "mouse-x", val );
656 if( [[o_view className] isEqualToString: @"VLCGLView"] )
658 val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
659 p_vout->render.i_height / i_height;
663 val.i_int = ( ((int)ml.y) - i_y ) *
664 p_vout->render.i_height / i_height;
666 var_Set( p_vout, "mouse-y", val );
669 var_Set( p_vout, "mouse-moved", val );
671 if( [self isFullscreen] )
672 [[[[VLCMain sharedInstance] getControls] getFSPanel] fadeIn];
675 [super mouseMoved: o_event];
678 - (BOOL)acceptsFirstResponder
683 - (BOOL)becomeFirstResponder
688 - (BOOL)resignFirstResponder
690 /* We need to stay the first responder or we'll miss some
695 /* Class methods used by the different vout modules */
697 + (vout_thread_t *)getRealVout: (vout_thread_t *)p_vout
699 /* p_real_vout: the vout we have to use to check for video-on-top
700 and a few other things. If we are the QuickTime output, it's us.
701 It we are the OpenGL provider, it is our parent.
702 Since we can't be the QuickTime output anymore, we need to be
704 FIXME: check with the caca and x11 vouts! */
705 return (vout_thread_t *) p_vout->p_parent;
708 + (id)voutView: (vout_thread_t *)p_vout subView: (NSView *)view
709 frame: (NSRect *)s_frame
711 vlc_value_t value_drawable;
715 var_Get( p_vout->p_libvlc, "drawable", &value_drawable );
717 var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
718 var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
719 var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
720 var_Create( p_vout, "macosx-background", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
721 var_Create( p_vout, "macosx-black", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
722 var_Create( p_vout, "embedded-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
724 /* We only wait for NSApp to initialise if we're not embedded (as in the
725 * case of the Mozilla plugin). We can tell whether we're embedded or not
726 * by examining the "drawable" value: if it's zero, we're running in the
727 * main Mac intf; if it's non-zero, we're embedded. */
728 if( value_drawable.i_int == 0 )
730 /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
731 for( i_timeout = 20 ; i_timeout-- ; )
735 msleep( INTF_IDLE_SLEEP );
741 /* No MacOS X intf, unable to communicate with MT */
742 msg_Err( p_vout, "no MacOS X interface present" );
747 if ( VLCIntf && !(p_vout->b_fullscreen) &&
748 !(var_GetBool( p_vout, "macosx-background" )) &&
749 var_GetBool( p_vout, "embedded-video") )
751 o_return = [[[VLCMain sharedInstance] getEmbeddedList]
757 /* No embedded vout is available */
758 if( o_return == nil )
761 bzero( &null_rect, sizeof( NSRect ) );
762 o_return = [[VLCDetachedVoutView alloc] initWithFrame: null_rect ];
764 [o_return setVout: p_vout subView: view frame: s_frame];
768 - (void)enterFullscreen
770 /* Save the settings for next playing item */
771 playlist_t * p_playlist = pl_Hold( p_real_vout );
772 var_SetBool( p_playlist, "fullscreen", true );
773 pl_Release( p_real_vout );
776 - (void)leaveFullscreen
778 /* Save the settings for next playing item */
779 playlist_t * p_playlist = pl_Hold( p_real_vout );
780 var_SetBool( p_playlist, "fullscreen", false );
781 pl_Release( p_real_vout );
786 /*****************************************************************************
787 * VLCDetachedVoutView implementation
788 *****************************************************************************/
789 @implementation VLCDetachedVoutView
791 - (id)initWithFrame: (NSRect)frameRect
793 [super initWithFrame: frameRect];
794 i_time_mouse_last_moved = 0;
798 - (BOOL)mouseDownCanMoveWindow
803 - (bool)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
804 frame: (NSRect *) s_arg_frame
806 BOOL b_return = [super setVout: p_arg_vout subView: view frame:s_arg_frame];
807 i_time_mouse_last_moved = mdate();
808 o_window = [[VLCVoutWindow alloc] initWithVout: p_arg_vout view: self
812 if([self isFullscreen])
813 [o_window performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: YES];
815 [view setFrame: [self frame]];
822 [o_window performSelectorOnMainThread: @selector(close) withObject: NULL waitUntilDone: YES];
823 i_time_mouse_last_moved = 0;
827 - (void)mouseMoved:(NSEvent *)o_event
829 i_time_mouse_last_moved = mdate();
830 [super mouseMoved: o_event];
833 - (void)hideMouse:(BOOL)b_hide
837 NSView *o_contents = [o_window contentView];
839 ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
840 ml = [o_contents convertPoint:ml fromView:nil];
841 b_inside = [o_contents mouse: ml inRect: [o_contents bounds]];
843 if( b_hide && b_inside )
845 [NSCursor setHiddenUntilMouseMoves: YES];
849 [NSCursor setHiddenUntilMouseMoves: NO];
855 /* Dooh, why do we spend processor time doing this kind of stuff? */
857 unsigned int i_mouse_hide_timeout =
858 var_CreateGetInteger(p_vout, "mouse-hide-timeout") * 1000;
860 if( i_mouse_hide_timeout < 100000 )
861 i_mouse_hide_timeout = 100000;
862 if( p_vout->b_fullscreen )
864 if( mdate() - i_time_mouse_last_moved > i_mouse_hide_timeout )
866 i_time_mouse_last_moved = mdate();
867 [self hideMouse: YES];
872 [self hideMouse: NO];
877 - (void)enterFullscreen
879 [o_window performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: NO];
880 [super enterFullscreen];
884 - (void)leaveFullscreen
886 [o_window performSelectorOnMainThread: @selector(leaveFullscreen) withObject: NULL waitUntilDone: NO];
887 [super leaveFullscreen];
891 - (void)scaleWindowWithFactor: (float)factor animate: (BOOL)animate
893 if( p_vout->b_fullscreen )
895 [o_window setMovableByWindowBackground: NO];
896 [super scaleWindowWithFactor: factor animate: animate];
897 [o_window setMovableByWindowBackground: YES];
901 /*****************************************************************************
902 * VLCEmbeddedVoutView implementation
903 *****************************************************************************/
905 @implementation VLCEmbeddedVoutView
909 o_embeddedwindow = [self window];
912 - (BOOL)mouseDownCanMoveWindow
917 - (id)initWithFrame: (NSRect)frameRect
919 if(self = [super initWithFrame: frameRect])
922 [[[VLCMain sharedInstance] getEmbeddedList] addEmbeddedVout: self];
923 o_embeddedwindow = nil; /* Filled later on in -awakeFromNib */
928 - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
929 frame: (NSRect *)s_arg_frame
933 [NSObject cancelPreviousPerformRequestsWithTarget:o_window];
935 b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame];
938 o_window = [self window];
940 [o_window setAcceptsMouseMovedEvents: TRUE];
942 if( var_CreateGetBool( p_real_vout, "video-on-top" ) )
944 [o_window setLevel: NSStatusWindowLevel];
947 [view setFrameSize: [self frame].size];
950 /* o_window needs to point to our o_embeddedwindow, super might have set it
951 * to the fullscreen window that o_embeddedwindow setups during fullscreen */
952 o_window = o_embeddedwindow;
956 [o_window lockFullscreenAnimation];
958 [o_window setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
962 [NSObject cancelPreviousPerformRequestsWithTarget:o_window];
964 /* Make the window the front and key window before animating */
965 if ([o_window isVisible] && (![o_window isFullscreen]))
966 [o_window makeKeyAndOrderFront: self];
968 [self scaleWindowWithFactor: 1.0 animate: [o_window isVisible] && (![o_window isFullscreen])];
970 [o_embeddedwindow setVideoRatio:[self voutSizeForFactor:1.0]];
972 /* Make sure our window is visible, if we are not in fullscreen */
973 if (![o_window isFullscreen])
974 [o_window makeKeyAndOrderFront: self];
975 [o_window unlockFullscreenAnimation];
982 - (void)setUsed: (BOOL)b_new_used
996 /* Don't close the window yet, wait a bit to see if a new input is poping up */
997 /* FIXME: Probably fade the window In and Out */
998 /* FIXME: fix core */
999 [o_embeddedwindow performSelector:@selector(orderOut:) withObject:nil afterDelay:3.];
1001 [[[VLCMain sharedInstance] getEmbeddedList] releaseEmbeddedVout: self];
1004 - (void)enterFullscreen
1007 [super enterFullscreen];
1009 /* We are in a VLCEmbeddedWindow */
1010 [o_embeddedwindow performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: YES];
1013 - (void)leaveFullscreen
1016 [super leaveFullscreen];
1018 /* We are in a VLCEmbeddedWindow */
1019 [o_embeddedwindow performSelectorOnMainThread: @selector(leaveFullscreen) withObject: NULL waitUntilDone: YES];
1023 /*****************************************************************************
1024 * VLCVoutWindow implementation
1025 *****************************************************************************/
1026 @implementation VLCVoutWindow
1028 - (id) initWithVout: (vout_thread_t *) vout view: (VLCVoutView *) view
1029 frame: (NSRect *) frame
1035 [self performSelectorOnMainThread: @selector(initMainThread:)
1036 withObject: NULL waitUntilDone: YES];
1038 return b_init_ok ? self : nil;
1041 - (id)initMainThread: (id) sender
1044 rect.size.height = p_vout->i_window_height;
1045 rect.size.width = p_vout->i_window_width;
1046 rect.origin.x = rect.origin.y = 70.;
1048 if( self = [super initWithContentRect:rect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO])
1050 [self setBackgroundColor:[NSColor blackColor]];
1051 [self setHasShadow:YES];
1052 [self setMovableByWindowBackground: YES];
1054 [self makeKeyAndOrderFront: self];
1055 [self setReleasedWhenClosed: YES];
1056 [self setFrameUsingName:@"VLCVoutWindowDetached"];
1057 [self setFrameAutosaveName:@"VLCVoutWindowDetached"];
1059 /* We'll catch mouse events */
1060 [self makeFirstResponder: o_view];
1061 [self setCanBecomeKeyWindow: YES];
1062 [self setAcceptsMouseMovedEvents: YES];
1063 [self setIgnoresMouseEvents: NO];
1065 if( var_CreateGetBool( p_vout, "macosx-background" ) )
1067 int i_device = var_GetInteger( p_vout->p_libvlc, "video-device" );
1069 /* Find out on which screen to open the window */
1070 NSScreen * screen = [NSScreen screenWithDisplayID: (CGDirectDisplayID)i_device];
1071 if( !screen ) screen = [NSScreen mainScreen];
1073 NSRect screen_rect = [screen frame];
1074 screen_rect.origin.x = screen_rect.origin.y = 0;
1076 /* Creates a window with size: screen_rect on o_screen */
1077 [self setFrame: screen_rect display: NO];
1079 [self setLevel: CGWindowLevelForKey(kCGDesktopWindowLevelKey)];
1080 [self setMovableByWindowBackground: NO];
1082 if( var_CreateGetBool( p_vout, "video-on-top" ) )
1084 [self setLevel: NSStatusWindowLevel];
1087 [self setAlphaValue: var_CreateGetFloat( p_vout, "macosx-opaqueness" )];
1089 /* Add the view. It's automatically resized to fit the window */
1090 [self setContentView: o_view];
1097 - (void)enterFullscreen
1099 if( fullscreen ) return;
1105 i_device = var_GetInteger( p_vout->p_libvlc, "video-device" );
1106 b_black = var_CreateGetBool( p_vout, "macosx-black" );
1108 /* Find out on which screen to open the window */
1109 screen = [NSScreen screenWithDisplayID: (CGDirectDisplayID)i_device];
1110 if( !screen ) screen = [self screen];
1113 [screen blackoutOtherScreens];
1115 [self setMovableByWindowBackground: NO];
1117 if( [screen isMainScreen] )
1118 SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1120 initialFrame = [self frame];
1121 [self setFrame:[screen frame] display:YES animate:YES];
1122 [self setLevel:NSNormalWindowLevel];
1124 /* tell the fspanel to move itself to front next time it's triggered */
1125 [[[[VLCMain sharedInstance] getControls] getFSPanel] setVoutWasUpdated: i_device];
1126 [[[[VLCMain sharedInstance] getControls] getFSPanel] setActive: nil];
1131 - (void)leaveFullscreen
1133 if( !fullscreen ) return;
1136 [NSScreen unblackoutScreens];
1138 [[[[VLCMain sharedInstance] getControls] getFSPanel] setNonActive: nil];
1139 SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
1140 [self setFrame:initialFrame display:YES animate:YES];
1141 [self setMovableByWindowBackground: YES];
1142 if( var_GetBool( p_vout, "video-on-top" ) )
1143 [self setLevel: NSStatusWindowLevel];