1 /*****************************************************************************
2 * vout.m: MacOS X video output module
3 *****************************************************************************
4 * Copyright (C) 2001-2007 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 K
\9fhne <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() */
35 #include <string.h> /* strerror() */
37 /* BeginFullScreen, EndFullScreen */
38 #include <QuickTime/QuickTime.h>
46 #import "embeddedwindow.h"
48 /*****************************************************************************
49 * DeviceCallback: Callback triggered when the video-device variable is changed
50 *****************************************************************************/
51 int DeviceCallback( vlc_object_t *p_this, const char *psz_variable,
52 vlc_value_t old_val, vlc_value_t new_val, void *param )
55 vout_thread_t *p_vout = (vout_thread_t *)p_this;
57 msg_Dbg( p_vout, "set %d", new_val.i_int );
58 var_Create( p_vout->p_libvlc, "video-device", VLC_VAR_INTEGER );
59 var_Set( p_vout->p_libvlc, "video-device", new_val );
61 val.b_bool = VLC_TRUE;
62 var_Set( p_vout, "intf-change", val );
67 /*****************************************************************************
68 * VLCEmbeddedList implementation
69 *****************************************************************************/
70 @implementation VLCEmbeddedList
75 o_embedded_array = [NSMutableArray array];
83 for( i = 0; i < [o_embedded_array count]; i++ )
85 id o_vout_view = [o_embedded_array objectAtIndex: i];
86 if( ![o_vout_view isUsed] )
88 [o_vout_view setUsed: YES];
95 - (void)releaseEmbeddedVout: (id)o_vout_view
97 if( [o_embedded_array containsObject: o_vout_view] )
99 [o_vout_view setUsed: NO];
103 msg_Warn( VLCIntf, "cannot find Video Output");
107 - (void)addEmbeddedVout: (id)o_vout_view
109 if( ![o_embedded_array containsObject: o_vout_view] )
111 [o_embedded_array addObject: o_vout_view];
115 - (BOOL)windowContainsEmbedded: (id)o_window
117 /* if( ![[o_window className] isEqualToString: @"VLCVoutWindow"] )
119 NSLog( @"We were not given a VLCVoutWindow" );
121 return ([self getViewForWindow: o_window] == nil ? NO : YES );
124 - (id)getViewForWindow: (id)o_window
126 id o_enumerator = [o_embedded_array objectEnumerator];
127 id o_current_embedded;
129 while( (o_current_embedded = [o_enumerator nextObject]) )
131 if( [o_current_embedded getWindow] == o_window )
133 return o_current_embedded;
141 /*****************************************************************************
142 * VLCVoutView implementation
143 *****************************************************************************/
144 @implementation VLCVoutView
146 - (id)initWithFrame:(NSRect)frameRect
148 [super initWithFrame: frameRect];
151 s_frame = &frameRect;
158 - (BOOL)setVout: (vout_thread_t *) vout subView: (NSView *) view
159 frame: (NSRect *) frame
162 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
163 NSArray *o_screens = [NSScreen screens];
169 if( [o_screens count] <= 0 )
171 msg_Err( p_vout, "no OSX screens available" );
175 p_real_vout = [VLCVoutView getRealVout: p_vout];
177 /* Get the pref value when this is the first time, otherwise retrieve the device from the top level video-device var */
178 if( var_Type( p_real_vout->p_libvlc, "video-device" ) == 0 )
180 i_device = var_GetInteger( p_vout, "macosx-vdev" );
184 i_device = var_GetInteger( p_real_vout->p_libvlc, "video-device" );
187 /* Setup the menuitem for the multiple displays. */
188 if( var_Type( p_real_vout, "video-device" ) == 0 )
191 vlc_value_t val2, text;
194 var_Create( p_real_vout, "video-device", VLC_VAR_INTEGER |
196 text.psz_string = _("Video Device");
197 var_Change( p_real_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
199 NSEnumerator * o_enumerator = [o_screens objectEnumerator];
202 text.psz_string = _("Default");
203 var_Change( p_real_vout, "video-device",
204 VLC_VAR_ADDCHOICE, &val2, &text );
205 var_Set( p_real_vout, "video-device", val2 );
207 while( (o_screen = [o_enumerator nextObject]) != NULL )
210 NSRect s_rect = [o_screen frame];
212 snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
213 "%s %d (%dx%d)", _("Screen"), i,
214 (int)s_rect.size.width, (int)s_rect.size.height );
216 text.psz_string = psz_temp;
217 val2.i_int = (int)[o_screen displayID];
218 var_Change( p_real_vout, "video-device",
219 VLC_VAR_ADDCHOICE, &val2, &text );
220 if( (int)[o_screen displayID] == i_device )
222 var_Set( p_real_vout, "video-device", val2 );
227 var_AddCallback( p_real_vout, "video-device", DeviceCallback,
230 val2.b_bool = VLC_TRUE;
231 var_Set( p_real_vout, "intf-change", val2 );
234 /* Add the view. It's automatically resized to fit the window */
235 [self addSubview: o_view];
236 [self setAutoresizesSubviews: YES];
242 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize
244 [super resizeSubviewsWithOldSize: oldBoundsSize];
245 [o_view setFrameSize: [self frame].size];
248 - (void)drawRect:(NSRect)rect
250 /* When there is no subview we draw a black background */
252 [[NSColor blackColor] set];
259 [[[[VLCMain sharedInstance] getControls] getFSPanel] fadeOut];
261 /* Make sure we don't see a white flash */
262 [[self window] disableScreenUpdatesUntilFlush];
263 [o_view removeFromSuperview];
273 NSMutableString * o_title = nil, * o_mrl = nil;
274 input_thread_t * p_input;
281 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT );
283 if( p_input == NULL )
288 if( input_GetItem(p_input)->psz_name != NULL )
289 o_title = [NSMutableString stringWithUTF8String:
290 input_GetItem(p_input)->psz_name];
291 if( input_GetItem(p_input)->psz_uri != NULL )
292 o_mrl = [NSMutableString stringWithUTF8String:
293 input_GetItem(p_input)->psz_uri];
299 /* FIXME once psz_access is exported, we could check if we are
300 * reading from a file in a smarter way. */
302 NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
303 if( prefix_range.location != NSNotFound )
304 [o_mrl deleteCharactersInRange: prefix_range];
306 if( [o_mrl characterAtIndex:0] == '/' )
308 /* it's a local file */
309 [o_window setRepresentedFilename: o_mrl];
313 /* it's from the network or somewhere else,
314 * we clear the previous path */
315 [o_window setRepresentedFilename: @""];
317 [o_window setTitle: o_title];
321 [o_window setTitle: [NSString stringWithCString: VOUT_TITLE]];
323 vlc_object_release( p_input );
327 - (void)setOnTop:(BOOL)b_on_top
331 [o_window setLevel: NSStatusWindowLevel];
335 [o_window setLevel: NSNormalWindowLevel];
339 - (void)scaleWindowWithFactor: (float)factor animate: (BOOL)animate
342 int i_corrected_height, i_corrected_width;
344 NSPoint topleftscreen;
346 if ( !p_vout->b_fullscreen )
351 topleftbase.y = [o_window frame].size.height;
352 topleftscreen = [o_window convertBaseToScreen: topleftbase];
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 );
370 /* In fullscreen mode we need to use a view that is different from
371 * ourselves, with the VLCEmbeddedWindow */
372 if([o_window isKindOfClass:[VLCEmbeddedWindow class]])
373 mainView = [o_window mainView];
377 /* Calculate the window's new size */
378 new_frame.size.width = [o_window frame].size.width -
379 [mainView frame].size.width + newsize.width;
380 new_frame.size.height = [o_window frame].size.height -
381 [mainView frame].size.height + newsize.height;
383 new_frame.origin.x = topleftscreen.x;
384 new_frame.origin.y = topleftscreen.y - new_frame.size.height;
386 [o_window setFrame: new_frame display: animate animate: animate];
388 p_vout->i_changes |= VOUT_SIZE_CHANGE;
392 - (void)toggleFloatOnTop
396 if( !p_real_vout ) return;
397 if( var_Get( p_real_vout, "video-on-top", &val )>=0 && val.b_bool)
399 val.b_bool = VLC_FALSE;
403 val.b_bool = VLC_TRUE;
405 var_Set( p_real_vout, "video-on-top", val );
408 - (void)toggleFullscreen
411 if( !p_real_vout ) return;
412 var_Get( p_real_vout, "fullscreen", &val );
413 val.b_bool = !val.b_bool;
414 var_Set( p_real_vout, "fullscreen", val );
420 if( !p_real_vout ) return NO;
421 var_Get( p_real_vout, "fullscreen", &val );
422 return( val.b_bool );
427 vout_Control( p_real_vout, VOUT_SNAPSHOT );
432 /* Disable Screensaver, when we're playing something, but allow it on pause */
433 if( VLCIntf->p_sys->i_play_status == PLAYING_S )
434 UpdateSystemActivity( UsrActivity );
442 - (void)scrollWheel:(NSEvent *)theEvent
444 VLCControls * o_controls = (VLCControls *)[[NSApp delegate] getControls];
445 float f_absvalue = [theEvent deltaY] > 0.0f ? [theEvent deltaY] : -[theEvent deltaY];
451 if (f_absvalue > 1.1f)
453 for (i = 0; i < (int)f_absvalue; i++)
455 if ([theEvent deltaY] < 0.0f)
456 [o_controls volumeDown: self];
458 [o_controls volumeUp: self];
463 - (void)keyDown:(NSEvent *)o_event
467 unsigned int i_pressed_modifiers = 0;
470 i_pressed_modifiers = [o_event modifierFlags];
472 if( i_pressed_modifiers & NSShiftKeyMask )
473 val.i_int |= KEY_MODIFIER_SHIFT;
474 if( i_pressed_modifiers & NSControlKeyMask )
475 val.i_int |= KEY_MODIFIER_CTRL;
476 if( i_pressed_modifiers & NSAlternateKeyMask )
477 val.i_int |= KEY_MODIFIER_ALT;
478 if( i_pressed_modifiers & NSCommandKeyMask )
479 val.i_int |= KEY_MODIFIER_COMMAND;
481 key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
485 /* Escape should always get you out of fullscreen */
486 if( key == (unichar) 0x1b )
488 if( p_real_vout && [self isFullscreen] )
490 [self toggleFullscreen];
493 else if ( key == ' ' )
496 val.i_int = config_GetInt( p_vout, "key-play-pause" );
497 var_Set( p_vout->p_libvlc, "key-pressed", val );
501 val.i_int |= CocoaKeyToVLC( key );
502 var_Set( p_vout->p_libvlc, "key-pressed", val );
507 [super keyDown: o_event];
511 - (void)mouseDown:(NSEvent *)o_event
517 if( ( [o_event type] == NSLeftMouseDown ) &&
518 ( ! ( [o_event modifierFlags] & NSControlKeyMask ) ) )
520 if( [o_event clickCount] <= 1 )
522 /* single clicking */
523 var_Get( p_vout, "mouse-button-down", &val );
525 var_Set( p_vout, "mouse-button-down", val );
529 /* multiple clicking */
530 [self toggleFullscreen];
533 else if( ( [o_event type] == NSRightMouseDown ) ||
534 ( ( [o_event type] == NSLeftMouseDown ) &&
535 ( [o_event modifierFlags] & NSControlKeyMask ) ) )
537 msg_Dbg( p_vout, "received NSRightMouseDown (generic method) or Ctrl clic" );
538 [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] getVoutView]];
542 [super mouseDown: o_event];
545 - (void)otherMouseDown:(NSEvent *)o_event
549 if( p_vout && [o_event type] == NSOtherMouseDown )
551 var_Get( p_vout, "mouse-button-down", &val );
553 var_Set( p_vout, "mouse-button-down", val );
556 [super mouseDown: o_event];
559 - (void)rightMouseDown:(NSEvent *)o_event
561 if( p_vout && [o_event type] == NSRightMouseDown )
563 msg_Dbg( p_vout, "received NSRightMouseDown (specific method)" );
564 [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] getVoutView]];
567 [super mouseDown: o_event];
570 - (void)mouseUp:(NSEvent *)o_event
574 if( p_vout && [o_event type] == NSLeftMouseUp )
577 b_val.b_bool = VLC_TRUE;
578 var_Set( p_vout, "mouse-clicked", b_val );
580 var_Get( p_vout, "mouse-button-down", &val );
582 var_Set( p_vout, "mouse-button-down", val );
585 [super mouseUp: o_event];
588 - (void)otherMouseUp:(NSEvent *)o_event
592 if( p_vout && [o_event type] == NSOtherMouseUp )
594 var_Get( p_vout, "mouse-button-down", &val );
596 var_Set( p_vout, "mouse-button-down", val );
599 [super mouseUp: o_event];
602 - (void)rightMouseUp:(NSEvent *)o_event
604 if( p_vout && [o_event type] == NSRightMouseUp )
606 /* FIXME: this isn't the appropriate place, but we can't receive
607 * NSRightMouseDown some how */
608 msg_Dbg( p_vout, "received NSRightMouseUp" );
609 [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] getVoutView]];
612 [super mouseUp: o_event];
615 - (void)mouseDragged:(NSEvent *)o_event
617 [self mouseMoved: o_event];
620 - (void)otherMouseDragged:(NSEvent *)o_event
622 [self mouseMoved: o_event];
625 - (void)rightMouseDragged:(NSEvent *)o_event
627 [self mouseMoved: o_event];
630 - (void)mouseMoved:(NSEvent *)o_event
638 s_rect = [o_view bounds];
639 ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
640 b_inside = [o_view mouse: ml inRect: s_rect];
645 unsigned int i_width, i_height, i_x, i_y;
647 vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
648 (unsigned int)s_rect.size.height,
649 &i_x, &i_y, &i_width, &i_height );
651 val.i_int = ( ((int)ml.x) - i_x ) *
652 p_vout->render.i_width / i_width;
653 var_Set( p_vout, "mouse-x", val );
655 if( [[o_view className] isEqualToString: @"VLCGLView"] )
657 val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
658 p_vout->render.i_height / i_height;
662 val.i_int = ( ((int)ml.y) - i_y ) *
663 p_vout->render.i_height / i_height;
665 var_Set( p_vout, "mouse-y", val );
667 val.b_bool = VLC_TRUE;
668 var_Set( p_vout, "mouse-moved", val );
670 if( [self isFullscreen] )
671 [[[[VLCMain sharedInstance] getControls] getFSPanel] fadeIn];
674 [super mouseMoved: o_event];
677 - (BOOL)acceptsFirstResponder
682 - (BOOL)becomeFirstResponder
687 - (BOOL)resignFirstResponder
689 /* We need to stay the first responder or we'll miss some
694 /* Class methods used by the different vout modules */
696 + (vout_thread_t *)getRealVout: (vout_thread_t *)p_vout
698 /* p_real_vout: the vout we have to use to check for video-on-top
699 and a few other things. If we are the QuickTime output, it's us.
700 It we are the OpenGL provider, it is our parent. */
701 if( p_vout->i_object_type == VLC_OBJECT_OPENGL )
703 return (vout_thread_t *) p_vout->p_parent;
712 + (id)getVoutView: (vout_thread_t *)p_vout subView: (NSView *)view
713 frame: (NSRect *)s_frame
715 vlc_value_t value_drawable;
719 var_Get( p_vout->p_libvlc, "drawable", &value_drawable );
721 var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
722 var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
723 var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
724 var_Create( p_vout, "macosx-background", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
725 var_Create( p_vout, "macosx-black", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
726 var_Create( p_vout, "macosx-embedded", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
729 /* We only wait for NSApp to initialise if we're not embedded (as in the
730 * case of the Mozilla plugin). We can tell whether we're embedded or not
731 * by examining the "drawable" value: if it's zero, we're running in the
732 * main Mac intf; if it's non-zero, we're embedded. */
733 if( value_drawable.i_int == 0 )
735 /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
736 for( i_timeout = 20 ; i_timeout-- ; )
740 msleep( INTF_IDLE_SLEEP );
746 /* No MacOS X intf, unable to communicate with MT */
747 msg_Err( p_vout, "no MacOS X interface present" );
752 if ( VLCIntf && !(p_vout->b_fullscreen) &&
753 !(var_GetBool( p_vout, "macosx-background" )) &&
754 var_GetBool( p_vout, "macosx-embedded") )
756 o_return = [[[VLCMain sharedInstance] getEmbeddedList]
762 /* No embedded vout is available */
763 if( o_return == nil )
766 bzero( &null_rect, sizeof( NSRect ) );
767 o_return = [[VLCDetachedVoutView alloc] initWithFrame: null_rect ];
769 [o_return setVout: p_vout subView: view frame: s_frame];
773 - (void)enterFullscreen
775 [[o_view class] resetVout: p_vout];
776 [[[[VLCMain sharedInstance] getControls] getFSPanel] setActive: nil];
779 - (void)leaveFullscreen
781 [[o_view class] resetVout: p_vout];
782 [[[[VLCMain sharedInstance] getControls] getFSPanel] setNonActive: nil];
787 /*****************************************************************************
788 * VLCDetachedVoutView implementation
789 *****************************************************************************/
790 @implementation VLCDetachedVoutView
792 - (id)initWithFrame: (NSRect)frameRect
794 [super initWithFrame: frameRect];
795 i_time_mouse_last_moved = 0;
799 - (bool)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
800 frame: (NSRect *) s_arg_frame
802 BOOL b_return = [super setVout: p_arg_vout subView: view frame:s_arg_frame];
803 i_time_mouse_last_moved = mdate();
804 o_window = [[VLCVoutWindow alloc] initWithVout: p_arg_vout view: self
807 [view setFrame: [self frame]];
809 if( var_GetBool( p_real_vout, "video-on-top" ) )
811 [o_window setLevel: NSStatusWindowLevel];
815 [o_window setAcceptsMouseMovedEvents: TRUE];
821 [o_window closeWindow];
822 [o_window setAcceptsMouseMovedEvents: NO];
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];
856 if( p_vout->b_fullscreen )
858 if( mdate() - i_time_mouse_last_moved > 3000000 )
860 [self hideMouse: YES];
865 [self hideMouse: NO];
871 /*****************************************************************************
872 * VLCEmbeddedVoutView implementation
873 *****************************************************************************/
875 @implementation VLCEmbeddedVoutView
877 - (id)initWithFrame: (NSRect)frameRect
879 [super initWithFrame: frameRect];
881 [[[VLCMain sharedInstance] getEmbeddedList] addEmbeddedVout: self];
885 - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
886 frame: (NSRect *)s_arg_frame showWindow: (BOOL)b_show_window
889 b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame];
892 o_window = [self window];
894 [o_window makeKeyAndOrderFront: self];
895 [o_window setAcceptsMouseMovedEvents: TRUE];
897 if( var_GetBool( p_real_vout, "video-on-top" ) )
899 [o_window setLevel: NSStatusWindowLevel];
902 [view setFrameSize: [self frame].size];
907 - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
908 frame: (NSRect *) s_arg_frame
911 return [self setVout: p_arg_vout subView: view frame:s_arg_frame showWindow: YES];
914 - (void)setUsed: (BOOL)b_new_used
927 [o_window setAcceptsMouseMovedEvents: NO];
928 [[[VLCMain sharedInstance] getEmbeddedList] releaseEmbeddedVout: self];
934 @implementation VLCDetachedEmbeddedVoutView
937 o_embeddedwindow = [self window];
940 - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
941 frame: (NSRect *) s_arg_frame
943 BOOL b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame showWindow: NO];
945 /* o_window needs to point to our o_embeddedwindow, super might have set it
946 * to the fullscreen window that o_embeddedwindow setups during fullscreen */
947 o_window = o_embeddedwindow;
951 [o_window lockFullscreenAnimation];
953 [o_window setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
957 /* Make the window the front and key window before animating */
958 if ([o_window isVisible] && (![o_window isFullscreen]))
959 [o_window makeKeyAndOrderFront: self];
961 [self scaleWindowWithFactor: 1.0 animate: [o_window isVisible] && (![o_window isFullscreen])];
963 /* Make sure our window is visible, if we are not in fullscreen */
964 if (![o_window isFullscreen])
965 [o_window makeKeyAndOrderFront: self];
966 [o_window unlockFullscreenAnimation];
974 playlist_t * p_playlist = pl_Yield( VLCIntf );
976 if(!playlist_IsPlaying( p_playlist ))
977 [o_window performSelectorOnMainThread: @selector(orderOut:) withObject: self waitUntilDone: YES];
979 vlc_object_release( p_playlist );
984 - (void)enterFullscreen
986 /* We are in a VLCEmbeddedWindow */
987 [o_embeddedwindow performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: YES];
990 - (void)leaveFullscreen
992 /* We are in a VLCEmbeddedWindow */
993 [o_embeddedwindow performSelectorOnMainThread: @selector(leaveFullscreen) withObject: NULL waitUntilDone: YES];
997 /*****************************************************************************
998 * VLCVoutWindow implementation
999 *****************************************************************************/
1000 @implementation VLCVoutWindow
1002 - (id) initWithVout: (vout_thread_t *) vout view: (VLCVoutView *) view
1003 frame: (NSRect *) frame
1009 [self performSelectorOnMainThread: @selector(initReal:)
1010 withObject: NULL waitUntilDone: YES];
1020 - (id)initReal: (id) sender
1022 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
1023 NSArray *o_screens = [NSScreen screens];
1025 vlc_bool_t b_menubar_screen = VLC_FALSE;
1028 b_init_ok = VLC_FALSE;
1030 p_real_vout = [VLCVoutView getRealVout: p_vout];
1031 i_device = var_GetInteger( p_real_vout->p_libvlc, "video-device" );
1033 b_embedded = var_GetBool( p_vout, "macosx-embedded" );
1035 /* Find out on which screen to open the window */
1036 o_screen = [NSScreen screenWithDisplayID: (CGDirectDisplayID)i_device];
1039 o_screen = [NSScreen mainScreen];
1041 if( [o_screen isMainScreen] )
1042 b_menubar_screen = VLC_TRUE;
1044 if( p_vout->b_fullscreen )
1046 CGDisplayFadeReservationToken token;
1047 NSRect screen_rect = [o_screen frame];
1048 screen_rect.origin.x = screen_rect.origin.y = 0;
1050 b_black = var_GetBool( p_vout, "macosx-black" );
1052 /* move the FSPanel to front in case that it is currently shown
1053 * this won't and is not supposed to work when it's fading right now */
1054 if( [[[[VLCMain sharedInstance] getControls] getFSPanel] isDisplayed] )
1055 [[[[VLCMain sharedInstance] getControls] getFSPanel] setActive: nil];
1057 /* tell the fspanel to move itself to front next time it's triggered */
1058 [[[[VLCMain sharedInstance] getControls] getFSPanel] setVoutWasUpdated: i_device];
1060 /* Creates a window with size: screen_rect on o_screen */
1061 [self initWithContentRect: screen_rect
1062 styleMask: NSBorderlessWindowMask
1063 backing: NSBackingStoreBuffered
1064 defer: YES screen: o_screen];
1066 if( b_menubar_screen )
1068 SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1070 if( b_black == VLC_TRUE )
1072 CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
1073 CGDisplayFade( token, 0.6 , kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
1075 [o_screen blackoutOtherScreens];
1077 CGDisplayFade( token, 0.3 , kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, NO );
1078 CGReleaseDisplayFadeReservation( token);
1081 else if( var_GetBool( p_vout, "macosx-background" ) )
1083 NSRect screen_rect = [o_screen frame];
1084 screen_rect.origin.x = screen_rect.origin.y = 0;
1086 /* Creates a window with size: screen_rect on o_screen */
1087 [self initWithContentRect: screen_rect
1088 styleMask: NSBorderlessWindowMask
1089 backing: NSBackingStoreBuffered
1090 defer: YES screen: o_screen];
1092 [self setLevel: CGWindowLevelForKey(kCGDesktopWindowLevelKey)];
1096 unsigned int i_stylemask = NSTitledWindowMask |
1097 NSMiniaturizableWindowMask |
1098 NSClosableWindowMask |
1099 NSResizableWindowMask;
1104 s_rect.size.width = p_vout->i_window_width;
1105 s_rect.size.height = p_vout->i_window_height;
1112 [self initWithContentRect: s_rect
1113 styleMask: i_stylemask
1114 backing: NSBackingStoreBuffered
1115 defer: YES screen: o_screen];
1117 [self setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
1125 [self makeKeyAndOrderFront: nil];
1126 [self setReleasedWhenClosed: YES];
1128 /* We'll catch mouse events */
1129 [self makeFirstResponder: o_view];
1131 /* Add the view. It's automatically resized to fit the window */
1132 [self setContentView: o_view];
1136 b_init_ok = VLC_TRUE;
1147 /* XXX waitUntilDone = NO to avoid a possible deadlock when hitting
1149 [self performSelectorOnMainThread: @selector(closeReal:)
1150 withObject: NULL waitUntilDone: NO];
1153 - (id)closeReal:(id)sender
1155 if( b_black == VLC_TRUE )
1157 CGDisplayFadeReservationToken token;
1158 CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
1159 CGDisplayFade( token, 0.3 , kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, YES );
1161 [self disableScreenUpdatesUntilFlush];
1162 [self orderOut: self];
1164 CGDisplayFade( token, 0.6 , kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, YES );
1165 CGReleaseDisplayFadeReservation( token);
1166 CGDisplayRestoreColorSyncSettings();
1168 [NSScreen unblackoutScreens];
1170 SetSystemUIMode( kUIModeNormal, 0);
1172 /* this does only work in embedded mode */
1173 if( b_embedded == VLC_TRUE )
1174 [[[[VLCMain sharedInstance] getControls] getFSPanel] orderOut: self];
1184 - (BOOL)canBecomeKeyWindow
1189 /* Sometimes crashes VLC....
1190 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
1192 return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event];
1195 /* This is actually the same as VLCControls::stop. */
1197 - (BOOL)windowShouldClose:(id)sender
1199 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1201 if( p_playlist == NULL )
1206 playlist_Stop( p_playlist );
1207 vlc_object_release( p_playlist );
1209 /* The window will be closed by the intf later. */