vout.m
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:32k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * vout.m: MacOS X video output module
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2009 the VideoLAN team
  5.  * $Id: 94548d3e40488c013a3983217762d504a015a3fc $
  6.  *
  7.  * Authors: Colin Delacroix <colin@zoy.org>
  8.  *          Florian G. Pflug <fgp@phlo.org>
  9.  *          Jon Lech Johansen <jon-vl@nanocrew.net>
  10.  *          Derk-Jan Hartman <hartman at videolan dot org>
  11.  *          Eric Petit <titer@m0k.org>
  12.  *          Benjamin Pracht <bigben at videolan dot org>
  13.  *          Felix Paul Kühne <fkuehne at videolan dot org>
  14.  *
  15.  * This program is free software; you can redistribute it and/or modify
  16.  * it under the terms of the GNU General Public License as published by
  17.  * the Free Software Foundation; either version 2 of the License, or
  18.  * (at your option) any later version.
  19.  *
  20.  * This program is distributed in the hope that it will be useful,
  21.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.  * GNU General Public License for more details.
  24.  *
  25.  * You should have received a copy of the GNU General Public License
  26.  * along with this program; if not, write to the Free Software
  27.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  28.  *****************************************************************************/
  29. /*****************************************************************************
  30.  * Preamble
  31.  *****************************************************************************/
  32. #include <errno.h>                                                 /* ENOMEM */
  33. #include <stdlib.h>                                                /* free() */
  34. #include <string.h>
  35. /* prevent system sleep */
  36. #import <CoreServices/CoreServices.h>
  37. /* FIXME: HACK!! */
  38. #ifdef __x86_64__
  39. #import <CoreServices/../Frameworks/OSServices.framework/Headers/Power.h>
  40. #endif
  41. /* SystemUIMode */
  42. #import <Carbon/Carbon.h>
  43. #include <vlc_keys.h>
  44. #include "intf.h"
  45. #include "fspanel.h"
  46. #include "vout.h"
  47. #import "controls.h"
  48. #import "embeddedwindow.h"
  49. /*****************************************************************************
  50.  * DeviceCallback: Callback triggered when the video-device variable is changed
  51.  *****************************************************************************/
  52. int DeviceCallback( vlc_object_t *p_this, const char *psz_variable,
  53.                      vlc_value_t old_val, vlc_value_t new_val, void *param )
  54. {
  55.     vlc_value_t val;
  56.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  57.     msg_Dbg( p_vout, "set %d", new_val.i_int );
  58.     var_Create( p_vout->p_libvlc, "video-device", VLC_VAR_INTEGER );
  59.     var_Set( p_vout->p_libvlc, "video-device", new_val );
  60.     val.b_bool = true;
  61.     var_Set( p_vout, "intf-change", val );
  62.     return VLC_SUCCESS;
  63. }
  64. /*****************************************************************************
  65.  * VLCEmbeddedList implementation
  66.  *****************************************************************************/
  67. @implementation VLCEmbeddedList
  68. - (id)init
  69. {
  70.     [super init];
  71.     o_embedded_array = [NSMutableArray array];
  72.     return self;
  73. }
  74. - (id)embeddedVout
  75. {
  76.     unsigned int i;
  77.     for( i = 0; i < [o_embedded_array count]; i++ )
  78.     {
  79.         id o_vout_view = [o_embedded_array objectAtIndex: i];
  80.         if( ![o_vout_view isUsed] )
  81.         {
  82.             [o_vout_view setUsed: YES];
  83.             return o_vout_view;
  84.         }
  85.     }
  86.     return nil;
  87. }
  88. - (void)releaseEmbeddedVout: (id)o_vout_view
  89. {
  90.     if( [o_embedded_array containsObject: o_vout_view] )
  91.     {
  92.         [o_vout_view setUsed: NO];
  93.     }
  94.     else
  95.     {
  96.         msg_Warn( VLCIntf, "cannot find Video Output");
  97.     }
  98. }
  99. - (void)addEmbeddedVout: (id)o_vout_view
  100. {
  101.     if( ![o_embedded_array containsObject: o_vout_view] )
  102.     {
  103.         [o_embedded_array addObject: o_vout_view];
  104.     }
  105. }
  106. - (BOOL)windowContainsEmbedded: (id)o_window
  107. {
  108. /*    if( ![[o_window className] isEqualToString: @"VLCVoutWindow"] )
  109.     {
  110.         NSLog( @"We were not given a VLCVoutWindow" );
  111.     }*/
  112.     return ([self viewForWindow: o_window] == nil ? NO : YES );
  113. }
  114. - (id)viewForWindow: (id)o_window
  115. {
  116.     if( o_embedded_array != nil )
  117.     {
  118.         id o_enumerator = [o_embedded_array objectEnumerator];
  119.         id o_current_embedded;
  120.         if( o_window != nil )
  121.         {
  122.             while( (o_current_embedded = [o_enumerator nextObject]) )
  123.             {
  124.                 if( [o_current_embedded voutWindow] == o_window )
  125.                 {
  126.                     return o_current_embedded;
  127.                 }
  128.             }
  129.         }
  130.     }
  131.     return nil;
  132. }
  133. @end
  134. /*****************************************************************************
  135.  * VLCVoutView implementation
  136.  *****************************************************************************/
  137. @implementation VLCVoutView
  138. - (id)initWithFrame: (NSRect)frameRect
  139. {
  140.     self = [super initWithFrame: frameRect];
  141.     p_vout = NULL;
  142.     o_view = nil;
  143.     s_frame = &frameRect;
  144.     p_real_vout = NULL;
  145.     o_window = nil;
  146.     return self;
  147. }
  148. - (BOOL)setVout: (vout_thread_t *) vout
  149.         subView: (NSView *) view
  150.           frame: (NSRect *) frame
  151. {
  152.     int i_device;
  153.     NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
  154.     NSArray *o_screens = [NSScreen screens];
  155.     p_vout  = vout;
  156.     o_view  = view;
  157.     s_frame = frame;
  158.     if( [o_screens count] <= 0 )
  159.     {
  160.         msg_Err( p_vout, "no OSX screens available" );
  161.         return NO;
  162.     }
  163.     p_real_vout = [VLCVoutView realVout: p_vout];
  164.     /* Get the pref value when this is the first time, otherwise retrieve the device from the top level video-device var */
  165.     if( var_Type( p_real_vout->p_libvlc, "video-device" ) == 0 )
  166.     {
  167.         i_device = var_GetInteger( p_vout, "macosx-vdev" );
  168.     }
  169.     else
  170.     {
  171.         i_device = var_GetInteger( p_real_vout->p_libvlc, "video-device" );
  172.     }
  173.     /* Setup the menuitem for the multiple displays. */
  174.     if( var_Type( p_real_vout, "video-device" ) == 0 )
  175.     {
  176.         int i = 1;
  177.         vlc_value_t val2, text;
  178.         NSScreen * o_screen;
  179.         var_Create( p_real_vout, "video-device", VLC_VAR_INTEGER |
  180.                                             VLC_VAR_HASCHOICE );
  181.         text.psz_string = _("Fullscreen Video Device");
  182.         var_Change( p_real_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
  183.         NSEnumerator * o_enumerator = [o_screens objectEnumerator];
  184.         val2.i_int = 0;
  185.         text.psz_string = _("Default");
  186.         var_Change( p_real_vout, "video-device",
  187.                         VLC_VAR_ADDCHOICE, &val2, &text );
  188.         var_Set( p_real_vout, "video-device", val2 );
  189.         while( (o_screen = [o_enumerator nextObject]) != NULL )
  190.         {
  191.             char psz_temp[255];
  192.             NSRect s_rect = [o_screen frame];
  193.             snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
  194.                       "%s %d (%dx%d)", _("Screen"), i,
  195.                       (int)s_rect.size.width, (int)s_rect.size.height );
  196.             text.psz_string = psz_temp;
  197.             val2.i_int = (int)[o_screen displayID];
  198.             var_Change( p_real_vout, "video-device",
  199.                         VLC_VAR_ADDCHOICE, &val2, &text );
  200.             if( (int)[o_screen displayID] == i_device )
  201.             {
  202.                 var_Set( p_real_vout, "video-device", val2 );
  203.             }
  204.             i++;
  205.         }
  206.         var_AddCallback( p_real_vout, "video-device", DeviceCallback,
  207.                          NULL );
  208.         val2.b_bool = true;
  209.         var_Set( p_real_vout, "intf-change", val2 );
  210.     }
  211.     /* Add the view. It's automatically resized to fit the window */
  212.     [self addSubview: o_view];
  213.     [self setAutoresizesSubviews: YES];
  214.     [o_pool release];
  215.     return YES;
  216. }
  217. - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize
  218. {
  219.     [super resizeSubviewsWithOldSize: oldBoundsSize];
  220.     [o_view setFrameSize: [self frame].size];
  221. }
  222. - (void)drawRect:(NSRect)rect
  223. {
  224.     /* When there is no subview we draw a black background */
  225.     [self lockFocus];
  226.     [[NSColor blackColor] set];
  227.     NSRectFill(rect);
  228.     [self unlockFocus];
  229. }
  230. - (void)closeVout
  231. {
  232.     [[[[VLCMain sharedInstance] controls] fspanel] fadeOut];
  233.     /* Make sure we don't see a white flash */
  234.     [[self voutWindow] disableScreenUpdatesUntilFlush];
  235.     [o_view removeFromSuperview];
  236.     o_view = nil;
  237.     p_vout = NULL;
  238.     s_frame = nil;
  239.     o_window = nil;
  240.     p_real_vout = NULL;
  241. }
  242. - (void)updateTitle
  243. {
  244.     NSString * o_title = nil; 
  245.     NSMutableString * o_mrl = nil;
  246.     input_thread_t * p_input;
  247.     char * psz_title;
  248.     if( !p_vout ) return;
  249.     p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT );
  250.     if( !p_input ) return;
  251.     input_item_t * p_item = input_GetItem( p_input );
  252.     psz_title = input_item_GetNowPlaying ( p_item );
  253.     if( !psz_title )
  254.         psz_title = input_item_GetName( p_item );
  255.     if( psz_title )
  256.         o_title = [NSString stringWithUTF8String: psz_title];
  257.     char *psz_uri = input_item_GetURI( p_item );
  258.     if( psz_uri )
  259.         o_mrl = [NSMutableString stringWithUTF8String: psz_uri];
  260.     free( psz_title );
  261.     free( psz_uri );
  262.     if( !o_title )
  263.         o_title = o_mrl;
  264.     if( o_mrl != nil )
  265.     {
  266.         /* FIXME once psz_access is exported, we could check if we are
  267.          * reading from a file in a smarter way. */
  268.         NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
  269.         if( prefix_range.location != NSNotFound )
  270.             [o_mrl deleteCharactersInRange: prefix_range];
  271.         if( [o_mrl characterAtIndex:0] == '/' )
  272.         {
  273.             /* it's a local file */
  274.             [o_window setRepresentedFilename: o_mrl];
  275.         }
  276.         else
  277.         {
  278.             /* it's from the network or somewhere else,
  279.              * we clear the previous path */
  280.             [o_window setRepresentedFilename: @""];
  281.         }
  282.         [o_window setTitle: o_title];
  283.     }
  284.     else
  285.     {
  286.         [o_window setTitle: [NSString stringWithUTF8String: VOUT_TITLE]];
  287.     }
  288.     vlc_object_release( p_input );
  289. }
  290. - (void)setOnTop:(BOOL)b_on_top
  291. {
  292.     if( b_on_top )
  293.     {
  294.         [o_window setLevel: NSStatusWindowLevel];
  295.     }
  296.     else
  297.     {
  298.         [o_window setLevel: NSNormalWindowLevel];
  299.     }
  300. }
  301. - (NSSize)voutSizeForFactor: (float)factor
  302. {
  303.     int i_corrected_height, i_corrected_width;
  304.     NSSize newsize;
  305.     if( p_vout->render.i_height * p_vout->render.i_aspect >
  306.                     p_vout->render.i_width * VOUT_ASPECT_FACTOR )
  307.     {
  308.         i_corrected_width = p_vout->render.i_height * p_vout->render.i_aspect /
  309.                                         VOUT_ASPECT_FACTOR;
  310.         newsize.width = (int) ( i_corrected_width * factor );
  311.         newsize.height = (int) ( p_vout->render.i_height * factor );
  312.     }
  313.     else
  314.     {
  315.         i_corrected_height = p_vout->render.i_width * VOUT_ASPECT_FACTOR /
  316.                                         p_vout->render.i_aspect;
  317.         newsize.width = (int) ( p_vout->render.i_width * factor );
  318.         newsize.height = (int) ( i_corrected_height * factor );
  319.     }
  320.     return newsize;
  321. }
  322. - (void)scaleWindowWithFactor: (float)factor animate: (BOOL)animate
  323. {
  324.     if ( !p_vout->b_fullscreen )
  325.     {
  326.         NSSize newsize;
  327.         NSPoint topleftbase;
  328.         NSPoint topleftscreen;
  329.         NSView *mainView;
  330.         NSRect new_frame;
  331.         topleftbase.x = 0;
  332.         topleftbase.y = [o_window frame].size.height;
  333.         topleftscreen = [o_window convertBaseToScreen: topleftbase];
  334.         newsize = [self voutSizeForFactor:factor];
  335.         /* In fullscreen mode we need to use a view that is different from
  336.          * ourselves, with the VLCEmbeddedWindow */
  337.         if([o_window isKindOfClass:[VLCEmbeddedWindow class]])
  338.             mainView = [o_window mainView];
  339.         else
  340.             mainView = self;
  341.         /* Calculate the window's new size */
  342.         new_frame.size.width = [o_window frame].size.width -
  343.                                     [mainView frame].size.width + newsize.width;
  344.         new_frame.size.height = [o_window frame].size.height -
  345.                                     [mainView frame].size.height + newsize.height;
  346.         new_frame.origin.x = topleftscreen.x;
  347.         new_frame.origin.y = topleftscreen.y - new_frame.size.height;
  348.         [o_window setFrame:new_frame display:animate animate:animate];
  349.         p_vout->i_changes |= VOUT_SIZE_CHANGE;
  350.     }
  351. }
  352. - (void)toggleFloatOnTop
  353. {
  354.     vlc_value_t val;
  355.     if( !p_real_vout ) return;
  356.     if( var_Get( p_real_vout, "video-on-top", &val )>=0 && val.b_bool)
  357.     {
  358.         val.b_bool = false;
  359.     }
  360.     else
  361.     {
  362.         val.b_bool = true;
  363.     }
  364.     var_Set( p_real_vout, "video-on-top", val );
  365. }
  366. - (void)toggleFullscreen
  367. {
  368.     vlc_value_t val;
  369.     if( !p_real_vout ) return;
  370.     var_Get( p_real_vout, "fullscreen", &val );
  371.     val.b_bool = !val.b_bool;
  372.     var_Set( p_real_vout, "fullscreen", val );
  373. }
  374. - (BOOL)isFullscreen
  375. {
  376.     vlc_value_t val;
  377.     if( !p_real_vout ) return NO;
  378.     var_Get( p_real_vout, "fullscreen", &val );
  379.     return( val.b_bool );
  380. }
  381. - (void)snapshot
  382. {
  383.     var_TriggerCallback( p_real_vout, "video-snapshot" );
  384. }
  385. - (void)manage
  386. {
  387.     /* Disable Screensaver, when we're playing something, but allow it on pause */
  388.     if( !VLCIntf || !VLCIntf->p_sys )
  389.         return;
  390.     if( VLCIntf->p_sys->i_play_status == PLAYING_S )
  391.         UpdateSystemActivity( UsrActivity );
  392. }
  393. - (id)voutWindow
  394. {
  395.     return o_window;
  396. }
  397. - (void)scrollWheel:(NSEvent *)theEvent
  398. {
  399.     VLCControls * o_controls = (VLCControls *)[[NSApp delegate] controls];
  400.     [o_controls scrollWheel: theEvent];
  401. }
  402. - (void)keyDown:(NSEvent *)o_event
  403. {
  404.     unichar key = 0;
  405.     vlc_value_t val;
  406.     unsigned int i_pressed_modifiers = 0;
  407.     val.i_int = 0;
  408.     i_pressed_modifiers = [o_event modifierFlags];
  409.     if( i_pressed_modifiers & NSShiftKeyMask )
  410.         val.i_int |= KEY_MODIFIER_SHIFT;
  411.     if( i_pressed_modifiers & NSControlKeyMask )
  412.         val.i_int |= KEY_MODIFIER_CTRL;
  413.     if( i_pressed_modifiers & NSAlternateKeyMask )
  414.         val.i_int |= KEY_MODIFIER_ALT;
  415.     if( i_pressed_modifiers & NSCommandKeyMask )
  416.         val.i_int |= KEY_MODIFIER_COMMAND;
  417.     key = [[[o_event charactersIgnoringModifiers] lowercaseString] characterAtIndex: 0];
  418.     if( key )
  419.     {
  420.         /* Escape should always get you out of fullscreen */
  421.         if( key == (unichar) 0x1b )
  422.         {
  423.              if( p_real_vout && [self isFullscreen] )
  424.              {
  425.                  [self toggleFullscreen];
  426.              }
  427.         }
  428.         else if ( p_vout )
  429.         {
  430.             if( key == ' ')
  431.                 val.i_int = config_GetInt( p_vout, "key-play-pause" );
  432.             else
  433.                 val.i_int |= (int)CocoaKeyToVLC( key );
  434.             var_Set( p_vout->p_libvlc, "key-pressed", val );
  435.         }
  436.         else NSLog( @"Could not send keyevent to VLC core" );
  437.     }
  438.     else
  439.         [super keyDown: o_event];
  440. }
  441. - (void)mouseDown:(NSEvent *)o_event
  442. {
  443.     vlc_value_t val;
  444.     if( p_vout )
  445.     {
  446.         if( ( [o_event type] == NSLeftMouseDown ) &&
  447.           ( ! ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
  448.         {
  449.             if( [o_event clickCount] <= 1 )
  450.             {
  451.                 /* single clicking */
  452.                 var_Get( p_vout, "mouse-button-down", &val );
  453.                 val.i_int |= 1;
  454.                 var_Set( p_vout, "mouse-button-down", val );
  455.             }
  456.             else
  457.             {
  458.                 /* multiple clicking */
  459.                 [self toggleFullscreen];
  460.             }
  461.         }
  462.         else if( ( [o_event type] == NSRightMouseDown ) ||
  463.                ( ( [o_event type] == NSLeftMouseDown ) &&
  464.                  ( [o_event modifierFlags] &  NSControlKeyMask ) ) )
  465.         {
  466.             msg_Dbg( p_vout, "received NSRightMouseDown (generic method) or Ctrl clic" );
  467.             [NSMenu popUpContextMenu: [[VLCMain sharedInstance] voutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] controls] voutView]];
  468.         }
  469.     }
  470.     [super mouseDown: o_event];
  471. }
  472. - (void)otherMouseDown:(NSEvent *)o_event
  473. {
  474.     vlc_value_t val;
  475.     if( p_vout && [o_event type] == NSOtherMouseDown )
  476.     {
  477.         var_Get( p_vout, "mouse-button-down", &val );
  478.         val.i_int |= 2;
  479.         var_Set( p_vout, "mouse-button-down", val );
  480.     }
  481.     [super mouseDown: o_event];
  482. }
  483. - (void)rightMouseDown:(NSEvent *)o_event
  484. {
  485.     if( p_vout && [o_event type] == NSRightMouseDown )
  486.     {
  487.         msg_Dbg( p_vout, "received NSRightMouseDown (specific method)" );
  488.         [NSMenu popUpContextMenu: [[VLCMain sharedInstance] voutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] controls] voutView]];
  489.     }
  490.     [super mouseDown: o_event];
  491. }
  492. - (void)mouseUp:(NSEvent *)o_event
  493. {
  494.     vlc_value_t val;
  495.     if( p_vout && [o_event type] == NSLeftMouseUp )
  496.     {
  497.         var_SetBool( p_vout, "mouse-clicked", true );
  498.         var_Get( p_vout, "mouse-button-down", &val );
  499.         val.i_int &= ~1;
  500.         var_Set( p_vout, "mouse-button-down", val );
  501.     }
  502.     [super mouseUp: o_event];
  503. }
  504. - (void)otherMouseUp:(NSEvent *)o_event
  505. {
  506.     vlc_value_t val;
  507.     if( p_vout && [o_event type] == NSOtherMouseUp )
  508.     {
  509.         var_Get( p_vout, "mouse-button-down", &val );
  510.         val.i_int &= ~2;
  511.         var_Set( p_vout, "mouse-button-down", val );
  512.     }
  513.     [super mouseUp: o_event];
  514. }
  515. - (void)rightMouseUp:(NSEvent *)o_event
  516. {
  517.     if( p_vout && [o_event type] == NSRightMouseUp )
  518.     {
  519.         /* FIXME: this isn't the appropriate place, but we can't receive
  520.          * NSRightMouseDown some how */
  521.         msg_Dbg( p_vout, "received NSRightMouseUp" );
  522.         [NSMenu popUpContextMenu: [[VLCMain sharedInstance] voutMenu] withEvent: o_event forView: [[[VLCMain sharedInstance] controls] voutView]];
  523.     }
  524.     [super mouseUp: o_event];
  525. }
  526. - (void)mouseDragged:(NSEvent *)o_event
  527. {
  528.     [self mouseMoved: o_event];
  529. }
  530. - (void)otherMouseDragged:(NSEvent *)o_event
  531. {
  532.     [self mouseMoved: o_event];
  533. }
  534. - (void)rightMouseDragged:(NSEvent *)o_event
  535. {
  536.     [self mouseMoved: o_event];
  537. }
  538. - (void)mouseMoved:(NSEvent *)o_event
  539. {
  540.     NSPoint ml;
  541.     NSRect s_rect;
  542.     BOOL b_inside;
  543.     if( p_vout )
  544.     {
  545.         s_rect = [o_view bounds];
  546.         ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
  547.         b_inside = [o_view mouse: ml inRect: s_rect];
  548.         if( b_inside )
  549.         {
  550.             vlc_value_t val;
  551.             unsigned int i_width, i_height, i_x, i_y;
  552.             vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
  553.                                        (unsigned int)s_rect.size.height,
  554.                                        &i_x, &i_y, &i_width, &i_height );
  555.             val.i_int = ( ((int)ml.x) - i_x ) *
  556.                         p_vout->render.i_width / i_width;
  557.             var_Set( p_vout, "mouse-x", val );
  558.             if( [[o_view className] isEqualToString: @"VLCGLView"] )
  559.             {
  560.                 val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
  561.                             p_vout->render.i_height / i_height;
  562.             }
  563.             else
  564.             {
  565.                 val.i_int = ( ((int)ml.y) - i_y ) *
  566.                             p_vout->render.i_height / i_height;
  567.             }
  568.             var_Set( p_vout, "mouse-y", val );
  569.             val.b_bool = true;
  570.             var_Set( p_vout, "mouse-moved", val );
  571.         }
  572.         if( [self isFullscreen] )
  573.             [[[[VLCMain sharedInstance] controls] fspanel] fadeIn];
  574.     }
  575.     [super mouseMoved: o_event];
  576. }
  577. - (BOOL)acceptsFirstResponder
  578. {
  579.     return YES;
  580. }
  581. - (BOOL)becomeFirstResponder
  582. {
  583.     return YES;
  584. }
  585. - (BOOL)resignFirstResponder
  586. {
  587.     /* We need to stay the first responder or we'll miss some
  588.        events */
  589.     return NO;
  590. }
  591. /* Class methods used by the different vout modules */
  592. + (vout_thread_t *)realVout: (vout_thread_t *)p_vout
  593. {
  594.     /* p_real_vout: the vout we have to use to check for video-on-top
  595.        and a few other things. If we are the QuickTime output, it's us.
  596.        It we are the OpenGL provider, it is our parent.
  597.        Since we can't be the QuickTime output anymore, we need to be
  598.        the parent.
  599.        FIXME: check with the caca and x11 vouts! */
  600.     return (vout_thread_t *) p_vout->p_parent;
  601. }
  602. + (id)voutView: (vout_thread_t *)p_vout subView: (NSView *)view
  603.          frame: (NSRect *)s_frame
  604. {
  605.     int i_drawable_gl;
  606.     int i_timeout;
  607.     id o_return = nil;
  608.     i_drawable_gl = var_GetInteger( p_vout->p_libvlc, "drawable-gl" );
  609.     var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  610.     var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  611.     var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
  612.     var_Create( p_vout, "macosx-background", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  613.     var_Create( p_vout, "macosx-black", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  614.     var_Create( p_vout, "embedded-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  615.     /* We only wait for NSApp to initialise if we're not embedded (as in the
  616.      * case of the Mozilla plugin).  We can tell whether we're embedded or not
  617.      * by examining the "drawable-gl" value: if it's zero, we're running in the
  618.      * main Mac intf; if it's non-zero, we're embedded. */
  619.     if( i_drawable_gl == 0 )
  620.     {
  621.         /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
  622.         for( i_timeout = 20 ; i_timeout-- ; )
  623.         {
  624.             if( NSApp == NULL )
  625.             {
  626.                 msleep( INTF_IDLE_SLEEP );
  627.             }
  628.         }
  629.         if( NSApp == NULL )
  630.         {
  631.             /* No MacOS X intf, unable to communicate with MT */
  632.             msg_Err( p_vout, "no MacOS X interface present" );
  633.             return nil;
  634.         }
  635.         else
  636.         {
  637.             if ( VLCIntf && !(p_vout->b_fullscreen) &&
  638.                         !(var_GetBool( p_vout, "macosx-background" )) &&
  639.                         var_GetBool( p_vout, "embedded-video") )
  640.             {
  641.                 o_return = [[[VLCMain sharedInstance] embeddedList] embeddedVout];
  642.             }
  643.         }
  644.     }
  645.     /* No embedded vout is available */
  646.     if( o_return == nil )
  647.     {
  648.         NSRect null_rect;
  649.         bzero( &null_rect, sizeof( NSRect ) );
  650.         o_return = [[VLCDetachedVoutView alloc] initWithFrame: null_rect ];
  651.     }
  652.     [o_return setVout: p_vout subView: view frame: s_frame];
  653.     return o_return;
  654. }
  655. - (void)enterFullscreen
  656. {
  657.     /* Save the settings for next playing item */
  658.     playlist_t * p_playlist = pl_Hold( p_real_vout );
  659.     var_SetBool( p_playlist, "fullscreen", true );
  660.     pl_Release( p_real_vout );
  661. }
  662. - (void)leaveFullscreen
  663. {
  664.     /* Save the settings for next playing item */
  665.     playlist_t * p_playlist = pl_Hold( p_real_vout );
  666.     var_SetBool( p_playlist, "fullscreen", false );
  667.     pl_Release( p_real_vout );
  668. }
  669. @end
  670. /*****************************************************************************
  671.  * VLCDetachedVoutView implementation
  672.  *****************************************************************************/
  673. @implementation VLCDetachedVoutView
  674. - (id)initWithFrame: (NSRect)frameRect
  675. {
  676.     [super initWithFrame: frameRect];
  677.     i_time_mouse_last_moved = 0;
  678.     return self;
  679. }
  680. - (BOOL)mouseDownCanMoveWindow
  681. {
  682.     return YES;
  683. }
  684. - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
  685.                      frame: (NSRect *) s_arg_frame
  686. {
  687.     BOOL b_return = [super setVout: p_arg_vout subView: view frame:s_arg_frame];
  688.     i_time_mouse_last_moved = mdate();
  689.     o_window = [[VLCVoutWindow alloc] initWithVout: p_arg_vout view: self
  690.                                                     frame: s_arg_frame];
  691.     
  692.     [self updateTitle];
  693.     if([self isFullscreen])
  694.         [o_window performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: YES];
  695.     else
  696.         [view setFrame: [self frame]];
  697.     return b_return;
  698. }
  699. - (void)closeVout
  700. {
  701.     [o_window performSelectorOnMainThread: @selector(close) withObject: NULL waitUntilDone: YES];
  702.     i_time_mouse_last_moved = 0;
  703.     [super closeVout];
  704. }
  705. - (void)mouseMoved:(NSEvent *)o_event
  706. {
  707.     i_time_mouse_last_moved = mdate();
  708.     [super mouseMoved: o_event];
  709. }
  710. - (void)hideMouse:(BOOL)b_hide
  711. {
  712.     BOOL b_inside;
  713.     NSPoint ml;
  714.     NSView *o_contents = [o_window contentView];
  715.     ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
  716.     ml = [o_contents convertPoint:ml fromView:nil];
  717.     b_inside = [o_contents mouse: ml inRect: [o_contents bounds]];
  718.     if( b_hide && b_inside )
  719.     {
  720.         [NSCursor setHiddenUntilMouseMoves: YES];
  721.     }
  722.     else if( !b_hide )
  723.     {
  724.         [NSCursor setHiddenUntilMouseMoves: NO];
  725.     }
  726. }
  727. - (void)manage
  728. {
  729.     /* Dooh, why do we spend processor time doing this kind of stuff? */
  730.     [super manage];
  731.     unsigned int i_mouse_hide_timeout =
  732.         var_CreateGetInteger(p_vout, "mouse-hide-timeout") * 1000;
  733.     if( i_mouse_hide_timeout < 100000 )
  734.         i_mouse_hide_timeout = 100000;
  735.     if( p_vout->b_fullscreen )
  736.     {
  737.         if( mdate() - i_time_mouse_last_moved > i_mouse_hide_timeout )
  738.         {
  739.             i_time_mouse_last_moved = mdate();
  740.             [self hideMouse: YES];
  741.         }
  742.     }
  743.     else
  744.     {
  745.         [self hideMouse: NO];
  746.     }
  747. }
  748. - (void)enterFullscreen
  749. {
  750.     [o_window performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: NO];
  751.     [super enterFullscreen];
  752. }
  753. - (void)leaveFullscreen
  754. {
  755.     [o_window performSelectorOnMainThread: @selector(leaveFullscreen) withObject: NULL waitUntilDone: NO];
  756.     [super leaveFullscreen];
  757. }
  758. - (void)scaleWindowWithFactor: (float)factor animate: (BOOL)animate
  759. {
  760.     if( p_vout->b_fullscreen )
  761.         return;
  762.     [o_window setMovableByWindowBackground: NO];
  763.     [super scaleWindowWithFactor: factor animate: animate];
  764.     [o_window setMovableByWindowBackground: YES];
  765. }
  766. @end
  767. /*****************************************************************************
  768.  * VLCEmbeddedVoutView implementation
  769.  *****************************************************************************/
  770. @implementation VLCEmbeddedVoutView
  771. - (void)awakeFromNib
  772. {
  773.     o_embeddedwindow = [self window];
  774. }
  775. - (BOOL)mouseDownCanMoveWindow
  776. {
  777.     return YES;
  778. }
  779. - (id)initWithFrame: (NSRect)frameRect
  780. {
  781.     if(self = [super initWithFrame: frameRect])
  782.     {
  783.         b_used = NO;
  784.         [[[VLCMain sharedInstance] embeddedList] addEmbeddedVout: self];
  785.         o_embeddedwindow = nil; /* Filled later on in -awakeFromNib */
  786.     }
  787.     return self;
  788. }
  789. - (BOOL)setVout: (vout_thread_t *) p_arg_vout subView: (NSView *) view
  790.                  frame: (NSRect *)s_arg_frame
  791. {
  792.     BOOL b_return;
  793.     [NSObject cancelPreviousPerformRequestsWithTarget:o_window];
  794.     b_return = [super setVout: p_arg_vout subView: view frame: s_arg_frame];
  795.     if( b_return )
  796.     {
  797.         o_window = [self window];
  798.         [o_window setAcceptsMouseMovedEvents: TRUE];
  799.         if( var_CreateGetBool( p_real_vout, "video-on-top" ) )
  800.         {
  801.             [o_window setLevel: NSStatusWindowLevel];
  802.         }
  803.         [view setFrameSize: [self frame].size];
  804.     }
  805.     /* o_window needs to point to our o_embeddedwindow, super might have set it
  806.      * to the fullscreen window that o_embeddedwindow setups during fullscreen */
  807.     o_window = o_embeddedwindow;
  808.  
  809.     if( b_return )
  810.     {
  811.         [o_window lockFullscreenAnimation];
  812.         [o_window setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
  813.         [self updateTitle];
  814.         [NSObject cancelPreviousPerformRequestsWithTarget:o_window];
  815.         /* Make the window the front and key window before animating */
  816.         if ([o_window isVisible] && (![o_window isFullscreen]))
  817.             [o_window makeKeyAndOrderFront: self];
  818.         [self scaleWindowWithFactor: 1.0 animate: [o_window isVisible] && (![o_window isFullscreen])];
  819.         [o_embeddedwindow setVideoRatio:[self voutSizeForFactor:1.0]];
  820.         /* Make sure our window is visible, if we are not in fullscreen */
  821.         if (![o_window isFullscreen])
  822.             [o_window makeKeyAndOrderFront: self];
  823.         [o_window unlockFullscreenAnimation];
  824.     }
  825.     return b_return;
  826. }
  827. - (void)setUsed: (BOOL)b_new_used
  828. {
  829.     b_used = b_new_used;
  830. }
  831. - (BOOL)isUsed
  832. {
  833.     return b_used;
  834. }
  835. - (void)closeVout
  836. {
  837.     [super closeVout];
  838.     /* Don't close the window yet, wait a bit to see if a new input is poping up */
  839.     /* FIXME: Probably fade the window In and Out */
  840.     /* FIXME: fix core */
  841.     [o_embeddedwindow performSelector:@selector(orderOut:) withObject:nil afterDelay:3.];
  842.     [[[VLCMain sharedInstance] embeddedList] releaseEmbeddedVout: self];
  843. }
  844. - (void)enterFullscreen
  845. {
  846.     /* Save settings */
  847.     [super enterFullscreen];
  848.     /* We are in a VLCEmbeddedWindow */
  849.     [o_embeddedwindow performSelectorOnMainThread: @selector(enterFullscreen) withObject: NULL waitUntilDone: YES];
  850. }
  851. - (void)leaveFullscreen
  852. {
  853.     /* Save settings */
  854.     [super leaveFullscreen];
  855.     /* We are in a VLCEmbeddedWindow */
  856.     [o_embeddedwindow performSelectorOnMainThread: @selector(leaveFullscreen) withObject: NULL waitUntilDone: YES];
  857. }
  858. @end
  859. /*****************************************************************************
  860.  * VLCVoutWindow implementation
  861.  *****************************************************************************/
  862. @implementation VLCVoutWindow
  863. - (id) initWithVout: (vout_thread_t *) vout view: (VLCVoutView *) view
  864.                      frame: (NSRect *) frame
  865. {
  866.     p_vout  = vout;
  867.     o_view  = view;
  868.     s_frame = frame;
  869.     b_init_ok = NO;
  870.     [self performSelectorOnMainThread: @selector(initMainThread:)
  871.         withObject: NULL waitUntilDone: YES];
  872.     return b_init_ok ? self : nil;
  873. }
  874. - (id)initMainThread: (id) sender
  875. {
  876.     NSRect rect;
  877.     rect.size.height = p_vout->i_window_height;
  878.     rect.size.width  = p_vout->i_window_width;
  879.     rect.origin.x = rect.origin.y = 70.;
  880.     if( self = [super initWithContentRect:rect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO])
  881.     {
  882.         [self setBackgroundColor:[NSColor blackColor]];
  883.         [self setHasShadow:YES];
  884.         [self setMovableByWindowBackground: YES];
  885.         [self center];
  886.         [self makeKeyAndOrderFront: self];
  887.         [self setReleasedWhenClosed: YES];
  888.         [self setFrameUsingName:@"VLCVoutWindowDetached"];
  889.         [self setFrameAutosaveName:@"VLCVoutWindowDetached"];
  890.         /* We'll catch mouse events */
  891.         [self makeFirstResponder: o_view];
  892.         [self setCanBecomeKeyWindow: YES];
  893.         [self setAcceptsMouseMovedEvents: YES];
  894.         [self setIgnoresMouseEvents: NO];
  895.         if( var_CreateGetBool( p_vout, "macosx-background" ) )
  896.         {
  897.             int i_device = var_GetInteger( p_vout->p_libvlc, "video-device" );
  898.             /* Find out on which screen to open the window */
  899.             NSScreen * screen = [NSScreen screenWithDisplayID: (CGDirectDisplayID)i_device];
  900.             if( !screen ) screen = [NSScreen mainScreen];
  901.             NSRect screen_rect = [screen frame];
  902.             screen_rect.origin.x = screen_rect.origin.y = 0;
  903.             /* Creates a window with size: screen_rect on o_screen */
  904.             [self setFrame: screen_rect display: NO];
  905.             [self setLevel: CGWindowLevelForKey(kCGDesktopWindowLevelKey)];
  906.             [self setMovableByWindowBackground: NO];
  907.         }
  908.         if( var_CreateGetBool( p_vout, "video-on-top" ) )
  909.         {
  910.             [self setLevel: NSStatusWindowLevel];
  911.         }
  912.         [self setAlphaValue: var_CreateGetFloat( p_vout, "macosx-opaqueness" )];
  913.         /* Add the view. It's automatically resized to fit the window */
  914.         [self setContentView: o_view];
  915.         b_init_ok = YES;
  916.     }
  917.     return self;
  918. }
  919. - (void)enterFullscreen
  920. {
  921.     if( fullscreen ) return;
  922.     NSScreen *screen;
  923.     int i_device;
  924.     BOOL b_black = NO;
  925.     i_device = var_GetInteger( p_vout->p_libvlc, "video-device" );
  926.     b_black = var_CreateGetBool( p_vout, "macosx-black" );
  927.     /* Find out on which screen to open the window */
  928.     screen = [NSScreen screenWithDisplayID: (CGDirectDisplayID)i_device];
  929.     if( !screen ) screen = [self screen];
  930.     if( b_black )
  931.         [screen blackoutOtherScreens];
  932.     [self setMovableByWindowBackground: NO];
  933.     if( [screen isMainScreen] )
  934.         SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
  935.     initialFrame = [self frame];
  936.     [self setFrame:[screen frame] display:YES animate:YES];
  937.     [self setLevel:NSNormalWindowLevel];
  938.     /* tell the fspanel to move itself to front next time it's triggered */
  939.     [[[[VLCMain sharedInstance] controls] fspanel] setVoutWasUpdated: i_device];
  940.     [[[[VLCMain sharedInstance] controls] fspanel] setActive: nil];
  941.     fullscreen = YES;
  942. }
  943. - (void)leaveFullscreen
  944. {
  945.     if( !fullscreen ) return;
  946.     fullscreen = NO;
  947.     [NSScreen unblackoutScreens];
  948.     [[[[VLCMain sharedInstance] controls] fspanel] setNonActive: nil];
  949.     SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
  950.     [self setFrame:initialFrame display:YES animate:YES];
  951.     [self setMovableByWindowBackground: YES];
  952.     if( var_GetBool( p_vout, "video-on-top" ) )
  953.         [self setLevel: NSStatusWindowLevel];
  954. }
  955. - (id)voutView
  956. {
  957.     return o_view;
  958. }
  959. @end