]> git.sesse.net Git - vlc/blob - modules/gui/macosx/vout.m
* Apply changed made to the 0.8.5 branch to trunk.
[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., 59 Temple Place - Suite 330, Boston, MA  02111, 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)setOnTop:(BOOL)b_on_top
252 {
253     if( b_on_top )
254     {
255         [o_window setLevel: NSStatusWindowLevel];
256     }
257     else
258     {
259         [o_window setLevel: NSNormalWindowLevel];
260     }
261 }
262
263 - (void)scaleWindowWithFactor: (float)factor
264 {
265     NSSize newsize;
266     int i_corrected_height, i_corrected_width;
267     NSPoint topleftbase;
268     NSPoint topleftscreen;
269
270     if ( !p_vout->b_fullscreen )
271     {
272         NSRect new_frame;
273         topleftbase.x = 0;
274         topleftbase.y = [o_window frame].size.height;
275         topleftscreen = [o_window convertBaseToScreen: topleftbase];
276
277         if( p_vout->render.i_height * p_vout->render.i_aspect >
278                         p_vout->render.i_width * VOUT_ASPECT_FACTOR )
279         {
280             i_corrected_width = p_vout->render.i_height * p_vout->render.i_aspect /
281                                             VOUT_ASPECT_FACTOR;
282             newsize.width = (int) ( i_corrected_width * factor );
283             newsize.height = (int) ( p_vout->render.i_height * factor );
284         }
285         else
286         {
287             i_corrected_height = p_vout->render.i_width * VOUT_ASPECT_FACTOR /
288                                             p_vout->render.i_aspect;
289             newsize.width = (int) ( p_vout->render.i_width * factor );
290             newsize.height = (int) ( i_corrected_height * factor );
291         }
292
293         /* Calculate the window's new size */
294         new_frame.size.width = [o_window frame].size.width -
295                                     [self frame].size.width + newsize.width;
296         new_frame.size.height = [o_window frame].size.height -
297                                     [self frame].size.height + newsize.height;
298
299         new_frame.origin.x = topleftscreen.x;
300         new_frame.origin.y = topleftscreen.y - new_frame.size.height;
301
302         [o_window setFrame: new_frame display: YES];
303
304         p_vout->i_changes |= VOUT_SIZE_CHANGE;
305     }
306 }
307
308 - (void)toggleFloatOnTop
309 {
310     vlc_value_t val;
311
312     if( var_Get( p_real_vout, "video-on-top", &val )>=0 && val.b_bool)
313     {
314         val.b_bool = VLC_FALSE;
315     }
316     else
317     {
318         val.b_bool = VLC_TRUE;
319     }
320     var_Set( p_real_vout, "video-on-top", val );
321 }
322
323 - (void)toggleFullscreen
324 {
325     vlc_value_t val;
326     var_Get( p_real_vout, "fullscreen", &val );
327     val.b_bool = !val.b_bool;
328     var_Set( p_real_vout, "fullscreen", val );
329 }
330
331 - (BOOL)isFullscreen
332 {
333     vlc_value_t val;
334     var_Get( p_real_vout, "fullscreen", &val );
335     return( val.b_bool );
336 }
337
338 - (void)snapshot
339 {
340     vout_Control( p_real_vout, VOUT_SNAPSHOT );
341 }
342
343 - (void)manage
344 {
345     /* Disable Screensaver */
346     UpdateSystemActivity( UsrActivity );
347 }
348
349 - (id)getWindow
350 {
351     return o_window;
352 }
353
354 - (void)keyDown:(NSEvent *)o_event
355 {
356     unichar key = 0;
357     vlc_value_t val;
358     unsigned int i_pressed_modifiers = 0;
359     val.i_int = 0;
360
361     i_pressed_modifiers = [o_event modifierFlags];
362
363     if( i_pressed_modifiers & NSShiftKeyMask )
364         val.i_int |= KEY_MODIFIER_SHIFT;
365     if( i_pressed_modifiers & NSControlKeyMask )
366         val.i_int |= KEY_MODIFIER_CTRL;
367     if( i_pressed_modifiers & NSAlternateKeyMask )
368         val.i_int |= KEY_MODIFIER_ALT;
369     if( i_pressed_modifiers & NSCommandKeyMask )
370         val.i_int |= KEY_MODIFIER_COMMAND;
371
372     key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
373
374     if( key )
375     {
376         /* Escape should always get you out of fullscreen */
377         if( key == (unichar) 0x1b )
378         {
379              if( [self isFullscreen] )
380              {
381                  [self toggleFullscreen];
382              }
383         }
384         else if ( key == ' ' )
385         {
386             vlc_value_t val;
387             val.i_int = config_GetInt( p_vout, "key-play-pause" );
388             var_Set( p_vout->p_vlc, "key-pressed", val );
389         }
390         else
391         {
392             val.i_int |= CocoaKeyToVLC( key );
393             var_Set( p_vout->p_vlc, "key-pressed", val );
394         }
395     }
396     else
397     {
398         [super keyDown: o_event];
399     }
400 }
401
402 - (void)mouseDown:(NSEvent *)o_event
403 {
404     vlc_value_t val;
405
406     if( p_vout )
407     {
408         switch( [o_event type] )
409         {
410             case NSLeftMouseDown:
411             {
412                 var_Get( p_vout, "mouse-button-down", &val );
413                 val.i_int |= 1;
414                 var_Set( p_vout, "mouse-button-down", val );
415             }
416             break;
417
418             default:
419                 [super mouseDown: o_event];
420             break;
421         }
422     }
423 }
424
425 - (void)otherMouseDown:(NSEvent *)o_event
426 {
427     vlc_value_t val;
428
429     if( p_vout )
430     {
431         switch( [o_event type] )
432         {
433             case NSOtherMouseDown:
434             {
435                 var_Get( p_vout, "mouse-button-down", &val );
436                 val.i_int |= 2;
437                 var_Set( p_vout, "mouse-button-down", val );
438             }
439             break;
440
441             default:
442                 [super mouseDown: o_event];
443             break;
444         }
445     }
446 }
447
448 - (void)rightMouseDown:(NSEvent *)o_event
449 {
450     vlc_value_t val;
451
452     if( p_vout )
453     {
454         switch( [o_event type] )
455         {
456             case NSRightMouseDown:
457             {
458                 var_Get( p_vout, "mouse-button-down", &val );
459                 val.i_int |= 4;
460                 var_Set( p_vout, "mouse-button-down", val );
461             }
462             break;
463
464             default:
465                 [super mouseDown: o_event];
466             break;
467         }
468     }
469 }
470
471 - (void)mouseUp:(NSEvent *)o_event
472 {
473     vlc_value_t val;
474
475     if( p_vout )
476     {
477         switch( [o_event type] )
478         {
479             case NSLeftMouseUp:
480             {
481                 vlc_value_t b_val;
482                 b_val.b_bool = VLC_TRUE;
483                 var_Set( p_vout, "mouse-clicked", b_val );
484
485                 var_Get( p_vout, "mouse-button-down", &val );
486                 val.i_int &= ~1;
487                 var_Set( p_vout, "mouse-button-down", val );
488             }
489             break;
490
491             default:
492                 [super mouseUp: o_event];
493             break;
494         }
495     }
496 }
497
498 - (void)otherMouseUp:(NSEvent *)o_event
499 {
500     vlc_value_t val;
501
502     if( p_vout )
503     {
504         switch( [o_event type] )
505         {
506             case NSOtherMouseUp:
507             {
508                 var_Get( p_vout, "mouse-button-down", &val );
509                 val.i_int &= ~2;
510                 var_Set( p_vout, "mouse-button-down", val );
511             }
512             break;
513
514             default:
515                 [super mouseUp: o_event];
516             break;
517         }
518     }
519 }
520
521 - (void)rightMouseUp:(NSEvent *)o_event
522 {
523     vlc_value_t val;
524
525     if( p_vout )
526     {
527         switch( [o_event type] )
528         {
529             case NSRightMouseUp:
530             {
531                 var_Get( p_vout, "mouse-button-down", &val );
532                 val.i_int &= ~4;
533                 var_Set( p_vout, "mouse-button-down", val );
534             }
535             break;
536
537             default:
538                 [super mouseUp: o_event];
539             break;
540         }
541     }
542 }
543
544 - (void)mouseDragged:(NSEvent *)o_event
545 {
546     [self mouseMoved: o_event];
547 }
548
549 - (void)otherMouseDragged:(NSEvent *)o_event
550 {
551     [self mouseMoved: o_event];
552 }
553
554 - (void)rightMouseDragged:(NSEvent *)o_event
555 {
556     [self mouseMoved: o_event];
557 }
558
559 - (void)mouseMoved:(NSEvent *)o_event
560 {
561     NSPoint ml;
562     NSRect s_rect;
563     BOOL b_inside;
564
565     if( p_vout )
566     {
567         s_rect = [o_view bounds];
568         ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
569         b_inside = [o_view mouse: ml inRect: s_rect];
570
571         if( b_inside )
572         {
573             vlc_value_t val;
574             unsigned int i_width, i_height, i_x, i_y;
575
576             vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
577                                        (unsigned int)s_rect.size.height,
578                                        &i_x, &i_y, &i_width, &i_height );
579
580             val.i_int = ( ((int)ml.x) - i_x ) *
581                         p_vout->render.i_width / i_width;
582             var_Set( p_vout, "mouse-x", val );
583
584             if( [[o_view className] isEqualToString: @"VLCGLView"] )
585             {
586                 val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
587                             p_vout->render.i_height / i_height;
588             }
589             else
590             {
591                 val.i_int = ( ((int)ml.y) - i_y ) *
592                             p_vout->render.i_height / i_height;
593             }
594             var_Set( p_vout, "mouse-y", val );
595
596             val.b_bool = VLC_TRUE;
597             var_Set( p_vout, "mouse-moved", val );
598         }
599     }
600     [super mouseMoved: o_event];
601 }
602
603 - (BOOL)acceptsFirstResponder
604 {
605     return YES;
606 }
607
608 - (BOOL)becomeFirstResponder
609 {
610     return YES;
611 }
612
613 - (BOOL)resignFirstResponder
614 {
615     /* We need to stay the first responder or we'll miss some
616        events */
617     return NO;
618 }
619
620 /* Class methods used by the different vout modules */
621
622 + (vout_thread_t *)getRealVout: (vout_thread_t *)p_vout
623 {
624     /* p_real_vout: the vout we have to use to check for video-on-top
625        and a few other things. If we are the QuickTime output, it's us.
626        It we are the OpenGL provider, it is our parent. */
627     if( p_vout->i_object_type == VLC_OBJECT_OPENGL )
628     {
629         return (vout_thread_t *) p_vout->p_parent;
630     }
631     else
632     {
633         return p_vout;
634     }
635
636 }
637
638 + (id)getVoutView: (vout_thread_t *)p_vout subView: (NSView *)view
639                                     frame: (NSRect *)s_frame
640 {
641     vlc_value_t value_drawable;
642     int i_timeout;
643     id o_return = nil;
644     vout_thread_t * p_real_vout = [VLCVoutView getRealVout: p_vout];
645
646     var_Get( p_vout->p_vlc, "drawable", &value_drawable );
647
648     var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
649     var_Create( p_vout, "macosx-fill", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
650     var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
651     var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
652     var_Create( p_vout, "macosx-background", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
653
654
655     /* We only wait for NSApp to initialise if we're not embedded (as in the
656      * case of the Mozilla plugin).  We can tell whether we're embedded or not
657      * by examining the "drawable" value: if it's zero, we're running in the
658      * main Mac intf; if it's non-zero, we're embedded. */
659     if( value_drawable.i_int == 0 )
660     {
661         /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
662         for( i_timeout = 20 ; i_timeout-- ; )
663         {
664             if( NSApp == NULL )
665             {
666                 msleep( INTF_IDLE_SLEEP );
667             }
668         }
669
670         if( NSApp == NULL )
671         {
672             /* No MacOS X intf, unable to communicate with MT */
673             msg_Err( p_vout, "no MacOS X interface present" );
674             return nil;
675         }
676         else
677         {
678             if ( VLCIntf && !(p_vout->b_fullscreen) &&
679                         !(var_GetBool( p_real_vout, "macosx-background" )) )
680             {
681                 o_return = [[[VLCMain sharedInstance] getEmbeddedList]
682                                                             getEmbeddedVout];
683             }
684         }
685     }
686
687     /* No embedded vout is available */
688     if( o_return == nil )
689     {
690         NSRect null_rect;
691         bzero( &null_rect, sizeof( NSRect ) );
692         o_return = [[VLCDetachedVoutView alloc] initWithFrame: null_rect ];
693     }
694     [o_return setVout: p_vout subView: view frame: s_frame];
695     return o_return;
696 }
697
698 @end
699
700 /*****************************************************************************
701  * VLCDetachedVoutView implementation
702  *****************************************************************************/
703 @implementation VLCDetachedVoutView
704
705 - (id)initWithFrame: (NSRect)frameRect
706 {
707     [super initWithFrame: frameRect];
708     i_time_mouse_last_moved = 0;
709     return self;
710 }
711
712 - (bool)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
713                      frame: (NSRect *) s_arg_frame
714 {
715     BOOL b_return = [super setVout: p_arg_vout subView: view frame:s_arg_frame];
716     i_time_mouse_last_moved = mdate();
717     o_window = [[VLCWindow alloc] initWithVout: p_arg_vout view: self
718                                                     frame: s_arg_frame];
719     [view setFrame: [self frame]];
720     [o_window setAcceptsMouseMovedEvents: TRUE];
721     return b_return;
722 }
723
724 - (void)closeVout
725 {
726     [o_window closeWindow];
727     [o_window setAcceptsMouseMovedEvents: NO];
728     i_time_mouse_last_moved = 0;
729     [super closeVout];
730 }
731
732 - (void)mouseMoved:(NSEvent *)o_event
733 {
734     i_time_mouse_last_moved = mdate();
735     [super mouseMoved: o_event];
736 }
737
738 - (void)hideMouse:(BOOL)b_hide
739 {
740     BOOL b_inside;
741     NSPoint ml;
742     NSView *o_contents = [o_window contentView];
743
744     ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
745     ml = [o_contents convertPoint:ml fromView:nil];
746     b_inside = [o_contents mouse: ml inRect: [o_contents bounds]];
747
748     if( b_hide && b_inside )
749     {
750         [NSCursor setHiddenUntilMouseMoves: YES];
751     }
752     else if( !b_hide )
753     {
754         [NSCursor setHiddenUntilMouseMoves: NO];
755     }
756 }
757
758 - (void)manage
759 {
760     [super manage];
761     if( p_vout->b_fullscreen )
762     {
763         if( mdate() - i_time_mouse_last_moved > 3000000 )
764         {
765             [self hideMouse: YES];
766         }
767     }
768     else
769     {
770         [self hideMouse: NO];
771     }
772 }
773
774 @end
775
776 /*****************************************************************************
777  * VLCEmbeddedVoutView implementation
778  *****************************************************************************/
779
780 @implementation VLCEmbeddedVoutView
781
782 - (id)initWithFrame: (NSRect)frameRect
783 {
784     [super initWithFrame: frameRect];
785     b_used = NO;
786     [[[VLCMain sharedInstance] getEmbeddedList] addEmbeddedVout: self];
787     return self;
788 }
789
790 - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
791                      frame: (NSRect *) s_arg_frame
792
793 {
794     BOOL b_return;
795     b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame];
796     if( b_return )
797     {
798         o_window = [self window];
799         [o_window makeKeyAndOrderFront: self];
800         [o_window setAcceptsMouseMovedEvents: TRUE];
801         [view setFrameSize: [self frame].size];
802     }
803     return b_return;
804 }
805
806 - (void)setUsed: (BOOL)b_new_used
807 {
808     b_used = b_new_used;
809 }
810
811 - (BOOL)isUsed
812 {
813     return b_used;
814 }
815
816 - (void)closeVout
817 {
818     [super closeVout];
819     [o_window setAcceptsMouseMovedEvents: NO];
820     [[[VLCMain sharedInstance] getEmbeddedList] releaseEmbeddedVout: self];
821 }
822
823
824 @end
825
826
827 /*****************************************************************************
828  * VLCWindow implementation
829  *****************************************************************************/
830 @implementation VLCWindow
831
832 - (id) initWithVout: (vout_thread_t *) vout view: (VLCVoutView *) view
833                      frame: (NSRect *) frame
834 {
835     p_vout  = vout;
836     o_view  = view;
837     s_frame = frame;
838
839     [self performSelectorOnMainThread: @selector(initReal:)
840         withObject: NULL waitUntilDone: YES];
841
842     if( !b_init_ok )
843     {
844         return NULL;
845     }
846
847     return self;
848 }
849
850 - (id) initReal: (id) sender
851 {
852     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
853     NSArray *o_screens = [NSScreen screens];
854     NSScreen *o_screen;
855     vlc_bool_t b_menubar_screen = VLC_FALSE;
856     int i_device;
857
858     b_init_ok = VLC_FALSE;
859
860     p_fullscreen_state = NULL;
861
862     p_real_vout = [VLCVoutView getRealVout: p_vout];
863     i_device = var_GetInteger( p_real_vout->p_vlc, "video-device" );
864
865     /* Find out on which screen to open the window */
866     if( i_device <= 0 || i_device > (int)[o_screens count] )
867     {
868          /* No preference specified. Use the main screen */
869         o_screen = [NSScreen mainScreen];
870         if( o_screen == [o_screens objectAtIndex: 0] )
871             b_menubar_screen = VLC_TRUE;
872     }
873     else
874     {
875         i_device--;
876         o_screen = [o_screens objectAtIndex: i_device];
877         b_menubar_screen = ( i_device == 0 );
878     }
879
880     if( p_vout->b_fullscreen )
881     {
882         NSRect screen_rect = [o_screen frame];
883         screen_rect.origin.x = screen_rect.origin.y = 0;
884
885         /* Creates a window with size: screen_rect on o_screen */
886         [self initWithContentRect: screen_rect
887               styleMask: NSBorderlessWindowMask
888               backing: NSBackingStoreBuffered
889               defer: YES screen: o_screen];
890
891         if( b_menubar_screen )
892         {
893             BeginFullScreen( &p_fullscreen_state, NULL, 0, 0,
894                              NULL, NULL, fullScreenAllowEvents );
895         }
896     }
897     else if( var_GetBool( p_real_vout, "macosx-background" ) )
898     {
899         NSRect screen_rect = [o_screen frame];
900         screen_rect.origin.x = screen_rect.origin.y = 0;
901
902         /* Creates a window with size: screen_rect on o_screen */
903         [self initWithContentRect: screen_rect
904               styleMask: NSBorderlessWindowMask
905               backing: NSBackingStoreBuffered
906               defer: YES screen: o_screen];
907
908         [self setLevel: CGWindowLevelForKey(kCGDesktopWindowLevelKey)];
909     }
910     else
911     {
912         unsigned int i_stylemask = NSTitledWindowMask |
913                                    NSMiniaturizableWindowMask |
914                                    NSClosableWindowMask |
915                                    NSResizableWindowMask;
916
917         NSRect s_rect;
918         if( !s_frame )
919         {
920             s_rect.size.width  = p_vout->i_window_width;
921             s_rect.size.height = p_vout->i_window_height;
922         }
923         else
924         {
925             s_rect = *s_frame;
926         }
927
928         [self initWithContentRect: s_rect
929               styleMask: i_stylemask
930               backing: NSBackingStoreBuffered
931               defer: YES screen: o_screen];
932
933         [self setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
934
935         if( var_GetBool( p_real_vout, "video-on-top" ) )
936         {
937             [self setLevel: NSStatusWindowLevel];
938         }
939
940         if( !s_frame )
941         {
942             [self center];
943         }
944     }
945
946     [self updateTitle];
947     [self makeKeyAndOrderFront: nil];
948     [self setReleasedWhenClosed: YES];
949
950     /* We'll catch mouse events */
951     [self makeFirstResponder: o_view];
952
953     /* Add the view. It's automatically resized to fit the window */
954     [self setContentView: o_view];
955
956     [o_pool release];
957
958     b_init_ok = VLC_TRUE;
959     return self;
960 }
961
962 - (void)close
963 {
964     [o_view closeVout];
965 }
966
967 - (void) closeWindow
968 {
969     /* XXX waitUntilDone = NO to avoid a possible deadlock when hitting
970        Command-Q */
971     [self setContentView: NULL];
972     [self performSelectorOnMainThread: @selector(closeReal:)
973         withObject: NULL waitUntilDone: NO];
974 }
975
976 - (id) closeReal: (id) sender
977 {
978     [super close];
979     if( p_fullscreen_state )
980     {
981         EndFullScreen( p_fullscreen_state, 0 );
982     }
983     return NULL;
984 }
985
986 - (id)getVoutView
987 {
988     return o_view;
989 }
990
991 - (BOOL)canBecomeKeyWindow
992 {
993     return YES;
994 }
995
996 /* Sometimes crashes VLC....
997 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
998 {
999         return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event];
1000 }*/
1001
1002 /* This is actually the same as VLCControls::stop. */
1003
1004 - (void)updateTitle /*not modified yey ! */
1005 {
1006     NSMutableString * o_title = NULL, * o_mrl = NULL;
1007     input_thread_t * p_input;
1008
1009     if( p_vout == NULL )
1010     {
1011         return;
1012     }
1013
1014     p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT );
1015
1016     if( p_input == NULL )
1017     {
1018         return;
1019     }
1020
1021     if( p_input->input.p_item->psz_name != NULL )
1022         o_title = [NSMutableString stringWithUTF8String:
1023             p_input->input.p_item->psz_name];
1024     if( p_input->input.p_item->psz_uri != NULL )
1025         o_mrl = [NSMutableString stringWithUTF8String:
1026             p_input->input.p_item->psz_uri];
1027     if( o_title == nil )
1028         o_title = o_mrl;
1029
1030     if( o_mrl != nil )
1031     {
1032         if( p_input->input.p_access && !strcmp( p_input->input.p_access->p_module->psz_shortname, "File" ) )
1033         {
1034             NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
1035             if( prefix_range.location != NSNotFound )
1036                 [o_mrl deleteCharactersInRange: prefix_range];
1037             [self setRepresentedFilename: o_mrl];
1038         }
1039         [self setTitle: o_title];
1040     }
1041     else
1042     {
1043         [self setTitle: [NSString stringWithCString: VOUT_TITLE]];
1044     }
1045     vlc_object_release( p_input );
1046 }
1047
1048 - (BOOL)windowShouldClose:(id)sender
1049 {
1050     playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1051                                                        FIND_ANYWHERE );
1052     if( p_playlist == NULL )
1053     {
1054         return NO;
1055     }
1056
1057     playlist_Stop( p_playlist );
1058     vlc_object_release( p_playlist );
1059
1060     /* The window will be closed by the intf later. */
1061     return NO;
1062 }
1063
1064
1065 @end