gui/macosx: Do not automatically resize the video view by calling scaleWindowWithFact...
[vlc/asuraparaju-public.git] / modules / gui / macosx / vout.m
blobebc803af1470ff56f4e823802292cd69b5808040
1 /*****************************************************************************
2  * vout.m: MacOS X video output module
3  *****************************************************************************
4  * Copyright (C) 2001-2009 the VideoLAN team
5  * $Id$
6  *
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>
14  *
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.
19  *
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.
24  *
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 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include <errno.h>                                                 /* ENOMEM */
34 #include <stdlib.h>                                                /* free() */
35 #include <string.h>
37 /* prevent system sleep */
38 #import <CoreServices/CoreServices.h>
39 /* FIXME: HACK!! */
40 #ifdef __x86_64__
41 #import <CoreServices/../Frameworks/OSServices.framework/Headers/Power.h>
42 #endif
44 /* SystemUIMode */
45 #import <Carbon/Carbon.h>
48 #include "intf.h"
49 #include "fspanel.h"
50 #include "vout.h"
51 #import "controls.h"
52 #import "embeddedwindow.h"
54 #include <vlc_common.h>
55 #include <vlc_keys.h>
57 /*****************************************************************************
58  * DeviceCallback: Callback triggered when the video-device variable is changed
59  *****************************************************************************/
60 int DeviceCallback( vlc_object_t *p_this, const char *psz_variable,
61                      vlc_value_t old_val, vlc_value_t new_val, void *param )
63     vlc_value_t val;
64     vout_thread_t *p_vout = (vout_thread_t *)p_this;
66     msg_Dbg( p_vout, "set %d", new_val.i_int );
67     var_Create( p_vout->p_libvlc, "video-device", VLC_VAR_INTEGER );
68     var_Set( p_vout->p_libvlc, "video-device", new_val );
70     val.b_bool = true;
71     var_Set( p_vout, "intf-change", val );
72     return VLC_SUCCESS;
76 /*****************************************************************************
77  * VLCEmbeddedList implementation
78  *****************************************************************************/
79 @implementation VLCEmbeddedList
81 - (id)init
83     [super init];
84     o_embedded_array = [NSMutableArray array];
85     return self;
88 - (id)embeddedVout
90     unsigned int i;
92     for( i = 0; i < [o_embedded_array count]; i++ )
93     {
94         id o_vout_view = [o_embedded_array objectAtIndex: i];
95         if( ![o_vout_view isUsed] )
96         {
97             [o_vout_view setUsed: YES];
98             return o_vout_view;
99         }
100     }
101     return nil;
104 - (void)releaseEmbeddedVout: (id)o_vout_view
106     if( [o_embedded_array containsObject: o_vout_view] )
107     {
108         [o_vout_view setUsed: NO];
109     }
110     else
111     {
112         msg_Warn( VLCIntf, "cannot find Video Output");
113     }
116 - (void)addEmbeddedVout: (id)o_vout_view
118     if( ![o_embedded_array containsObject: o_vout_view] )
119     {
120         [o_embedded_array addObject: o_vout_view];
121     }
124 - (BOOL)windowContainsEmbedded: (id)o_window
126 /*    if( ![[o_window className] isEqualToString: @"VLCVoutWindow"] )
127     {
128         NSLog( @"We were not given a VLCVoutWindow" );
129     }*/
130     return ([self viewForWindow: o_window] == nil ? NO : YES );
133 - (id)viewForWindow: (id)o_window
135     if( o_embedded_array != nil )
136     {
137         id o_enumerator = [o_embedded_array objectEnumerator];
138         id o_current_embedded;
139         if( o_window != nil )
140         {
141             while( (o_current_embedded = [o_enumerator nextObject]) )
142             {
143                 if( [o_current_embedded voutWindow] == o_window )
144                 {
145                     return o_current_embedded;
146                 }
147             }
148         }
149     }
150     return nil;
153 @end
155 /*****************************************************************************
156  * VLCVoutView implementation
157  *****************************************************************************/
158 @implementation VLCVoutView
160 - (id)initWithFrame: (NSRect)frameRect
162     self = [super initWithFrame: frameRect];
163     p_vout = NULL;
164     o_view = nil;
165     s_frame = &frameRect;
167     p_real_vout = NULL;
168     o_window = nil;
169     return self;
172 - (BOOL)setVout: (vout_thread_t *) vout
173         subView: (NSView *) view
174           frame: (NSRect *) frame
176     int i_device;
177     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
178     NSArray *o_screens = [NSScreen screens];
180     p_vout  = vout;
181     o_view  = view;
182     s_frame = frame;
184     if( [o_screens count] <= 0 )
185     {
186         msg_Err( p_vout, "no OSX screens available" );
187         return NO;
188     }
190     p_real_vout = [VLCVoutView realVout: p_vout];
192     /* Get the pref value when this is the first time, otherwise retrieve the device from the top level video-device var */
193     if( var_Type( p_real_vout->p_libvlc, "video-device" ) == 0 )
194     {
195         i_device = var_GetInteger( p_vout, "macosx-vdev" );
196     }
197     else
198     {
199         i_device = var_GetInteger( p_real_vout->p_libvlc, "video-device" );
200     }
202     /* Setup the menuitem for the multiple displays. */
203     if( var_Type( p_real_vout, "video-device" ) == 0 )
204     {
205         int i = 1;
206         vlc_value_t val2, text;
207         NSScreen * o_screen;
209         var_Create( p_real_vout, "video-device", VLC_VAR_INTEGER |
210                                             VLC_VAR_HASCHOICE );
211         text.psz_string = _("Fullscreen Video Device");
212         var_Change( p_real_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
214         NSEnumerator * o_enumerator = [o_screens objectEnumerator];
216         val2.i_int = 0;
217         text.psz_string = _("Default");
218         var_Change( p_real_vout, "video-device",
219                         VLC_VAR_ADDCHOICE, &val2, &text );
220         var_Set( p_real_vout, "video-device", val2 );
222         while( (o_screen = [o_enumerator nextObject]) != NULL )
223         {
224             char psz_temp[255];
225             NSRect s_rect = [o_screen frame];
227             snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
228                       "%s %d (%dx%d)", _("Screen"), i,
229                       (int)s_rect.size.width, (int)s_rect.size.height );
231             text.psz_string = psz_temp;
232             val2.i_int = (int)[o_screen displayID];
233             var_Change( p_real_vout, "video-device",
234                         VLC_VAR_ADDCHOICE, &val2, &text );
235             if( (int)[o_screen displayID] == i_device )
236             {
237                 var_Set( p_real_vout, "video-device", val2 );
238             }
239             i++;
240         }
242         var_AddCallback( p_real_vout, "video-device", DeviceCallback,
243                          NULL );
245         val2.b_bool = true;
246         var_Set( p_real_vout, "intf-change", val2 );
247     }
249     /* Add the view. It's automatically resized to fit the window */
250     [self addSubview: o_view];
251     [self setAutoresizesSubviews: YES];
252     [o_pool release];
254     return YES;
257 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize
259     [super resizeSubviewsWithOldSize: oldBoundsSize];
260     [o_view setFrameSize: [self frame].size];
263 - (void)drawRect:(NSRect)rect
265     /* When there is no subview we draw a black background */
266     [self lockFocus];
267     [[NSColor blackColor] set];
268     NSRectFill(rect);
269     [self unlockFocus];
272 - (void)closeVout
274     [[[[VLCMain sharedInstance] controls] fspanel] fadeOut];
276     /* Make sure we don't see a white flash */
277     [[self voutWindow] disableScreenUpdatesUntilFlush];
278     [o_view removeFromSuperview];
279     o_view = nil;
280     p_vout = NULL;
281     s_frame = nil;
282     o_window = nil;
283     p_real_vout = NULL;
286 - (void)updateTitle
288     NSString * o_title = nil; 
289     NSMutableString * o_mrl = nil;
290     input_thread_t * p_input;
291     char * psz_title;
293     if( !p_vout ) return;
295     p_input = getInput();
297     if( !p_input ) return;
299     input_item_t * p_item = input_GetItem( p_input );
301     psz_title = input_item_GetNowPlaying ( p_item );
302     if( !psz_title )
303         psz_title = input_item_GetName( p_item );
305     if( psz_title )
306         o_title = [NSString stringWithUTF8String: psz_title];
308     char *psz_uri = input_item_GetURI( p_item );
309     if( psz_uri )
310         o_mrl = [NSMutableString stringWithUTF8String: psz_uri];
312     free( psz_title );
313     free( psz_uri );
315     if( !o_title )
316         o_title = o_mrl;
318     if( o_mrl != nil )
319     {
320         /* FIXME once psz_access is exported, we could check if we are
321          * reading from a file in a smarter way. */
323         NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
324         if( prefix_range.location != NSNotFound )
325             [o_mrl deleteCharactersInRange: prefix_range];
327         if( [o_mrl characterAtIndex:0] == '/' )
328         {
329             /* it's a local file */
330             [o_window setRepresentedFilename: o_mrl];
331         }
332         else
333         {
334             /* it's from the network or somewhere else,
335              * we clear the previous path */
336             [o_window setRepresentedFilename: @""];
337         }
338         [o_window setTitle: o_title];
339     }
340     else
341     {
342         [o_window setTitle: [NSString stringWithUTF8String: VOUT_TITLE]];
343     }
344     vlc_object_release( p_input );
347 - (void)setOnTop:(BOOL)b_on_top
349     if( b_on_top )
350     {
351         [o_window setLevel: NSStatusWindowLevel];
352     }
353     else
354     {
355         [o_window setLevel: NSNormalWindowLevel];
356     }
359 - (NSSize)voutSizeForFactor: (float)factor
361     int i_corrected_height, i_corrected_width;
362     NSSize newsize;
364     if( p_vout->render.i_height * p_vout->render.i_aspect >
365                     p_vout->render.i_width * VOUT_ASPECT_FACTOR )
366     {
367         i_corrected_width = p_vout->render.i_height * p_vout->render.i_aspect /
368                                         VOUT_ASPECT_FACTOR;
369         newsize.width = (int) ( i_corrected_width * factor );
370         newsize.height = (int) ( p_vout->render.i_height * factor );
371     }
372     else
373     {
374         i_corrected_height = p_vout->render.i_width * VOUT_ASPECT_FACTOR /
375                                         p_vout->render.i_aspect;
376         newsize.width = (int) ( p_vout->render.i_width * factor );
377         newsize.height = (int) ( i_corrected_height * factor );
378     }
380     return newsize;
383 - (void)scaleWindowWithFactor: (float)factor animate: (BOOL)animate
385     if ( !p_vout->b_fullscreen )
386     {
387         NSSize newsize;
388         NSPoint topleftbase;
389         NSPoint topleftscreen;
390         NSView *mainView;
391         NSRect new_frame;
392         topleftbase.x = 0;
393         topleftbase.y = [o_window frame].size.height;
394         topleftscreen = [o_window convertBaseToScreen: topleftbase];
396         newsize = [self voutSizeForFactor:factor];
398         /* In fullscreen mode we need to use a view that is different from
399          * ourselves, with the VLCEmbeddedWindow */
400         if([o_window isKindOfClass:[VLCEmbeddedWindow class]])
401             mainView = [o_window mainView];
402         else
403             mainView = self;
405         /* Calculate the window's new size */
406         new_frame.size.width = [o_window frame].size.width -
407                                     [mainView frame].size.width + newsize.width;
408         new_frame.size.height = [o_window frame].size.height -
409                                     [mainView frame].size.height + newsize.height;
411         new_frame.origin.x = topleftscreen.x;
412         new_frame.origin.y = topleftscreen.y - new_frame.size.height;
414         [o_window setFrame:new_frame display:animate animate:animate];
415         p_vout->i_changes |= VOUT_SIZE_CHANGE;
416     }
419 - (void)toggleFloatOnTop
421     vlc_value_t val;
423     if( !p_real_vout ) return;
424     if( var_Get( p_real_vout, "video-on-top", &val )>=0 && val.b_bool)
425     {
426         val.b_bool = false;
427     }
428     else
429     {
430         val.b_bool = true;
431     }
432     var_Set( p_real_vout, "video-on-top", val );
435 - (void)toggleFullscreen
437     vlc_value_t val;
438     if( !p_real_vout ) return;
439     var_ToggleBool( p_real_vout, "fullscreen" );
442 - (BOOL)isFullscreen
444     vlc_value_t val;
445     if( !p_real_vout ) return NO;
446     var_Get( p_real_vout, "fullscreen", &val );
447     return( val.b_bool );
450 - (void)snapshot
452     var_TriggerCallback( p_real_vout, "video-snapshot" );
455 - (void)manage
457     /* Disable Screensaver, when we're playing something, but allow it on pause */
458     if( !VLCIntf || !VLCIntf->p_sys )
459         return;
461     if( VLCIntf->p_sys->i_play_status == PLAYING_S )
462         UpdateSystemActivity( UsrActivity );
465 - (id)voutWindow
467     return o_window;
470 - (void)scrollWheel:(NSEvent *)theEvent
472     VLCControls * o_controls = (VLCControls *)[[NSApp delegate] controls];
473     [o_controls scrollWheel: theEvent];
476 - (void)keyDown:(NSEvent *)o_event
478     unichar key = 0;
479     vlc_value_t val;
480     unsigned int i_pressed_modifiers = 0;
481     val.i_int = 0;
483     i_pressed_modifiers = [o_event modifierFlags];
485     if( i_pressed_modifiers & NSShiftKeyMask )
486         val.i_int |= KEY_MODIFIER_SHIFT;
487     if( i_pressed_modifiers & NSControlKeyMask )
488         val.i_int |= KEY_MODIFIER_CTRL;
489     if( i_pressed_modifiers & NSAlternateKeyMask )
490         val.i_int |= KEY_MODIFIER_ALT;
491     if( i_pressed_modifiers & NSCommandKeyMask )
492         val.i_int |= KEY_MODIFIER_COMMAND;
494     key = [[[o_event charactersIgnoringModifiers] lowercaseString] characterAtIndex: 0];
496     if( key )
497     {
498         /* Escape should always get you out of fullscreen */
499         if( key == (unichar) 0x1b )
500         {
501              if( p_real_vout && [self isFullscreen] )
502              {
503                  [self toggleFullscreen];
504              }
505         }
506         else if ( p_vout )
507         {
508             if( key == ' ')
509                 val.i_int = config_GetInt( p_vout, "key-play-pause" );
510             else
511                 val.i_int |= (int)CocoaKeyToVLC( key );
512             var_Set( p_vout->p_libvlc, "key-pressed", val );
513         }
514         else NSLog( @"Could not send keyevent to VLC core" );
515     }
516     else
517         [super keyDown: o_event];
520 - (void)mouseDown:(NSEvent *)o_event
522     vlc_value_t val;
523     if( p_vout )
524     {
525         if( ( [o_event type] == NSLeftMouseDown ) &&
526           ( ! ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
527         {
528             if( [o_event clickCount] <= 1 )
529             {
530                 /* single clicking */
531                 var_Get( p_vout, "mouse-button-down", &val );
532                 val.i_int |= 1;
533                 var_Set( p_vout, "mouse-button-down", val );
534             }
535             else
536             {
537                 /* multiple clicking */
538                 [self toggleFullscreen];
539             }
540         }
541         else if( ( [o_event type] == NSRightMouseDown ) ||
542                ( ( [o_event type] == NSLeftMouseDown ) &&
543                  ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
544         {
545             msg_Dbg( p_vout, "received NSRightMouseDown (generic method) or Ctrl clic" );
546             [NSMenu popUpContextMenu: [[VLCMain sharedInstance] voutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] controls] voutView]];
547         }
548     }
550     [super mouseDown: o_event];
553 - (void)otherMouseDown:(NSEvent *)o_event
555     vlc_value_t val;
557     if( p_vout && [o_event type] == NSOtherMouseDown )
558     {
559         var_Get( p_vout, "mouse-button-down", &val );
560         val.i_int |= 2;
561         var_Set( p_vout, "mouse-button-down", val );
562     }
564     [super mouseDown: o_event];
567 - (void)rightMouseDown:(NSEvent *)o_event
569     if( p_vout && [o_event type] == NSRightMouseDown )
570     {
571         msg_Dbg( p_vout, "received NSRightMouseDown (specific method)" );
572         [NSMenu popUpContextMenu: [[VLCMain sharedInstance] voutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] controls] voutView]];
573     }
575     [super mouseDown: o_event];
578 - (void)mouseUp:(NSEvent *)o_event
580     vlc_value_t val;
582     if( p_vout && [o_event type] == NSLeftMouseUp )
583     {
584         var_SetBool( p_vout, "mouse-clicked", true );
586         var_Get( p_vout, "mouse-button-down", &val );
587         val.i_int &= ~1;
588         var_Set( p_vout, "mouse-button-down", val );
589     }
591     [super mouseUp: o_event];
594 - (void)otherMouseUp:(NSEvent *)o_event
596     vlc_value_t val;
598     if( p_vout && [o_event type] == NSOtherMouseUp )
599     {
600         var_Get( p_vout, "mouse-button-down", &val );
601         val.i_int &= ~2;
602         var_Set( p_vout, "mouse-button-down", val );
603     }
605     [super mouseUp: o_event];
608 - (void)rightMouseUp:(NSEvent *)o_event
610     if( p_vout && [o_event type] == NSRightMouseUp )
611     {
612         /* FIXME: this isn't the appropriate place, but we can't receive
613          * NSRightMouseDown some how */
614         msg_Dbg( p_vout, "received NSRightMouseUp" );
615         [NSMenu popUpContextMenu: [[VLCMain sharedInstance] voutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] controls] voutView]];
616     }
618     [super mouseUp: o_event];
621 - (void)mouseDragged:(NSEvent *)o_event
623     [self mouseMoved: o_event];
626 - (void)otherMouseDragged:(NSEvent *)o_event
628     [self mouseMoved: o_event];
631 - (void)rightMouseDragged:(NSEvent *)o_event
633     [self mouseMoved: o_event];
636 - (void)mouseMoved:(NSEvent *)o_event
638     NSPoint ml;
639     NSRect s_rect;
640     BOOL b_inside;
642     if( p_vout )
643     {
644         s_rect = [o_view bounds];
645         ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
646         b_inside = [o_view mouse: ml inRect: s_rect];
648         if( b_inside )
649         {
650             vlc_value_t val;
651             unsigned int i_width, i_height, i_x, i_y;
653             vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
654                                        (unsigned int)s_rect.size.height,
655                                        &i_x, &i_y, &i_width, &i_height );
657             val.i_int = ( ((int)ml.x) - i_x ) *
658                         p_vout->render.i_width / i_width;
659             var_Set( p_vout, "mouse-x", val );
661             if( [[o_view className] isEqualToString: @"VLCGLView"] )
662             {
663                 val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
664                             p_vout->render.i_height / i_height;
665             }
666             else
667             {
668                 val.i_int = ( ((int)ml.y) - i_y ) *
669                             p_vout->render.i_height / i_height;
670             }
671             var_Set( p_vout, "mouse-y", val );
673             val.b_bool = true;
674             var_Set( p_vout, "mouse-moved", val );
675         }
676         if( [self isFullscreen] )
677             [[[[VLCMain sharedInstance] controls] fspanel] fadeIn];
678     }
680     [super mouseMoved: o_event];
683 - (BOOL)acceptsFirstResponder
685     return YES;
688 - (BOOL)becomeFirstResponder
690     return YES;
693 - (BOOL)resignFirstResponder
695     /* We need to stay the first responder or we'll miss some
696        events */
697     return NO;
700 /* Class methods used by the different vout modules */
702 + (vout_thread_t *)realVout: (vout_thread_t *)p_vout
704     /* p_real_vout: the vout we have to use to check for video-on-top
705        and a few other things. If we are the QuickTime output, it's us.
706        It we are the OpenGL provider, it is our parent.
707        Since we can't be the QuickTime output anymore, we need to be
708        the parent.
709        FIXME: check with the caca and x11 vouts! */
710     return (vout_thread_t *) p_vout->p_parent;
713 + (id)voutView: (vout_thread_t *)p_vout subView: (NSView *)view
714          frame: (NSRect *)s_frame
716     int i_drawable_gl;
717     int i_timeout;
718     id o_return = nil;
720     i_drawable_gl = var_GetInteger( p_vout->p_libvlc, "drawable-gl" );
722     var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
723     var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
724     var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
725     var_Create( p_vout, "macosx-background", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
726     var_Create( p_vout, "macosx-black", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
727     var_Create( p_vout, "embedded-video", 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-gl" value: if it's zero, we're running in the
732      * main Mac intf; if it's non-zero, we're embedded. */
733     if( i_drawable_gl == 0 )
734     {
735         /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
736         for( i_timeout = 20 ; i_timeout-- ; )
737         {
738             if( NSApp == NULL )
739             {
740                 msleep( INTF_IDLE_SLEEP );
741             }
742         }
744         if( NSApp == NULL )
745         {
746             /* No MacOS X intf, unable to communicate with MT */
747             msg_Err( p_vout, "no MacOS X interface present" );
748             return nil;
749         }
750         else
751         {
752             if ( VLCIntf && !(p_vout->b_fullscreen) &&
753                         !(var_GetBool( p_vout, "macosx-background" )) &&
754                         var_GetBool( p_vout, "embedded-video") )
755             {
756                 o_return = [[[VLCMain sharedInstance] embeddedList] embeddedVout];
757             }
758         }
759     }
761     /* No embedded vout is available */
762     if( o_return == nil )
763     {
764         NSRect null_rect;
765         bzero( &null_rect, sizeof( NSRect ) );
766         o_return = [[VLCDetachedVoutView alloc] initWithFrame: null_rect ];
767     }
768     [o_return setVout: p_vout subView: view frame: s_frame];
769     return o_return;
772 - (void)enterFullscreen
774     /* Save the settings for next playing item */
775     playlist_t * p_playlist = pl_Hold( p_real_vout );
776     var_SetBool( p_playlist, "fullscreen", true );
777     pl_Release( p_real_vout );
780 - (void)leaveFullscreen
782     /* Save the settings for next playing item */
783     playlist_t * p_playlist = pl_Hold( p_real_vout );
784     var_SetBool( p_playlist, "fullscreen", false );
785     pl_Release( p_real_vout );
788 @end
790 /*****************************************************************************
791  * VLCDetachedVoutView implementation
792  *****************************************************************************/
793 @implementation VLCDetachedVoutView
795 - (id)initWithFrame: (NSRect)frameRect
797     [super initWithFrame: frameRect];
798     i_time_mouse_last_moved = 0;
799     return self;
802 - (BOOL)mouseDownCanMoveWindow
804     return YES;
807 - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
808                      frame: (NSRect *) s_arg_frame
810     BOOL b_return = [super setVout: p_arg_vout subView: view frame:s_arg_frame];
811     i_time_mouse_last_moved = mdate();
812     o_window = [[VLCVoutWindow alloc] initWithVout: p_arg_vout view: self
813                                                     frame: s_arg_frame];
814     
815     [self updateTitle];
816     if([self isFullscreen])
817         [o_window performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: YES];
818     else
819         [view setFrame: [self frame]];
821     return b_return;
824 - (void)closeVout
826     [o_window performSelectorOnMainThread: @selector(close) withObject: NULL waitUntilDone: YES];
827     i_time_mouse_last_moved = 0;
828     [super closeVout];
831 - (void)mouseMoved:(NSEvent *)o_event
833     i_time_mouse_last_moved = mdate();
834     [super mouseMoved: o_event];
837 - (void)hideMouse:(BOOL)b_hide
839     BOOL b_inside;
840     NSPoint ml;
841     NSView *o_contents = [o_window contentView];
843     ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
844     ml = [o_contents convertPoint:ml fromView:nil];
845     b_inside = [o_contents mouse: ml inRect: [o_contents bounds]];
847     if( b_hide && b_inside )
848     {
849         [NSCursor setHiddenUntilMouseMoves: YES];
850     }
851     else if( !b_hide )
852     {
853         [NSCursor setHiddenUntilMouseMoves: NO];
854     }
857 - (void)manage
859     /* Dooh, why do we spend processor time doing this kind of stuff? */
860     [super manage];
861     unsigned int i_mouse_hide_timeout =
862         var_CreateGetInteger(p_vout, "mouse-hide-timeout") * 1000;
864     if( i_mouse_hide_timeout < 100000 )
865         i_mouse_hide_timeout = 100000;
866     if( p_vout->b_fullscreen )
867     {
868         if( mdate() - i_time_mouse_last_moved > i_mouse_hide_timeout )
869         {
870             i_time_mouse_last_moved = mdate();
871             [self hideMouse: YES];
872         }
873     }
874     else
875     {
876         [self hideMouse: NO];
877     }
881 - (void)enterFullscreen
883     [o_window performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: NO];
884     [super enterFullscreen];
888 - (void)leaveFullscreen
890     [o_window performSelectorOnMainThread: @selector(leaveFullscreen) withObject: NULL waitUntilDone: NO];
891     [super leaveFullscreen];
895 - (void)scaleWindowWithFactor: (float)factor animate: (BOOL)animate
897     if( p_vout->b_fullscreen )
898         return;
899     [o_window setMovableByWindowBackground: NO];
900     [super scaleWindowWithFactor: factor animate: animate];
901     [o_window setMovableByWindowBackground: YES];
903 @end
905 /*****************************************************************************
906  * VLCEmbeddedVoutView implementation
907  *****************************************************************************/
909 @implementation VLCEmbeddedVoutView
911 - (void)awakeFromNib
913     o_embeddedwindow = [self window];
916 - (BOOL)mouseDownCanMoveWindow
918     return YES;
921 - (id)initWithFrame: (NSRect)frameRect
923     if(self = [super initWithFrame: frameRect])
924     {
925         b_used = NO;
926         [[[VLCMain sharedInstance] embeddedList] addEmbeddedVout: self];
927         o_embeddedwindow = nil; /* Filled later on in -awakeFromNib */
928     }
929     return self;
932 - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
933                  frame: (NSRect *)s_arg_frame
935     BOOL b_return;
937     [NSObject cancelPreviousPerformRequestsWithTarget:o_window];
939     b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame];
940     if( b_return )
941     {
942         o_window = [self window];
944         [o_window setAcceptsMouseMovedEvents: TRUE];
946         if( var_CreateGetBool( p_real_vout, "video-on-top" ) )
947         {
948             [o_window setLevel: NSStatusWindowLevel];
949         }
951         [view setFrameSize: [self frame].size];
952     }
954     /* o_window needs to point to our o_embeddedwindow, super might have set it
955      * to the fullscreen window that o_embeddedwindow setups during fullscreen */
956     o_window = o_embeddedwindow;
958     if( b_return )
959     {
960         [o_window lockFullscreenAnimation];
962         [o_window setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
964         [self updateTitle];
966         [NSObject cancelPreviousPerformRequestsWithTarget:o_window];
968         /* Make the window the front and key window before animating */
969         if ([o_window isVisible] && (![o_window isFullscreen]))
970             [o_window makeKeyAndOrderFront: self];
972         if ( [self window] != o_embeddedwindow )
973             [self scaleWindowWithFactor: 1.0 animate: [o_window isVisible] && (![o_window isFullscreen])];
975         [o_embeddedwindow setVideoRatio:[self voutSizeForFactor:1.0]];
977         /* Make sure our window is visible, if we are not in fullscreen */
978         if (![o_window isFullscreen])
979             [o_window makeKeyAndOrderFront: self];
980         [o_window unlockFullscreenAnimation];
982     }
984     return b_return;
987 - (void)setUsed: (BOOL)b_new_used
989     b_used = b_new_used;
992 - (BOOL)isUsed
994     return b_used;
997 - (void)closeVout
999     [super closeVout];
1001     /* Don't close the window yet, wait a bit to see if a new input is poping up */
1002     /* FIXME: Probably fade the window In and Out */
1003     /* FIXME: fix core */
1004     [o_embeddedwindow performSelector:@selector(orderOut:) withObject:nil afterDelay:3.];
1006     [[[VLCMain sharedInstance] embeddedList] releaseEmbeddedVout: self];
1009 - (void)enterFullscreen
1011     /* Save settings */
1012     [super enterFullscreen];
1014     /* We are in a VLCEmbeddedWindow */
1015     [o_embeddedwindow performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: YES];
1018 - (void)leaveFullscreen
1020     /* Save settings */
1021     [super leaveFullscreen];
1023     /* We are in a VLCEmbeddedWindow */
1024     [o_embeddedwindow performSelectorOnMainThread: @selector(leaveFullscreen) withObject: NULL waitUntilDone: YES];
1026 @end
1028 /*****************************************************************************
1029  * VLCVoutWindow implementation
1030  *****************************************************************************/
1031 @implementation VLCVoutWindow
1033 - (id) initWithVout: (vout_thread_t *) vout view: (VLCVoutView *) view
1034                      frame: (NSRect *) frame
1036     p_vout  = vout;
1037     o_view  = view;
1038     s_frame = frame;
1039     b_init_ok = NO;
1040     [self performSelectorOnMainThread: @selector(initMainThread:)
1041         withObject: NULL waitUntilDone: YES];
1043     return b_init_ok ? self : nil;
1046 - (id)initMainThread: (id) sender
1048     NSRect rect;
1049     rect.size.height = p_vout->i_window_height;
1050     rect.size.width  = p_vout->i_window_width;
1051     rect.origin.x = rect.origin.y = 70.;
1053     if( self = [super initWithContentRect:rect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO])
1054     {
1055         [self setBackgroundColor:[NSColor blackColor]];
1056         [self setHasShadow:YES];
1057         [self setMovableByWindowBackground: YES];
1058         [self center];
1059         [self makeKeyAndOrderFront: self];
1060         [self setReleasedWhenClosed: YES];
1061         [self setFrameUsingName:@"VLCVoutWindowDetached"];
1062         [self setFrameAutosaveName:@"VLCVoutWindowDetached"];
1064         /* We'll catch mouse events */
1065         [self makeFirstResponder: o_view];
1066         [self setCanBecomeKeyWindow: YES];
1067         [self setAcceptsMouseMovedEvents: YES];
1068         [self setIgnoresMouseEvents: NO];
1070         if( var_CreateGetBool( p_vout, "macosx-background" ) )
1071         {
1072             int i_device = var_GetInteger( p_vout->p_libvlc, "video-device" );
1074             /* Find out on which screen to open the window */
1075             NSScreen * screen = [NSScreen screenWithDisplayID: (CGDirectDisplayID)i_device];
1076             if( !screen ) screen = [NSScreen mainScreen];
1078             NSRect screen_rect = [screen frame];
1079             screen_rect.origin.x = screen_rect.origin.y = 0;
1081             /* Creates a window with size: screen_rect on o_screen */
1082             [self setFrame: screen_rect display: NO];
1084             [self setLevel: CGWindowLevelForKey(kCGDesktopWindowLevelKey)];
1085             [self setMovableByWindowBackground: NO];
1086         }
1087         if( var_CreateGetBool( p_vout, "video-on-top" ) )
1088         {
1089             [self setLevel: NSStatusWindowLevel];
1090         }
1092         [self setAlphaValue: var_CreateGetFloat( p_vout, "macosx-opaqueness" )];
1094         /* Add the view. It's automatically resized to fit the window */
1095         [self setContentView: o_view];
1097         b_init_ok = YES;
1098     }
1099     return self;
1102 - (void)enterFullscreen
1104     if( fullscreen ) return;
1106     NSScreen *screen;
1107     int i_device;
1108     BOOL b_black = NO;
1110     i_device = var_GetInteger( p_vout->p_libvlc, "video-device" );
1111     b_black = var_CreateGetBool( p_vout, "macosx-black" );
1113     /* Find out on which screen to open the window */
1114     screen = [NSScreen screenWithDisplayID: (CGDirectDisplayID)i_device];
1115     if( !screen ) screen = [self screen];
1117     if( b_black )
1118         [screen blackoutOtherScreens];
1120     [self setMovableByWindowBackground: NO];
1122     if( [screen isMainScreen] )
1123         SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1125     initialFrame = [self frame];
1126     [self setFrame:[screen frame] display:YES animate:YES];
1127     [self setLevel:NSNormalWindowLevel];
1129     /* tell the fspanel to move itself to front next time it's triggered */
1130     [[[[VLCMain sharedInstance] controls] fspanel] setVoutWasUpdated: i_device];
1131     [[[[VLCMain sharedInstance] controls] fspanel] setActive: nil];
1133     fullscreen = YES;
1136 - (void)leaveFullscreen
1138     if( !fullscreen ) return;
1139     fullscreen = NO;
1141     [NSScreen unblackoutScreens];
1143     [[[[VLCMain sharedInstance] controls] fspanel] setNonActive: nil];
1144     SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
1146     [self setFrame:initialFrame display:YES animate:YES];
1147     [self setMovableByWindowBackground: YES];
1148     if( var_GetBool( p_vout, "video-on-top" ) )
1149         [self setLevel: NSStatusWindowLevel];
1152 - (id)voutView
1154     return o_view;
1157 @end