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