X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fmacosx%2Fvout.m;h=484f8cb63a0b328e60a6c6432e9aea98656aa084;hb=699e4bb62df2e5b70a4f08c179686af1369a1a21;hp=2c73763f3c6c8e8e607bc44e653ad6e88a4a2be2;hpb=8f10d4fe9cc8f4e41341534d60dc5b469db109b6;p=vlc diff --git a/modules/gui/macosx/vout.m b/modules/gui/macosx/vout.m index 2c73763f3c..484f8cb63a 100644 --- a/modules/gui/macosx/vout.m +++ b/modules/gui/macosx/vout.m @@ -1,13 +1,14 @@ /***************************************************************************** - * vout.m: MacOS X video output plugin + * vout.m: MacOS X video output module ***************************************************************************** * Copyright (C) 2001-2003 VideoLAN - * $Id: vout.m,v 1.16 2003/01/23 23:51:13 massiot Exp $ + * $Id$ * * Authors: Colin Delacroix * Florian G. Pflug * Jon Lech Johansen - * Derk-Jan Hartman + * Derk-Jan Hartman + * Eric Petit * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,163 +32,62 @@ #include /* free() */ #include /* strerror() */ -#include -#include -#include -#include - -#include +/* BeginFullScreen, EndFullScreen */ #include +#include + #include "intf.h" #include "vout.h" -#define QT_MAX_DIRECTBUFFERS 10 - -struct picture_sys_t -{ - void *p_info; - unsigned int i_size; - - /* When using I420 output */ - PlanarPixmapInfoYUV420 pixmap_i420; -}; - -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static int vout_Init ( vout_thread_t * ); -static void vout_End ( vout_thread_t * ); -static int vout_Manage ( vout_thread_t * ); -static void vout_Display ( vout_thread_t *, picture_t * ); - -static int CoSendRequest ( vout_thread_t *, SEL ); -static int CoCreateWindow ( vout_thread_t * ); -static int CoDestroyWindow ( vout_thread_t * ); -static int CoToggleFullscreen ( vout_thread_t * ); - -static void QTScaleMatrix ( vout_thread_t * ); -static int QTCreateSequence ( vout_thread_t * ); -static void QTDestroySequence ( vout_thread_t * ); -static int QTNewPicture ( vout_thread_t *, picture_t * ); -static void QTFreePicture ( vout_thread_t *, picture_t * ); - /***************************************************************************** - * OpenVideo: allocates MacOS X video thread output method - ***************************************************************************** - * This function allocates and initializes a MacOS X vout method. + * VLCWindow implementation *****************************************************************************/ -int E_(OpenVideo) ( vlc_object_t *p_this ) -{ - vout_thread_t * p_vout = (vout_thread_t *)p_this; - OSErr err; - int i_timeout; - - p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); - if( p_vout->p_sys == NULL ) - { - msg_Err( p_vout, "out of memory" ); - return( 1 ); - } +@implementation VLCWindow - memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) ); +- (id)initWithVout:(vout_thread_t *)_p_vout frame:(NSRect *)s_frame +{ + [self setReleasedWhenClosed: YES]; - /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */ - for( i_timeout = 20 ; i_timeout-- ; ) - { - if( NSApp == NULL ) - { - msleep( INTF_IDLE_SLEEP ); - } - } + p_vout = _p_vout; - if( NSApp == NULL ) + /* p_real_vout: the vout we have to use to check for video-on-top + and a few other things. If we are the QuickTime output, it's us. + It we are the OpenGL provider, it is our parent. */ + if( p_vout->i_object_type == VLC_OBJECT_OPENGL ) { - msg_Err( p_vout, "no MacOS X interface present" ); - free( p_vout->p_sys ); - return( 1 ); + p_real_vout = (vout_thread_t *) p_vout->p_parent; } - - if( [NSApp respondsToSelector: @selector(getIntf)] ) + else { - intf_thread_t * p_intf; - - for( i_timeout = 10 ; i_timeout-- ; ) - { - if( ( p_intf = [NSApp getIntf] ) == NULL ) - { - msleep( INTF_IDLE_SLEEP ); - } - } - - if( p_intf == NULL ) - { - msg_Err( p_vout, "MacOS X intf has getIntf, but is NULL" ); - free( p_vout->p_sys ); - return( 1 ); - } + p_real_vout = p_vout; } - p_vout->p_sys->h_img_descr = - (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) ); - p_vout->p_sys->p_matrix = (MatrixRecordPtr)malloc( sizeof(MatrixRecord) ); - p_vout->p_sys->p_fullscreen_state = NULL; - - p_vout->p_sys->b_mouse_pointer_visible = 1; - - /* set window size */ - p_vout->p_sys->s_rect.size.width = p_vout->i_window_width; - p_vout->p_sys->s_rect.size.height = p_vout->i_window_height; + p_fullscreen_state = NULL; + i_time_mouse_last_moved = mdate(); - if( ( err = EnterMovies() ) != noErr ) - { - msg_Err( p_vout, "EnterMovies failed: %d", err ); - free( p_vout->p_sys->p_matrix ); - DisposeHandle( (Handle)p_vout->p_sys->h_img_descr ); - free( p_vout->p_sys ); - return( 1 ); - } - - if( vout_ChromaCmp( p_vout->render.i_chroma, VLC_FOURCC('I','4','2','0') ) ) - { - err = FindCodec( kYUV420CodecType, bestSpeedCodec, - nil, &p_vout->p_sys->img_dc ); - if( err == noErr && p_vout->p_sys->img_dc != 0 ) - { - p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0'); - p_vout->p_sys->i_codec = kYUV420CodecType; - } - else - { - msg_Err( p_vout, "failed to find an appropriate codec" ); - } - } - else - { - msg_Err( p_vout, "chroma 0x%08x not supported", - p_vout->render.i_chroma ); - } + NSScreen * o_screen; + vlc_bool_t b_main_screen; - if( p_vout->p_sys->img_dc == 0 ) - { - free( p_vout->p_sys->p_matrix ); - DisposeHandle( (Handle)p_vout->p_sys->h_img_descr ); - free( p_vout->p_sys ); - return( 1 ); - } + var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + var_Create( p_vout, "macosx-fill", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); + var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); + var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT ); - NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; + /* Setup the menuitem for the multiple displays. Read the vlc preference (macosx-vdev) for the primary display */ NSArray * o_screens = [NSScreen screens]; - if( [o_screens count] > 0 && var_Type( p_vout, "video-device" ) == 0 ) + if( [o_screens count] > 0 && var_Type( p_real_vout, "video-device" ) == 0 ) { int i = 1; - vlc_value_t val; + vlc_value_t val, val2, text; NSScreen * o_screen; - int i_option = config_GetInt( p_vout, "macosx-vdev" ); + var_Get( p_real_vout, "macosx-vdev", &val ); - var_Create( p_vout, "video-device", VLC_VAR_STRING | - VLC_VAR_HASCHOICE ); + var_Create( p_real_vout, "video-device", VLC_VAR_INTEGER | + VLC_VAR_HASCHOICE ); + text.psz_string = _("Video device"); + var_Change( p_real_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL ); NSEnumerator * o_enumerator = [o_screens objectEnumerator]; @@ -196,648 +96,351 @@ int E_(OpenVideo) ( vlc_object_t *p_this ) char psz_temp[255]; NSRect s_rect = [o_screen frame]; - snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1, + snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1, "%s %d (%dx%d)", _("Screen"), i, - (int)s_rect.size.width, (int)s_rect.size.height ); + (int)s_rect.size.width, (int)s_rect.size.height ); - val.psz_string = psz_temp; - var_Change( p_vout, "video-device", VLC_VAR_ADDCHOICE, &val ); + text.psz_string = psz_temp; + val2.i_int = i; + var_Change( p_real_vout, "video-device", + VLC_VAR_ADDCHOICE, &val2, &text ); - if( ( i - 1 ) == i_option ) + if( ( i - 1 ) == val.i_int ) { - var_Set( p_vout, "video-device", val ); + var_Set( p_real_vout, "video-device", val2 ); } - i++; } - var_AddCallback( p_vout, "video-device", vout_VarCallback, + var_AddCallback( p_real_vout, "video-device", vout_VarCallback, NULL ); - val.b_bool = VLC_TRUE; - var_Set( p_vout, "intf-change", val ); - } - [o_pool release]; - - if( CoCreateWindow( p_vout ) ) - { - msg_Err( p_vout, "unable to create window" ); - free( p_vout->p_sys->p_matrix ); - DisposeHandle( (Handle)p_vout->p_sys->h_img_descr ); - free( p_vout->p_sys ); - return( 1 ); + val2.b_bool = VLC_TRUE; + var_Set( p_real_vout, "intf-change", val2 ); } - p_vout->pf_init = vout_Init; - p_vout->pf_end = vout_End; - p_vout->pf_manage = vout_Manage; - p_vout->pf_render = NULL; - p_vout->pf_display = vout_Display; - - return( 0 ); -} - -/***************************************************************************** - * vout_Init: initialize video thread output method - *****************************************************************************/ -static int vout_Init( vout_thread_t *p_vout ) -{ - int i_index; - picture_t *p_pic; - - I_OUTPUTPICTURES = 0; - - /* Initialize the output structure; we already found a codec, - * and the corresponding chroma we will be using. Since we can - * arbitrary scale, stick to the coordinates and aspect. */ - p_vout->output.i_width = p_vout->render.i_width; - p_vout->output.i_height = p_vout->render.i_height; - p_vout->output.i_aspect = p_vout->render.i_aspect; - - SetPort( p_vout->p_sys->p_qdport ); - QTScaleMatrix( p_vout ); - - if( QTCreateSequence( p_vout ) ) + /* Find out on which screen to open the window */ + int i_device = var_GetInteger( p_real_vout, "video-device" ); + if( i_device < 0 ) { - msg_Err( p_vout, "unable to create sequence" ); - return( 1 ); + /* No preference specified. Use the main screen */ + o_screen = [NSScreen mainScreen]; + b_main_screen = 1; } - - /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */ - while( I_OUTPUTPICTURES < QT_MAX_DIRECTBUFFERS ) + else { - p_pic = NULL; - - /* Find an empty picture slot */ - for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ ) + NSArray *o_screens = [NSScreen screens]; + + if( [o_screens count] < (unsigned) i_device ) { - if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) - { - p_pic = p_vout->p_picture + i_index; - break; - } + o_screen = [NSScreen mainScreen]; + b_main_screen = 1; } - - /* Allocate the picture */ - if( p_pic == NULL || QTNewPicture( p_vout, p_pic ) ) + else { - break; + i_device--; + o_screen = [o_screens objectAtIndex: i_device]; + var_SetInteger( p_real_vout, "macosx-vdev", i_device ); + b_main_screen = ( i_device == 0 ); } - - p_pic->i_status = DESTROYED_PICTURE; - p_pic->i_type = DIRECT_PICTURE; - - PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; - - I_OUTPUTPICTURES++; } - return( 0 ); -} - -/***************************************************************************** - * vout_End: terminate video thread output method - *****************************************************************************/ -static void vout_End( vout_thread_t *p_vout ) -{ - int i_index; - - QTDestroySequence( p_vout ); - - /* Free the direct buffers we allocated */ - for( i_index = I_OUTPUTPICTURES; i_index; ) - { - i_index--; - QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] ); - } -} + NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; -/***************************************************************************** - * CloseVideo: destroy video thread output method - *****************************************************************************/ -void E_(CloseVideo) ( vlc_object_t *p_this ) -{ - vout_thread_t * p_vout = (vout_thread_t *)p_this; - - if( CoDestroyWindow( p_vout ) ) + if( p_vout->b_fullscreen ) { - msg_Err( p_vout, "unable to destroy window" ); - } - - if ( p_vout->p_sys->p_fullscreen_state != NULL ) - EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL ); - - ExitMovies(); - - free( p_vout->p_sys->p_matrix ); - DisposeHandle( (Handle)p_vout->p_sys->h_img_descr ); + NSRect screen_rect = [o_screen frame]; + screen_rect.origin.x = screen_rect.origin.y = 0; - free( p_vout->p_sys ); -} + /* Creates a window with size: screen_rect on o_screen */ + [self initWithContentRect: screen_rect + styleMask: NSBorderlessWindowMask + backing: NSBackingStoreBuffered + defer: YES screen: o_screen]; -/***************************************************************************** - * vout_Manage: handle events - ***************************************************************************** - * This function should be called regularly by video output thread. It manages - * console events. It returns a non null value on error. - *****************************************************************************/ -static int vout_Manage( vout_thread_t *p_vout ) -{ - if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) - { - if( CoToggleFullscreen( p_vout ) ) + if( b_main_screen ) { - return( 1 ); + BeginFullScreen( &p_fullscreen_state, NULL, 0, 0, + NULL, NULL, fullScreenAllowEvents ); } - - p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; } - - if( p_vout->i_changes & VOUT_SIZE_CHANGE ) - { - QTScaleMatrix( p_vout ); - SetDSequenceMatrix( p_vout->p_sys->i_seq, - p_vout->p_sys->p_matrix ); - - p_vout->i_changes &= ~VOUT_SIZE_CHANGE; - } - - /* hide/show mouse cursor */ - if( p_vout->p_sys->b_mouse_moved || - p_vout->p_sys->i_time_mouse_last_moved ) + else { - vlc_bool_t b_change = 0; + unsigned int i_stylemask = NSTitledWindowMask | + NSMiniaturizableWindowMask | + NSClosableWindowMask | + NSResizableWindowMask; - if( !p_vout->p_sys->b_mouse_pointer_visible ) + NSRect s_rect; + if( !s_frame ) { - CGDisplayShowCursor( kCGDirectMainDisplay ); - b_change = 1; + s_rect.size.width = p_vout->i_window_width; + s_rect.size.height = p_vout->i_window_height; } -#if 0 - else if( !p_vout->p_sys->b_mouse_moved && - mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 && - p_vout->p_sys->b_mouse_pointer_visible ) + else { - CGDisplayHideCursor( kCGDirectMainDisplay ); - b_change = 1; + s_rect = *s_frame; } -#endif + + [self initWithContentRect: s_rect + styleMask: i_stylemask + backing: NSBackingStoreBuffered + defer: YES screen: o_screen]; - if( b_change ) + [self setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )]; + + if( var_GetBool( p_real_vout, "video-on-top" ) ) { - p_vout->p_sys->i_time_mouse_last_moved = 0; - p_vout->p_sys->b_mouse_moved = 0; - p_vout->p_sys->b_mouse_pointer_visible = - !p_vout->p_sys->b_mouse_pointer_visible; + [self setLevel: NSStatusWindowLevel]; } - } - return( 0 ); -} - -/***************************************************************************** - * vout_Display: displays previously rendered output - ***************************************************************************** - * This function sends the currently rendered image to the display. - *****************************************************************************/ -static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic ) -{ - OSErr err; - CodecFlags flags; - - if( ( err = DecompressSequenceFrameS( - p_vout->p_sys->i_seq, - p_pic->p_sys->p_info, - p_pic->p_sys->i_size, - codecFlagUseImageBuffer, &flags, nil ) != noErr ) ) - { - msg_Err( p_vout, "DecompressSequenceFrameS failed: %d", err ); - } - else - { - QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil ); + if( !s_frame ) + { + [self center]; + } } -} - -/***************************************************************************** - * CoSendRequest: send request to interface thread - ***************************************************************************** - * Returns 0 on success, 1 otherwise - *****************************************************************************/ -static int CoSendRequest( vout_thread_t *p_vout, SEL sel ) -{ - int i_ret = 0; - NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init]; - VLCVout * o_vlv = [[[VLCVout alloc] init] autorelease]; - - if( [o_vlv respondsToSelector: @selector(performSelectorOnMainThread: - withObject:waitUntilDone:)] ) - { - [o_vlv performSelectorOnMainThread: sel - withObject: [NSValue valueWithPointer: p_vout] - waitUntilDone: YES]; - } - else if( [NSApp respondsToSelector: @selector(getIntf)] ) - { - NSArray * o_array; - NSValue * o_value; - NSPort * o_recv_port; - NSInvocation * o_inv; - NSPortMessage * o_msg; - intf_thread_t * p_intf; - NSMethodSignature * o_sig; - - p_intf = (intf_thread_t *)[NSApp getIntf]; - - o_recv_port = [[NSPort port] retain]; - o_value = [NSValue valueWithPointer: p_vout]; - - o_sig = [VLCVout instanceMethodSignatureForSelector: sel]; - o_inv = [NSInvocation invocationWithMethodSignature: o_sig]; - [o_inv setArgument: &o_value atIndex: 2]; - [o_inv setTarget: o_vlv]; - [o_inv setSelector: sel]; - - o_array = [NSArray arrayWithObject: - [NSData dataWithBytes: &o_inv length: sizeof(o_inv)]]; - o_msg = [[NSPortMessage alloc] - initWithSendPort: p_intf->p_sys->o_sendport - receivePort: o_recv_port components: o_array]; - - p_vout->p_sys->o_lock = - [[NSConditionLock alloc] initWithCondition: 0]; - [o_msg sendBeforeDate: [NSDate distantPast]]; - [p_vout->p_sys->o_lock lockWhenCondition: 1]; - [p_vout->p_sys->o_lock unlock]; - [p_vout->p_sys->o_lock release]; - p_vout->p_sys->o_lock = nil; - - [o_msg release]; - [o_recv_port release]; - } - else - { - msg_Err( p_vout, "SendRequest: no way to communicate with mt" ); - i_ret = 1; - } + [self updateTitle]; + [self makeKeyAndOrderFront: nil]; + /* We'll catch mouse events */ + [self setAcceptsMouseMovedEvents: YES]; + [self makeFirstResponder: self]; + [o_pool release]; - - return( i_ret ); + return self; } -/***************************************************************************** - * CoCreateWindow: create new window - ***************************************************************************** - * Returns 0 on success, 1 otherwise - *****************************************************************************/ -static int CoCreateWindow( vout_thread_t *p_vout ) +- (void)close { - if( CoSendRequest( p_vout, @selector(createWindow:) ) ) + if( p_fullscreen_state ) { - msg_Err( p_vout, "CoSendRequest (createWindow) failed" ); - return( 1 ); + EndFullScreen( p_fullscreen_state, NULL ); } - - return( 0 ); + [super close]; } -/***************************************************************************** - * CoDestroyWindow: destroy window - ***************************************************************************** - * Returns 0 on success, 1 otherwise - *****************************************************************************/ -static int CoDestroyWindow( vout_thread_t *p_vout ) +- (void)setOnTop:(BOOL)b_on_top { - if( !p_vout->p_sys->b_mouse_pointer_visible ) + if( b_on_top ) { - CGDisplayShowCursor( kCGDirectMainDisplay ); - p_vout->p_sys->b_mouse_pointer_visible = 1; + [self setLevel: NSStatusWindowLevel]; } - - if( CoSendRequest( p_vout, @selector(destroyWindow:) ) ) + else { - msg_Err( p_vout, "CoSendRequest (destroyWindow) failed" ); - return( 1 ); + [self setLevel: NSNormalWindowLevel]; } - - return( 0 ); } -/***************************************************************************** - * CoToggleFullscreen: toggle fullscreen - ***************************************************************************** - * Returns 0 on success, 1 otherwise - *****************************************************************************/ -static int CoToggleFullscreen( vout_thread_t *p_vout ) +- (void)hideMouse:(BOOL)b_hide { - QTDestroySequence( p_vout ); - - if( CoDestroyWindow( p_vout ) ) - { - msg_Err( p_vout, "unable to destroy window" ); - return( 1 ); - } + BOOL b_inside; + NSPoint ml; + NSView *o_contents = [self contentView]; - p_vout->b_fullscreen = !p_vout->b_fullscreen; - - config_PutInt( p_vout, "fullscreen", p_vout->b_fullscreen ); - - if( CoCreateWindow( p_vout ) ) + ml = [self convertScreenToBase:[NSEvent mouseLocation]]; + ml = [o_contents convertPoint:ml fromView:nil]; + b_inside = [o_contents mouse: ml inRect: [o_contents bounds]]; + + if( b_hide && b_inside ) { - msg_Err( p_vout, "unable to create window" ); - return( 1 ); + [NSCursor setHiddenUntilMouseMoves: YES]; } - - SetPort( p_vout->p_sys->p_qdport ); - QTScaleMatrix( p_vout ); - - if( QTCreateSequence( p_vout ) ) + else if( !b_hide ) { - msg_Err( p_vout, "unable to create sequence" ); - return( 1 ); - } - - return( 0 ); + [NSCursor setHiddenUntilMouseMoves: NO]; + } } -/***************************************************************************** - * QTScaleMatrix: scale matrix - *****************************************************************************/ -static void QTScaleMatrix( vout_thread_t *p_vout ) +- (void)manage { - Rect s_rect; - unsigned int i_width, i_height; - Fixed factor_x, factor_y; - unsigned int i_offset_x = 0; - unsigned int i_offset_y = 0; - - GetPortBounds( p_vout->p_sys->p_qdport, &s_rect ); - - i_width = s_rect.right - s_rect.left; - i_height = s_rect.bottom - s_rect.top; - - if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR ) + if( p_fullscreen_state ) { - int i_adj_width = i_height * p_vout->output.i_aspect / - VOUT_ASPECT_FACTOR; - - factor_x = FixDiv( Long2Fix( i_adj_width ), - Long2Fix( p_vout->output.i_width ) ); - factor_y = FixDiv( Long2Fix( i_height ), - Long2Fix( p_vout->output.i_height ) ); - - i_offset_x = (i_width - i_adj_width) / 2; + if( mdate() - i_time_mouse_last_moved > 3000000 ) + { + [self hideMouse: YES]; + } } else { - int i_adj_height = i_width * VOUT_ASPECT_FACTOR / - p_vout->output.i_aspect; - - factor_x = FixDiv( Long2Fix( i_width ), - Long2Fix( p_vout->output.i_width ) ); - factor_y = FixDiv( Long2Fix( i_adj_height ), - Long2Fix( p_vout->output.i_height ) ); - - i_offset_y = (i_height - i_adj_height) / 2; + [self hideMouse: NO]; } - SetIdentityMatrix( p_vout->p_sys->p_matrix ); - - ScaleMatrix( p_vout->p_sys->p_matrix, - factor_x, factor_y, - Long2Fix(0), Long2Fix(0) ); - - TranslateMatrix( p_vout->p_sys->p_matrix, - Long2Fix(i_offset_x), - Long2Fix(i_offset_y) ); + /* Disable screensaver */ + UpdateSystemActivity( UsrActivity ); } -/***************************************************************************** - * QTCreateSequence: create a new sequence - ***************************************************************************** - * Returns 0 on success, 1 otherwise - *****************************************************************************/ -static int QTCreateSequence( vout_thread_t *p_vout ) +- (void)scaleWindowWithFactor: (float)factor { - OSErr err; - ImageDescriptionPtr p_descr; - - HLock( (Handle)p_vout->p_sys->h_img_descr ); - p_descr = *p_vout->p_sys->h_img_descr; - - p_descr->idSize = sizeof(ImageDescription); - p_descr->cType = p_vout->p_sys->i_codec; - p_descr->version = 1; - p_descr->revisionLevel = 0; - p_descr->vendor = 'appl'; - p_descr->width = p_vout->output.i_width; - p_descr->height = p_vout->output.i_height; - p_descr->hRes = Long2Fix(72); - p_descr->vRes = Long2Fix(72); - p_descr->spatialQuality = codecLosslessQuality; - p_descr->frameCount = 1; - p_descr->clutID = -1; - p_descr->dataSize = 0; - p_descr->depth = 24; - - HUnlock( (Handle)p_vout->p_sys->h_img_descr ); - - if( ( err = DecompressSequenceBeginS( - &p_vout->p_sys->i_seq, - p_vout->p_sys->h_img_descr, - NULL, 0, - p_vout->p_sys->p_qdport, - NULL, NULL, - p_vout->p_sys->p_matrix, - 0, NULL, - codecFlagUseImageBuffer, - codecLosslessQuality, - p_vout->p_sys->img_dc ) ) ) - { - msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err ); - return( 1 ); + NSSize newsize; + int i_corrected_height, i_corrected_width; + NSPoint topleftbase; + NSPoint topleftscreen; + + if ( !p_vout->b_fullscreen ) + { + topleftbase.x = 0; + topleftbase.y = [self frame].size.height; + topleftscreen = [self convertBaseToScreen: topleftbase]; + + if( p_vout->render.i_height * p_vout->render.i_aspect > + p_vout->render.i_width * VOUT_ASPECT_FACTOR ) + { + i_corrected_width = p_vout->render.i_height * p_vout->render.i_aspect / + VOUT_ASPECT_FACTOR; + newsize.width = (int) ( i_corrected_width * factor ); + newsize.height = (int) ( p_vout->render.i_height * factor ); + } + else + { + i_corrected_height = p_vout->render.i_width * VOUT_ASPECT_FACTOR / + p_vout->render.i_aspect; + newsize.width = (int) ( p_vout->render.i_width * factor ); + newsize.height = (int) ( i_corrected_height * factor ); + } + + [self setContentSize: newsize]; + + [self setFrameTopLeftPoint: topleftscreen]; + p_vout->i_changes |= VOUT_SIZE_CHANGE; } - - return( 0 ); -} - -/***************************************************************************** - * QTDestroySequence: destroy sequence - *****************************************************************************/ -static void QTDestroySequence( vout_thread_t *p_vout ) -{ - CDSequenceEnd( p_vout->p_sys->i_seq ); } -/***************************************************************************** - * QTNewPicture: allocate a picture - ***************************************************************************** - * Returns 0 on success, 1 otherwise - *****************************************************************************/ -static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic ) +- (void)toggleFloatOnTop { - int i_width = p_vout->output.i_width; - int i_height = p_vout->output.i_height; - - /* We know the chroma, allocate a buffer which will be used - * directly by the decoder */ - p_pic->p_sys = malloc( sizeof( picture_sys_t ) ); - - if( p_pic->p_sys == NULL ) - { - return( -1 ); - } - - switch( p_vout->output.i_chroma ) + vlc_value_t val; + if( var_Get( p_vout, "video-on-top", &val )>=0 && val.b_bool) { - case VLC_FOURCC('I','4','2','0'): - - p_pic->p_sys->p_info = (void *)&p_pic->p_sys->pixmap_i420; - p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420); - - /* Allocate the memory buffer */ - p_pic->p_data = vlc_memalign( &p_pic->p_data_orig, - 16, i_width * i_height * 3 / 2 ); - - /* Y buffer */ - p_pic->Y_PIXELS = p_pic->p_data; - p_pic->p[Y_PLANE].i_lines = i_height; - p_pic->p[Y_PLANE].i_pitch = i_width; - p_pic->p[Y_PLANE].i_pixel_pitch = 1; - p_pic->p[Y_PLANE].i_visible_pitch = i_width; - - /* U buffer */ - p_pic->U_PIXELS = p_pic->Y_PIXELS + i_height * i_width; - p_pic->p[U_PLANE].i_lines = i_height / 2; - p_pic->p[U_PLANE].i_pitch = i_width / 2; - p_pic->p[U_PLANE].i_pixel_pitch = 1; - p_pic->p[U_PLANE].i_visible_pitch = i_width / 2; - - /* V buffer */ - p_pic->V_PIXELS = p_pic->U_PIXELS + i_height * i_width / 4; - p_pic->p[V_PLANE].i_lines = i_height / 2; - p_pic->p[V_PLANE].i_pitch = i_width / 2; - p_pic->p[V_PLANE].i_pixel_pitch = 1; - p_pic->p[V_PLANE].i_visible_pitch = i_width / 2; - - /* We allocated 3 planes */ - p_pic->i_planes = 3; - -#define P p_pic->p_sys->pixmap_i420 - P.componentInfoY.offset = (void *)p_pic->Y_PIXELS - - p_pic->p_sys->p_info; - P.componentInfoCb.offset = (void *)p_pic->U_PIXELS - - p_pic->p_sys->p_info; - P.componentInfoCr.offset = (void *)p_pic->V_PIXELS - - p_pic->p_sys->p_info; - - P.componentInfoY.rowBytes = i_width; - P.componentInfoCb.rowBytes = i_width / 2; - P.componentInfoCr.rowBytes = i_width / 2; -#undef P - - break; - - default: - /* Unknown chroma, tell the guy to get lost */ - free( p_pic->p_sys ); - msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)", - p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma ); - p_pic->i_planes = 0; - return( -1 ); + val.b_bool = VLC_FALSE; + var_Set( p_vout, "video-on-top", val ); } - - return( 0 ); -} - -/***************************************************************************** - * QTFreePicture: destroy a picture allocated with QTNewPicture - *****************************************************************************/ -static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic ) -{ - switch( p_vout->output.i_chroma ) + else { - case VLC_FOURCC('I','4','2','0'): - free( p_pic->p_data_orig ); - break; + val.b_bool = VLC_TRUE; + var_Set( p_vout, "video-on-top", val ); } - - free( p_pic->p_sys ); } -/***************************************************************************** - * VLCWindow implementation - *****************************************************************************/ -@implementation VLCWindow - -- (void)setVout:(vout_thread_t *)_p_vout +- (void)toggleFullscreen { - p_vout = _p_vout; + vlc_value_t val; + val.b_bool = !p_real_vout->b_fullscreen; + var_Set( p_real_vout, "fullscreen", val ); } -- (vout_thread_t *)getVout +- (BOOL)isFullscreen { - return( p_vout ); + return( p_vout->b_fullscreen ); } -- (void)toggleFullscreen +- (void)snapshot { - p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; + vout_Control( p_vout, VOUT_SNAPSHOT ); } -- (BOOL)isFullscreen +- (BOOL)canBecomeKeyWindow { - return( p_vout->b_fullscreen ); + return YES; } -- (BOOL)canBecomeKeyWindow +/* Sometimes crashes VLC.... +- (BOOL)performKeyEquivalent:(NSEvent *)o_event { - return( YES ); -} + return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event]; +}*/ - (void)keyDown:(NSEvent *)o_event { unichar key = 0; + vlc_value_t val; + unsigned int i_pressed_modifiers = 0; + val.i_int = 0; + + i_pressed_modifiers = [o_event modifierFlags]; + + if( i_pressed_modifiers & NSShiftKeyMask ) + val.i_int |= KEY_MODIFIER_SHIFT; + if( i_pressed_modifiers & NSControlKeyMask ) + val.i_int |= KEY_MODIFIER_CTRL; + if( i_pressed_modifiers & NSAlternateKeyMask ) + val.i_int |= KEY_MODIFIER_ALT; + if( i_pressed_modifiers & NSCommandKeyMask ) + val.i_int |= KEY_MODIFIER_COMMAND; - if( [[o_event characters] length] ) + key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0]; + + if( key ) + { + /* Escape should always get you out of fullscreen */ + if( key == (unichar) 0x1b ) + { + if( [self isFullscreen] ) + { + [self toggleFullscreen]; + } + } + else if ( key == ' ' ) + { + vlc_value_t val; + val.i_int = config_GetInt( p_vout, "key-play-pause" ); + var_Set( p_vout->p_vlc, "key-pressed", val ); + } + else + { + val.i_int |= CocoaKeyToVLC( key ); + var_Set( p_vout->p_vlc, "key-pressed", val ); + } + } + else { - key = [[o_event characters] characterAtIndex: 0]; + [super keyDown: o_event]; } +} - switch( key ) +- (void)updateTitle +{ + NSMutableString * o_title; + playlist_t * p_playlist; + + if( p_vout == NULL ) { - case 'f': case 'F': - [self toggleFullscreen]; - break; - - case (unichar)0x1b: /* escape */ - if( [self isFullscreen] ) - { - [self toggleFullscreen]; - } - break; + return; + } + + p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + + if( p_playlist == NULL ) + { + return; + } - case 'q': case 'Q': - p_vout->p_vlc->b_die = VLC_TRUE; - break; + vlc_mutex_lock( &p_playlist->object_lock ); + o_title = [NSMutableString stringWithUTF8String: + p_playlist->status.p_item->input.psz_uri]; + vlc_mutex_unlock( &p_playlist->object_lock ); + vlc_object_release( p_playlist ); - case ' ': - input_SetStatus( p_vout, INPUT_STATUS_PAUSE ); - break; + if( o_title != nil ) + { + NSRange prefix_range = [o_title rangeOfString: @"file:"]; + if( prefix_range.location != NSNotFound ) + { + [o_title deleteCharactersInRange: prefix_range]; + } - default: - [super keyDown: o_event]; - break; + [self setTitleWithRepresentedFilename: o_title]; + } + else + { + [self setTitle: [NSString stringWithCString: VOUT_TITLE]]; } } /* This is actually the same as VLCControls::stop. */ - (BOOL)windowShouldClose:(id)sender { - intf_thread_t * p_intf = [NSApp getIntf]; - playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, + playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( p_playlist == NULL ) { @@ -846,262 +449,211 @@ static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic ) playlist_Stop( p_playlist ); vlc_object_release( p_playlist ); - p_intf->p_sys->b_stopping = 1; /* The window will be closed by the intf later. */ return NO; } -@end - -/***************************************************************************** - * VLCView implementation - *****************************************************************************/ -@implementation VLCView - -- (void)drawRect:(NSRect)rect -{ - vout_thread_t * p_vout; - id o_window = [self window]; - p_vout = (vout_thread_t *)[o_window getVout]; - - [[NSColor blackColor] set]; - NSRectFill( rect ); - [super drawRect: rect]; - - p_vout->i_changes |= VOUT_SIZE_CHANGE; -} - - (BOOL)acceptsFirstResponder { - return( YES ); + return YES; } - (BOOL)becomeFirstResponder { - [[self window] setAcceptsMouseMovedEvents: YES]; - return( YES ); + return YES; } - (BOOL)resignFirstResponder { - [[self window] setAcceptsMouseMovedEvents: NO]; - return( YES ); + /* We need to stay the first responder or we'll miss some + events */ + return NO; } -- (void)mouseUp:(NSEvent *)o_event +- (void)mouseDown:(NSEvent *)o_event { - vout_thread_t * p_vout; - id o_window = [self window]; - p_vout = (vout_thread_t *)[o_window getVout]; + vlc_value_t val; switch( [o_event type] ) { - case NSLeftMouseUp: + case NSLeftMouseDown: { - vlc_value_t val; - val.b_bool = VLC_TRUE; - var_Set( p_vout, "mouse-clicked", val ); + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int |= 1; + var_Set( p_vout, "mouse-button-down", val ); } break; default: - [super mouseUp: o_event]; + [super mouseDown: o_event]; break; } } -- (void)mouseMoved:(NSEvent *)o_event +- (void)otherMouseDown:(NSEvent *)o_event { - NSPoint ml; - NSRect s_rect; - BOOL b_inside; - - vout_thread_t * p_vout; - id o_window = [self window]; - p_vout = (vout_thread_t *)[o_window getVout]; - - s_rect = [self bounds]; - ml = [self convertPoint: [o_event locationInWindow] fromView: nil]; - b_inside = [self mouse: ml inRect: s_rect]; + vlc_value_t val; - if( b_inside ) + switch( [o_event type] ) { - vlc_value_t val; - int i_width, i_height, i_x, i_y; - - vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width, - (unsigned int)s_rect.size.height, - &i_x, &i_y, &i_width, &i_height ); - - val.i_int = ( ((int)ml.x) - i_x ) * - p_vout->render.i_width / i_width; - var_Set( p_vout, "mouse-x", val ); - - val.i_int = ( ((int)ml.y) - i_y ) * - p_vout->render.i_height / i_height; - var_Set( p_vout, "mouse-y", val ); + case NSOtherMouseDown: + { + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int |= 2; + var_Set( p_vout, "mouse-button-down", val ); + } + break; - val.b_bool = VLC_TRUE; - var_Set( p_vout, "mouse-moved", val ); - } - else - { - [super mouseMoved: o_event]; + default: + [super mouseDown: o_event]; + break; } } -@end - -/***************************************************************************** - * VLCVout implementation - *****************************************************************************/ -@implementation VLCVout - -- (void)createWindow:(NSValue *)o_value +- (void)rightMouseDown:(NSEvent *)o_event { vlc_value_t val; - VLCView * o_view; - NSScreen * o_screen; - vout_thread_t * p_vout; - id o_title; - vlc_bool_t b_main_screen; - - intf_thread_t * p_intf = [NSApp getIntf]; - playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, - FIND_ANYWHERE ); - - p_vout = (vout_thread_t *)[o_value pointerValue]; - - p_vout->p_sys->o_window = [VLCWindow alloc]; - [p_vout->p_sys->o_window setVout: p_vout]; - [p_vout->p_sys->o_window setReleasedWhenClosed: YES]; - if( var_Get( p_vout, "video-device", &val ) < 0 ) - { - o_screen = [NSScreen mainScreen]; - b_main_screen = 1; - } - else + switch( [o_event type] ) { - unsigned int i_index = 0; - NSArray *o_screens = [NSScreen screens]; - - if( !sscanf( val.psz_string, _("Screen %d"), &i_index ) || - [o_screens count] < i_index ) + case NSRightMouseDown: { - o_screen = [NSScreen mainScreen]; - b_main_screen = 1; + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int |= 4; + var_Set( p_vout, "mouse-button-down", val ); } - else - { - i_index--; - o_screen = [o_screens objectAtIndex: i_index]; - config_PutInt( p_vout, "macosx-vdev", i_index ); - b_main_screen = (i_index == 0); - } + break; - free( val.psz_string ); - } + default: + [super mouseDown: o_event]; + break; + } +} - if( p_vout->b_fullscreen ) - { - NSRect screen_rect = [o_screen frame]; - screen_rect.origin.x = screen_rect.origin.y = 0; +- (void)mouseUp:(NSEvent *)o_event +{ + vlc_value_t val; - if ( b_main_screen && p_vout->p_sys->p_fullscreen_state == NULL ) - BeginFullScreen( &p_vout->p_sys->p_fullscreen_state, NULL, 0, 0, - NULL, NULL, fullScreenHideCursor | fullScreenAllowEvents ); + switch( [o_event type] ) + { + case NSLeftMouseUp: + { + vlc_value_t b_val; + b_val.b_bool = VLC_TRUE; + var_Set( p_vout, "mouse-clicked", b_val ); - [p_vout->p_sys->o_window - initWithContentRect: screen_rect - styleMask: NSBorderlessWindowMask - backing: NSBackingStoreBuffered - defer: NO screen: o_screen]; + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int &= ~1; + var_Set( p_vout, "mouse-button-down", val ); + } + break; - [p_vout->p_sys->o_window setLevel: NSModalPanelWindowLevel]; + default: + [super mouseUp: o_event]; + break; } - else - { - unsigned int i_stylemask = NSTitledWindowMask | - NSMiniaturizableWindowMask | - NSClosableWindowMask | - NSResizableWindowMask | - NSTexturedBackgroundWindowMask; - - if ( p_vout->p_sys->p_fullscreen_state != NULL ) - EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL ); - p_vout->p_sys->p_fullscreen_state = NULL; +} - [p_vout->p_sys->o_window - initWithContentRect: p_vout->p_sys->s_rect - styleMask: i_stylemask - backing: NSBackingStoreBuffered - defer: NO screen: o_screen]; +- (void)otherMouseUp:(NSEvent *)o_event +{ + vlc_value_t val; - if( !p_vout->p_sys->b_pos_saved ) + switch( [o_event type] ) + { + case NSOtherMouseUp: { - [p_vout->p_sys->o_window center]; + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int &= ~2; + var_Set( p_vout, "mouse-button-down", val ); } - } - - o_view = [[VLCView alloc] init]; - /* FIXME: [o_view setMenu:] */ - [p_vout->p_sys->o_window setContentView: o_view]; - [o_view autorelease]; + break; - [o_view lockFocus]; - p_vout->p_sys->p_qdport = [o_view qdPort]; - [o_view unlockFocus]; + default: + [super mouseUp: o_event]; + break; + } +} +- (void)rightMouseUp:(NSEvent *)o_event +{ + vlc_value_t val; - if( p_playlist == NULL ) + switch( [o_event type] ) { - return; - } + case NSRightMouseUp: + { + var_Get( p_vout, "mouse-button-down", &val ); + val.i_int &= ~4; + var_Set( p_vout, "mouse-button-down", val ); + } + break; - vlc_mutex_lock( &p_playlist->object_lock ); - o_title = [NSString stringWithUTF8String: - p_playlist->pp_items[p_playlist->i_index]->psz_name]; - vlc_mutex_unlock( &p_playlist->object_lock ); + default: + [super mouseUp: o_event]; + break; + } +} - vlc_object_release( p_playlist ); +- (void)mouseDragged:(NSEvent *)o_event +{ + [self mouseMoved: o_event]; +} - if (o_title) - { - [p_vout->p_sys->o_window setTitle: o_title]; - [p_vout->p_sys->o_window makeKeyAndOrderFront: nil]; - } - else - { - [p_vout->p_sys->o_window setTitle: - [NSString stringWithCString: VOUT_TITLE " (QuickTime)"]]; - [p_vout->p_sys->o_window makeKeyAndOrderFront: nil]; - } +- (void)otherMouseDragged:(NSEvent *)o_event +{ + [self mouseMoved: o_event]; } -- (void)destroyWindow:(NSValue *)o_value +- (void)rightMouseDragged:(NSEvent *)o_event { - vout_thread_t * p_vout; + [self mouseMoved: o_event]; +} - p_vout = (vout_thread_t *)[o_value pointerValue]; +- (void)mouseMoved:(NSEvent *)o_event +{ + NSPoint ml; + NSRect s_rect; + BOOL b_inside; + NSView * o_view; + + i_time_mouse_last_moved = mdate(); + + o_view = [self contentView]; + s_rect = [o_view bounds]; + ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil]; + b_inside = [o_view mouse: ml inRect: s_rect]; - if( !p_vout->b_fullscreen ) + if( b_inside ) { - NSRect s_rect; + vlc_value_t val; + int i_width, i_height, i_x, i_y; - s_rect = [[p_vout->p_sys->o_window contentView] frame]; - p_vout->p_sys->s_rect.size = s_rect.size; + vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width, + (unsigned int)s_rect.size.height, + &i_x, &i_y, &i_width, &i_height ); - s_rect = [p_vout->p_sys->o_window frame]; - p_vout->p_sys->s_rect.origin = s_rect.origin; + val.i_int = ( ((int)ml.x) - i_x ) * + p_vout->render.i_width / i_width; + var_Set( p_vout, "mouse-x", val ); - p_vout->p_sys->b_pos_saved = 1; + if( [[o_view className] isEqualToString: @"VLCGLView"] ) + { + val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) * + p_vout->render.i_height / i_height; + } + else + { + val.i_int = ( ((int)ml.y) - i_y ) * + p_vout->render.i_height / i_height; + } + var_Set( p_vout, "mouse-y", val ); + + val.b_bool = VLC_TRUE; + var_Set( p_vout, "mouse-moved", val ); } - p_vout->p_sys->p_qdport = nil; - [p_vout->p_sys->o_window close]; - p_vout->p_sys->o_window = nil; + [super mouseMoved: o_event]; } @end