]> git.sesse.net Git - vlc/blob - modules/gui/macosx/vout.m
* removed useless include
[vlc] / modules / gui / macosx / vout.m
1 /*****************************************************************************
2  * vout.m: MacOS X video output module
3  *****************************************************************************
4  * Copyright (C) 2001-2006 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 K\9fhne <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  *****************************************************************************/
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include <errno.h>                                                 /* ENOMEM */
34 #include <stdlib.h>                                                /* free() */
35 #include <string.h>                                            /* strerror() */
36
37 /* BeginFullScreen, EndFullScreen */
38 #include <QuickTime/QuickTime.h>
39
40 #include <vlc_keys.h>
41
42 #include "intf.h"
43 #include "vout.h"
44
45 /*****************************************************************************
46  * DeviceCallback: Callback triggered when the video-device variable is changed
47  *****************************************************************************/
48 int DeviceCallback( vlc_object_t *p_this, const char *psz_variable,
49                      vlc_value_t old_val, vlc_value_t new_val, void *param )
50 {
51     vlc_value_t val;
52     vout_thread_t *p_vout = (vout_thread_t *)p_this;
53
54     msg_Dbg( p_vout, "set %d", new_val.i_int );
55     var_Create( p_vout->p_vlc, "video-device", VLC_VAR_INTEGER );
56     var_Set( p_vout->p_vlc, "video-device", new_val );
57
58     val.b_bool = VLC_TRUE;
59     var_Set( p_vout, "intf-change", val );
60     return VLC_SUCCESS;
61 }
62
63
64 /*****************************************************************************
65  * VLCEmbeddedList implementation
66  *****************************************************************************/
67 @implementation VLCEmbeddedList
68
69 - (id)init
70 {
71     [super init];
72     o_embedded_array = [NSMutableArray array];
73     return self;
74 }
75
76 - (id)getEmbeddedVout
77 {
78     unsigned int i;
79
80     for( i = 0; i < [o_embedded_array count]; i++ )
81     {
82         id o_vout_view = [o_embedded_array objectAtIndex: i];
83         if( ![o_vout_view isUsed] )
84         {
85             [o_vout_view setUsed: YES];
86             return o_vout_view;
87         }
88     }
89     return nil;
90 }
91
92 - (void)releaseEmbeddedVout: (id)o_vout_view
93 {
94     if( [o_embedded_array containsObject: o_vout_view] )
95     {
96         [o_vout_view setUsed: NO];
97     }
98     else
99     {
100         msg_Warn( VLCIntf, "cannot find Video Output");
101     }
102 }
103
104 - (void)addEmbeddedVout: (id)o_vout_view
105 {
106     if( ![o_embedded_array containsObject: o_vout_view] )
107     {
108         [o_embedded_array addObject: o_vout_view];
109     }
110 }
111
112 - (BOOL)windowContainsEmbedded: (id)o_window
113 {
114 /*    if( ![[o_window className] isEqualToString: @"VLCWindow"] )
115     {
116         NSLog( @"We were not given a VLCWindow" );
117     }*/
118     return ([self getViewForWindow: o_window] == nil ? NO : YES );
119 }
120
121 - (id)getViewForWindow: (id)o_window
122 {
123     id o_enumerator = [o_embedded_array objectEnumerator];
124     id o_current_embedded;
125
126     while( (o_current_embedded = [o_enumerator nextObject]) )
127     {
128         if( [o_current_embedded getWindow] == o_window )
129         {
130             return o_current_embedded;
131         }
132     }
133     return nil;
134 }
135
136 @end
137
138 /*****************************************************************************
139  * VLCVoutView implementation
140  *****************************************************************************/
141 @implementation VLCVoutView
142
143 - (id)initWithFrame:(NSRect)frameRect
144 {
145     [super initWithFrame: frameRect];
146     p_vout = NULL;
147     o_view = nil;
148     s_frame = &frameRect;
149
150     p_real_vout = NULL;
151     o_window = nil;
152     return self;
153 }
154
155 - (BOOL)setVout: (vout_thread_t *) vout subView: (NSView *) view
156                      frame: (NSRect *) frame
157 {
158     int i_device;
159     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
160     NSArray *o_screens = [NSScreen screens];
161
162     p_vout  = vout;
163     o_view  = view;
164     s_frame = frame;
165
166     if( [o_screens count] <= 0 )
167     {
168         msg_Err( p_vout, "no OSX screens available" );
169         return NO;
170     }
171
172     p_real_vout = [VLCVoutView getRealVout: p_vout];
173
174     /* Get the pref value when this is the first time, otherwise retrieve the device from the top level video-device var */
175     if( var_Type( p_real_vout->p_vlc, "video-device" ) == 0 )
176     {
177         i_device = var_GetInteger( p_vout, "macosx-vdev" );
178     }
179     else
180     {
181         i_device = var_GetInteger( p_real_vout->p_vlc, "video-device" );
182     }
183
184     /* Setup the menuitem for the multiple displays. */
185     if( var_Type( p_real_vout, "video-device" ) == 0 )
186     {
187         int i = 1;
188         vlc_value_t val2, text;
189         NSScreen * o_screen;
190
191         var_Create( p_real_vout, "video-device", VLC_VAR_INTEGER |
192                                             VLC_VAR_HASCHOICE );
193         text.psz_string = _("Video Device");
194         var_Change( p_real_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
195
196         NSEnumerator * o_enumerator = [o_screens objectEnumerator];
197
198         val2.i_int = 0;
199         text.psz_string = _("Default");
200         var_Change( p_real_vout, "video-device",
201                         VLC_VAR_ADDCHOICE, &val2, &text );
202         var_Set( p_real_vout, "video-device", val2 );
203
204         while( (o_screen = [o_enumerator nextObject]) != NULL )
205         {
206             char psz_temp[255];
207             NSRect s_rect = [o_screen frame];
208
209             snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
210                       "%s %d (%dx%d)", _("Screen"), i,
211                       (int)s_rect.size.width, (int)s_rect.size.height );
212
213             text.psz_string = psz_temp;
214             val2.i_int = i;
215             var_Change( p_real_vout, "video-device",
216                         VLC_VAR_ADDCHOICE, &val2, &text );
217             if( i == i_device )
218             {
219                 var_Set( p_real_vout, "video-device", val2 );
220             }
221             i++;
222         }
223
224         var_AddCallback( p_real_vout, "video-device", DeviceCallback,
225                          NULL );
226
227         val2.b_bool = VLC_TRUE;
228         var_Set( p_real_vout, "intf-change", val2 );
229     }
230
231     /* Add the view. It's automatically resized to fit the window */
232     [self addSubview: o_view];
233     [self setAutoresizesSubviews: YES];
234     [o_pool release];
235
236     return YES;
237 }
238
239 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize
240 {
241     [super resizeSubviewsWithOldSize: oldBoundsSize];
242     [o_view setFrameSize: [self frame].size];
243 }
244
245 - (void)closeVout
246 {
247     [o_view removeFromSuperview];
248     o_view = nil;
249     p_vout = NULL;
250     s_frame = nil;
251     o_window = nil;
252     p_real_vout = NULL;
253 }
254
255 - (void)updateTitle
256 {
257     NSMutableString * o_title = nil, * o_mrl = nil;
258     input_thread_t * p_input;
259
260     if( p_vout == NULL )
261     {
262         return;
263     }
264
265     p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT );
266
267     if( p_input == NULL )
268     {
269         return;
270     }
271
272     if( p_input->input.p_item->psz_name != NULL )
273         o_title = [NSMutableString stringWithUTF8String:
274             p_input->input.p_item->psz_name];
275     if( p_input->input.p_item->psz_uri != NULL )
276         o_mrl = [NSMutableString stringWithUTF8String:
277             p_input->input.p_item->psz_uri];
278     if( o_title == nil )
279         o_title = o_mrl;
280
281     if( o_mrl != nil )
282     {
283         if( p_input->input.p_access && !strcmp( p_input->input.p_access->p_module->psz_shortname, "File" ) )
284         {
285             NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
286             if( prefix_range.location != NSNotFound )
287                 [o_mrl deleteCharactersInRange: prefix_range];
288             [o_window setRepresentedFilename: o_mrl];
289         }
290         [o_window setTitle: o_title];
291     }
292     else
293     {
294         [o_window setTitle: [NSString stringWithCString: VOUT_TITLE]];
295     }
296     vlc_object_release( p_input );
297 }
298
299
300 - (void)setOnTop:(BOOL)b_on_top
301 {
302     if( b_on_top )
303     {
304         [o_window setLevel: NSStatusWindowLevel];
305     }
306     else
307     {
308         [o_window setLevel: NSNormalWindowLevel];
309     }
310 }
311
312 - (void)scaleWindowWithFactor: (float)factor
313 {
314     NSSize newsize;
315     int i_corrected_height, i_corrected_width;
316     NSPoint topleftbase;
317     NSPoint topleftscreen;
318
319     if ( !p_vout->b_fullscreen )
320     {
321         NSRect new_frame;
322         topleftbase.x = 0;
323         topleftbase.y = [o_window frame].size.height;
324         topleftscreen = [o_window convertBaseToScreen: topleftbase];
325
326         if( p_vout->render.i_height * p_vout->render.i_aspect >
327                         p_vout->render.i_width * VOUT_ASPECT_FACTOR )
328         {
329             i_corrected_width = p_vout->render.i_height * p_vout->render.i_aspect /
330                                             VOUT_ASPECT_FACTOR;
331             newsize.width = (int) ( i_corrected_width * factor );
332             newsize.height = (int) ( p_vout->render.i_height * factor );
333         }
334         else
335         {
336             i_corrected_height = p_vout->render.i_width * VOUT_ASPECT_FACTOR /
337                                             p_vout->render.i_aspect;
338             newsize.width = (int) ( p_vout->render.i_width * factor );
339             newsize.height = (int) ( i_corrected_height * factor );
340         }
341
342         /* Calculate the window's new size */
343         new_frame.size.width = [o_window frame].size.width -
344                                     [self frame].size.width + newsize.width;
345         new_frame.size.height = [o_window frame].size.height -
346                                     [self frame].size.height + newsize.height;
347
348         new_frame.origin.x = topleftscreen.x;
349         new_frame.origin.y = topleftscreen.y - new_frame.size.height;
350
351         [o_window setFrame: new_frame display: YES];
352
353         p_vout->i_changes |= VOUT_SIZE_CHANGE;
354     }
355 }
356
357 - (void)toggleFloatOnTop
358 {
359     vlc_value_t val;
360
361     if( !p_real_vout ) return;
362     if( var_Get( p_real_vout, "video-on-top", &val )>=0 && val.b_bool)
363     {
364         val.b_bool = VLC_FALSE;
365     }
366     else
367     {
368         val.b_bool = VLC_TRUE;
369     }
370     var_Set( p_real_vout, "video-on-top", val );
371 }
372
373 - (void)toggleFullscreen
374 {
375     vlc_value_t val;
376     if( !p_real_vout ) return;
377     var_Get( p_real_vout, "fullscreen", &val );
378     val.b_bool = !val.b_bool;
379     var_Set( p_real_vout, "fullscreen", val );
380 }
381
382 - (BOOL)isFullscreen
383 {
384     vlc_value_t val;
385     var_Get( p_real_vout, "fullscreen", &val );
386     return( val.b_bool );
387 }
388
389 - (void)snapshot
390 {
391     vout_Control( p_real_vout, VOUT_SNAPSHOT );
392 }
393
394 - (void)manage
395 {
396     /* Disable Screensaver */
397     UpdateSystemActivity( UsrActivity );
398 }
399
400 - (id)getWindow
401 {
402     return o_window;
403 }
404
405 - (void)keyDown:(NSEvent *)o_event
406 {
407     unichar key = 0;
408     vlc_value_t val;
409     unsigned int i_pressed_modifiers = 0;
410     val.i_int = 0;
411
412     i_pressed_modifiers = [o_event modifierFlags];
413
414     if( i_pressed_modifiers & NSShiftKeyMask )
415         val.i_int |= KEY_MODIFIER_SHIFT;
416     if( i_pressed_modifiers & NSControlKeyMask )
417         val.i_int |= KEY_MODIFIER_CTRL;
418     if( i_pressed_modifiers & NSAlternateKeyMask )
419         val.i_int |= KEY_MODIFIER_ALT;
420     if( i_pressed_modifiers & NSCommandKeyMask )
421         val.i_int |= KEY_MODIFIER_COMMAND;
422
423     key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
424
425     if( key )
426     {
427         /* Escape should always get you out of fullscreen */
428         if( key == (unichar) 0x1b )
429         {
430              if( p_real_vout && [self isFullscreen] )
431              {
432                  [self toggleFullscreen];
433              }
434         }
435         else if ( key == ' ' )
436         {
437             vlc_value_t val;
438             val.i_int = config_GetInt( p_vout, "key-play-pause" );
439             var_Set( p_vout->p_vlc, "key-pressed", val );
440         }
441         else
442         {
443             val.i_int |= CocoaKeyToVLC( key );
444             var_Set( p_vout->p_vlc, "key-pressed", val );
445         }
446     }
447     else
448     {
449         [super keyDown: o_event];
450     }
451 }
452
453 - (void)mouseDown:(NSEvent *)o_event
454 {
455     vlc_value_t val;
456
457     if( p_vout )
458     {
459         switch( [o_event type] )
460         {
461             case NSLeftMouseDown:
462             {
463                 if( [o_event clickCount] <= 1 )
464                 {
465                     /* single clicking */
466                     var_Get( p_vout, "mouse-button-down", &val );
467                     val.i_int |= 1;
468                     var_Set( p_vout, "mouse-button-down", val );
469                 }
470                 else
471                 {
472                     /* multiple clicking */
473                     [self toggleFullscreen];
474                 }
475             }
476             break;
477             case NSRightMouseDown:
478             {
479                 msg_Dbg( p_vout, "received NSRightMouseDown (generic method)" );
480                 [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] getVoutView]];
481             }
482             break;
483
484             default:
485                 [super mouseDown: o_event];
486             break;
487         }
488     }
489 }
490
491 - (void)otherMouseDown:(NSEvent *)o_event
492 {
493     vlc_value_t val;
494
495     if( p_vout )
496     {
497         switch( [o_event type] )
498         {
499             case NSOtherMouseDown:
500             {
501                 var_Get( p_vout, "mouse-button-down", &val );
502                 val.i_int |= 2;
503                 var_Set( p_vout, "mouse-button-down", val );
504             }
505             break;
506
507             default:
508                 [super mouseDown: o_event];
509             break;
510         }
511     }
512 }
513
514 - (void)rightMouseDown:(NSEvent *)o_event
515 {
516     if( p_vout )
517     {
518         switch( [o_event type] )
519         {
520             case NSRightMouseDown:
521             {
522                 msg_Dbg( p_vout, "received NSRightMouseDown (specific method)" );
523                 [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] getVoutView]];
524             }
525             break;
526
527             default:
528                 [super mouseDown: o_event];
529             break;
530         }
531     }
532 }
533
534 - (void)mouseUp:(NSEvent *)o_event
535 {
536     vlc_value_t val;
537
538     if( p_vout )
539     {
540         switch( [o_event type] )
541         {
542             case NSLeftMouseUp:
543             {
544                 vlc_value_t b_val;
545                 b_val.b_bool = VLC_TRUE;
546                 var_Set( p_vout, "mouse-clicked", b_val );
547
548                 var_Get( p_vout, "mouse-button-down", &val );
549                 val.i_int &= ~1;
550                 var_Set( p_vout, "mouse-button-down", val );
551             }
552             break;
553
554             default:
555                 [super mouseUp: o_event];
556             break;
557         }
558     }
559 }
560
561 - (void)otherMouseUp:(NSEvent *)o_event
562 {
563     vlc_value_t val;
564
565     if( p_vout )
566     {
567         switch( [o_event type] )
568         {
569             case NSOtherMouseUp:
570             {
571                 var_Get( p_vout, "mouse-button-down", &val );
572                 val.i_int &= ~2;
573                 var_Set( p_vout, "mouse-button-down", val );
574             }
575             break;
576
577             default:
578                 [super mouseUp: o_event];
579             break;
580         }
581     }
582 }
583
584 - (void)rightMouseUp:(NSEvent *)o_event
585 {
586     if( p_vout )
587     {
588         switch( [o_event type] )
589         {
590             case NSRightMouseUp:
591             {
592                 /* FIXME: this isn't the appropriate place, but we can't receive
593                  * NSRightMouseDown some how */
594                 msg_Dbg( p_vout, "received NSRightMouseUp" ); 
595                 [NSMenu popUpContextMenu: [[VLCMain sharedInstance] getVoutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] getControls] getVoutView]];
596             }
597             break;
598
599             default:
600                 [super mouseUp: o_event];
601             break;
602         }
603     }
604 }
605
606 - (void)mouseDragged:(NSEvent *)o_event
607 {
608     [self mouseMoved: o_event];
609 }
610
611 - (void)otherMouseDragged:(NSEvent *)o_event
612 {
613     [self mouseMoved: o_event];
614 }
615
616 - (void)rightMouseDragged:(NSEvent *)o_event
617 {
618     [self mouseMoved: o_event];
619 }
620
621 - (void)mouseMoved:(NSEvent *)o_event
622 {
623     NSPoint ml;
624     NSRect s_rect;
625     BOOL b_inside;
626
627     if( p_vout )
628     {
629         s_rect = [o_view bounds];
630         ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
631         b_inside = [o_view mouse: ml inRect: s_rect];
632
633         if( b_inside )
634         {
635             vlc_value_t val;
636             unsigned int i_width, i_height, i_x, i_y;
637
638             vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
639                                        (unsigned int)s_rect.size.height,
640                                        &i_x, &i_y, &i_width, &i_height );
641
642             val.i_int = ( ((int)ml.x) - i_x ) *
643                         p_vout->render.i_width / i_width;
644             var_Set( p_vout, "mouse-x", val );
645
646             if( [[o_view className] isEqualToString: @"VLCGLView"] )
647             {
648                 val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
649                             p_vout->render.i_height / i_height;
650             }
651             else
652             {
653                 val.i_int = ( ((int)ml.y) - i_y ) *
654                             p_vout->render.i_height / i_height;
655             }
656             var_Set( p_vout, "mouse-y", val );
657
658             val.b_bool = VLC_TRUE;
659             var_Set( p_vout, "mouse-moved", val );
660         }
661     }
662     [super mouseMoved: o_event];
663 }
664
665 - (BOOL)acceptsFirstResponder
666 {
667     return YES;
668 }
669
670 - (BOOL)becomeFirstResponder
671 {
672     return YES;
673 }
674
675 - (BOOL)resignFirstResponder
676 {
677     /* We need to stay the first responder or we'll miss some
678        events */
679     return NO;
680 }
681
682 /* Class methods used by the different vout modules */
683
684 + (vout_thread_t *)getRealVout: (vout_thread_t *)p_vout
685 {
686     /* p_real_vout: the vout we have to use to check for video-on-top
687        and a few other things. If we are the QuickTime output, it's us.
688        It we are the OpenGL provider, it is our parent. */
689     if( p_vout->i_object_type == VLC_OBJECT_OPENGL )
690     {
691         return (vout_thread_t *) p_vout->p_parent;
692     }
693     else
694     {
695         return p_vout;
696     }
697
698 }
699
700 + (id)getVoutView: (vout_thread_t *)p_vout subView: (NSView *)view
701                                     frame: (NSRect *)s_frame
702 {
703     vlc_value_t value_drawable;
704     int i_timeout;
705     id o_return = nil;
706     vout_thread_t * p_real_vout = [VLCVoutView getRealVout: p_vout];
707
708     var_Get( p_vout->p_vlc, "drawable", &value_drawable );
709
710     var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
711     var_Create( p_vout, "macosx-fill", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
712     var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
713     var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
714     var_Create( p_vout, "macosx-background", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
715     var_Create( p_vout, "macosx-black", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
716     var_Create( p_vout, "macosx-embedded", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
717
718
719     /* We only wait for NSApp to initialise if we're not embedded (as in the
720      * case of the Mozilla plugin).  We can tell whether we're embedded or not
721      * by examining the "drawable" value: if it's zero, we're running in the
722      * main Mac intf; if it's non-zero, we're embedded. */
723     if( value_drawable.i_int == 0 )
724     {
725         /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
726         for( i_timeout = 20 ; i_timeout-- ; )
727         {
728             if( NSApp == NULL )
729             {
730                 msleep( INTF_IDLE_SLEEP );
731             }
732         }
733
734         if( NSApp == NULL )
735         {
736             /* No MacOS X intf, unable to communicate with MT */
737             msg_Err( p_vout, "no MacOS X interface present" );
738             return nil;
739         }
740         else
741         {
742             if ( VLCIntf && !(p_vout->b_fullscreen) &&
743                         !(var_GetBool( p_real_vout, "macosx-background" )) &&
744                         var_GetBool( p_vout, "macosx-embedded") )
745             {
746                 o_return = [[[VLCMain sharedInstance] getEmbeddedList]
747                                                             getEmbeddedVout];
748             }
749         }
750     }
751
752     /* No embedded vout is available */
753     if( o_return == nil )
754     {
755         NSRect null_rect;
756         bzero( &null_rect, sizeof( NSRect ) );
757         o_return = [[VLCDetachedVoutView alloc] initWithFrame: null_rect ];
758     }
759     [o_return setVout: p_vout subView: view frame: s_frame];
760     return o_return;
761 }
762
763 @end
764
765 /*****************************************************************************
766  * VLCDetachedVoutView implementation
767  *****************************************************************************/
768 @implementation VLCDetachedVoutView
769
770 - (id)initWithFrame: (NSRect)frameRect
771 {
772     [super initWithFrame: frameRect];
773     i_time_mouse_last_moved = 0;
774     return self;
775 }
776
777 - (bool)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
778                      frame: (NSRect *) s_arg_frame
779 {
780     BOOL b_return = [super setVout: p_arg_vout subView: view frame:s_arg_frame];
781     i_time_mouse_last_moved = mdate();
782     o_window = [[VLCWindow alloc] initWithVout: p_arg_vout view: self
783                                                     frame: s_arg_frame];
784     [self updateTitle];
785     [view setFrame: [self frame]];
786
787     if( var_GetBool( p_real_vout, "video-on-top" ) )
788     {
789         [o_window setLevel: NSStatusWindowLevel];
790     }
791
792
793     [o_window setAcceptsMouseMovedEvents: TRUE];
794     return b_return;
795 }
796
797 - (void)closeVout
798 {
799     [o_window closeWindow];
800     [o_window setAcceptsMouseMovedEvents: NO];
801     i_time_mouse_last_moved = 0;
802     [super closeVout];
803 }
804
805 - (void)mouseMoved:(NSEvent *)o_event
806 {
807     i_time_mouse_last_moved = mdate();
808     [super mouseMoved: o_event];
809 }
810
811 - (void)hideMouse:(BOOL)b_hide
812 {
813     BOOL b_inside;
814     NSPoint ml;
815     NSView *o_contents = [o_window contentView];
816
817     ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
818     ml = [o_contents convertPoint:ml fromView:nil];
819     b_inside = [o_contents mouse: ml inRect: [o_contents bounds]];
820
821     if( b_hide && b_inside )
822     {
823         [NSCursor setHiddenUntilMouseMoves: YES];
824     }
825     else if( !b_hide )
826     {
827         [NSCursor setHiddenUntilMouseMoves: NO];
828     }
829 }
830
831 - (void)manage
832 {
833     [super manage];
834     if( p_vout->b_fullscreen )
835     {
836         if( mdate() - i_time_mouse_last_moved > 3000000 )
837         {
838             [self hideMouse: YES];
839         }
840     }
841     else
842     {
843         [self hideMouse: NO];
844     }
845 }
846
847 @end
848
849 /*****************************************************************************
850  * VLCEmbeddedVoutView implementation
851  *****************************************************************************/
852
853 @implementation VLCEmbeddedVoutView
854
855 - (id)initWithFrame: (NSRect)frameRect
856 {
857     [super initWithFrame: frameRect];
858     b_used = NO;
859     [[[VLCMain sharedInstance] getEmbeddedList] addEmbeddedVout: self];
860     return self;
861 }
862
863 - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
864                      frame: (NSRect *) s_arg_frame
865
866 {
867     BOOL b_return;
868     b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame];
869     if( b_return )
870     {
871         o_window = [self window];
872         [o_window makeKeyAndOrderFront: self];
873         [o_window setAcceptsMouseMovedEvents: TRUE];
874
875         if( var_GetBool( p_real_vout, "video-on-top" ) )
876         {
877             [o_window setLevel: NSStatusWindowLevel];
878         }
879
880         [view setFrameSize: [self frame].size];
881     }
882     return b_return;
883 }
884
885 - (void)setUsed: (BOOL)b_new_used
886 {
887     b_used = b_new_used;
888 }
889
890 - (BOOL)isUsed
891 {
892     return b_used;
893 }
894
895 - (void)closeVout
896 {
897     [super closeVout];
898     [o_window setAcceptsMouseMovedEvents: NO];
899     [[[VLCMain sharedInstance] getEmbeddedList] releaseEmbeddedVout: self];
900 }
901
902
903 @end
904
905 @implementation VLCDetachedEmbeddedVoutView
906
907 - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
908                      frame: (NSRect *) s_arg_frame
909 {
910     BOOL b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame];
911
912     if( b_return )
913     {
914         [o_window setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
915         [self updateTitle];
916         [self scaleWindowWithFactor: 1.0];
917         [o_window makeKeyAndOrderFront: self];
918     }
919     return b_return;
920 }
921
922 - (void)closeVout
923 {
924     [o_window orderOut: self];
925     [super closeVout];
926 }
927
928 @end
929
930 /*****************************************************************************
931  * VLCWindow implementation
932  *****************************************************************************/
933 @implementation VLCWindow
934
935 - (id) initWithVout: (vout_thread_t *) vout view: (VLCVoutView *) view
936                      frame: (NSRect *) frame
937 {
938     p_vout  = vout;
939     o_view  = view;
940     s_frame = frame;
941
942     [self performSelectorOnMainThread: @selector(initReal:)
943         withObject: NULL waitUntilDone: YES];
944
945     if( !b_init_ok )
946     {
947         return NULL;
948     }
949
950     return self;
951 }
952
953 - (id)initReal: (id) sender
954 {
955     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
956     NSArray *o_screens = [NSScreen screens];
957     NSScreen *o_screen;
958     vlc_bool_t b_menubar_screen = VLC_FALSE;
959     int i_device;
960
961     b_init_ok = VLC_FALSE;
962
963     p_real_vout = [VLCVoutView getRealVout: p_vout];
964     i_device = var_GetInteger( p_real_vout->p_vlc, "video-device" );
965     b_black = var_GetBool( p_real_vout->p_vlc, "macosx-black" );
966
967     /* Find out on which screen to open the window */
968     if( i_device <= 0 || i_device > (int)[o_screens count] )
969     {
970          /* No preference specified. Use the main screen */
971         o_screen = [NSScreen mainScreen];
972         i_device = [o_screens indexOfObject: o_screen];
973         if( o_screen == [o_screens objectAtIndex: 0] )
974             b_menubar_screen = VLC_TRUE;
975     }
976     else
977     {
978         i_device--;
979         o_screen = [o_screens objectAtIndex: i_device];
980         b_menubar_screen = ( i_device == 0 );
981     }
982
983     if( p_vout->b_fullscreen )
984     {
985         CGDisplayFadeReservationToken token;
986         NSRect screen_rect = [o_screen frame];
987         screen_rect.origin.x = screen_rect.origin.y = 0;
988
989         /* Creates a window with size: screen_rect on o_screen */
990         [self initWithContentRect: screen_rect
991               styleMask: NSBorderlessWindowMask
992               backing: NSBackingStoreBuffered
993               defer: YES screen: o_screen];
994
995         if( var_GetBool( p_real_vout, "macosx-black" ) )
996         if( b_black == VLC_TRUE )
997         {
998             CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
999             CGDisplayFade( token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, true );
1000             CGReleaseDisplayFadeReservation( token );
1001             unsigned int i;
1002             for( i = 0 ; i < [o_screens count]; i++)
1003             {
1004                 struct
1005                 {
1006                     CGDirectDisplayID displayID;
1007                     CGGammaValue redMin, redMax, redGamma,
1008                                  greenMin, greenMax, greenGamma,
1009                                  blueMin, blueMax, blueGamma;
1010                 } dispSettings;
1011                 CGDisplayCount dspyCnt;
1012                 CGPoint gPoint;
1013
1014                 if( i == (unsigned int)i_device ) continue;
1015
1016                 screen_rect = [[o_screens objectAtIndex: i] frame];
1017
1018                 gPoint.x = screen_rect.origin.x;
1019                 gPoint.y = screen_rect.origin.y;
1020                 CGGetDisplaysWithPoint( gPoint, 1, &(dispSettings.displayID), &dspyCnt);
1021                 CGGetDisplayTransferByFormula(
1022                     dispSettings.displayID,
1023                     &dispSettings.redMin, &dispSettings.redMax, &dispSettings.redGamma,
1024                     &dispSettings.greenMin, &dispSettings.greenMax, &dispSettings.greenGamma,
1025                     &dispSettings.blueMin, &dispSettings.blueMax, &dispSettings.blueGamma );
1026                 CGSetDisplayTransferByFormula(
1027                     dispSettings.displayID,
1028                     dispSettings.redMin,   0, dispSettings.redGamma,
1029                     dispSettings.greenMin, 0, dispSettings.greenGamma,
1030                     dispSettings.blueMin,  0, dispSettings.blueGamma );
1031             }
1032         }
1033         if( b_menubar_screen )
1034         {
1035             SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1036         }
1037         if( b_black == VLC_TRUE )
1038         {
1039             CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
1040             CGDisplayFade( token, 2 , kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, false );
1041             CGReleaseDisplayFadeReservation( token);
1042         }
1043     }
1044     else if( var_GetBool( p_real_vout, "macosx-background" ) )
1045     {
1046         NSRect screen_rect = [o_screen frame];
1047         screen_rect.origin.x = screen_rect.origin.y = 0;
1048
1049         /* Creates a window with size: screen_rect on o_screen */
1050         [self initWithContentRect: screen_rect
1051               styleMask: NSBorderlessWindowMask
1052               backing: NSBackingStoreBuffered
1053               defer: YES screen: o_screen];
1054
1055         [self setLevel: CGWindowLevelForKey(kCGDesktopWindowLevelKey)];
1056     }
1057     else
1058     {
1059         unsigned int i_stylemask = NSTitledWindowMask |
1060                                    NSMiniaturizableWindowMask |
1061                                    NSClosableWindowMask |
1062                                    NSResizableWindowMask;
1063
1064         NSRect s_rect;
1065         if( !s_frame )
1066         {
1067             s_rect.size.width  = p_vout->i_window_width;
1068             s_rect.size.height = p_vout->i_window_height;
1069         }
1070         else
1071         {
1072             s_rect = *s_frame;
1073         }
1074
1075         [self initWithContentRect: s_rect
1076               styleMask: i_stylemask
1077               backing: NSBackingStoreBuffered
1078               defer: YES screen: o_screen];
1079
1080         [self setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
1081
1082         if( !s_frame )
1083         {
1084             [self center];
1085         }
1086     }
1087
1088     [self makeKeyAndOrderFront: nil];
1089     [self setReleasedWhenClosed: YES];
1090
1091     /* We'll catch mouse events */
1092     [self makeFirstResponder: o_view];
1093
1094     /* Add the view. It's automatically resized to fit the window */
1095     [self setContentView: o_view];
1096
1097     [o_pool release];
1098
1099     b_init_ok = VLC_TRUE;
1100     return self;
1101 }
1102
1103 - (void)close
1104 {
1105     [o_view closeVout];
1106 }
1107
1108 - (void) closeWindow
1109 {
1110     /* XXX waitUntilDone = NO to avoid a possible deadlock when hitting
1111        Command-Q */
1112     [self setContentView: NULL];
1113     [self performSelectorOnMainThread: @selector(closeReal:)
1114         withObject: NULL waitUntilDone: NO];
1115 }
1116
1117 - (id) closeReal: (id) sender
1118 {
1119     if( b_black == VLC_TRUE )
1120     {
1121         CGDisplayFadeReservationToken token;
1122         CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token);
1123         CGDisplayFade( token, 2, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0, 0, 0, false );
1124         CGReleaseDisplayFadeReservation( token);
1125         CGDisplayRestoreColorSyncSettings();
1126     }
1127     SetSystemUIMode( kUIModeNormal, 0);
1128     [super close];
1129     return NULL;
1130 }
1131
1132 - (id)getVoutView
1133 {
1134     return o_view;
1135 }
1136
1137 - (BOOL)canBecomeKeyWindow
1138 {
1139     return YES;
1140 }
1141
1142 /* Sometimes crashes VLC....
1143 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
1144 {
1145         return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event];
1146 }*/
1147
1148 /* This is actually the same as VLCControls::stop. */
1149
1150 - (BOOL)windowShouldClose:(id)sender
1151 {
1152     playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1153                                                        FIND_ANYWHERE );
1154     if( p_playlist == NULL )
1155     {
1156         return NO;
1157     }
1158
1159     playlist_Stop( p_playlist );
1160     vlc_object_release( p_playlist );
1161
1162     /* The window will be closed by the intf later. */
1163     return NO;
1164 }
1165
1166
1167 @end