X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fmacosx%2Fvoutgl.m;h=f574e6590da663f853e1aa2d2c2950d1ca5fd0d8;hb=5ea28c6c18a903514f48ae3362da7cc571df4ccf;hp=41c6c50a3f1942b89bc5134ac5add7d5278375dd;hpb=2db86f65c1e34d2c7c53473d92d7c5db98330b0d;p=vlc diff --git a/modules/gui/macosx/voutgl.m b/modules/gui/macosx/voutgl.m index 41c6c50a3f..f574e6590d 100644 --- a/modules/gui/macosx/voutgl.m +++ b/modules/gui/macosx/voutgl.m @@ -32,7 +32,7 @@ *****************************************************************************/ #include /* ENOMEM */ #include /* free() */ -#include /* strerror() */ +#include #include @@ -72,6 +72,8 @@ struct vout_sys_t int i_width, i_height; WindowRef theWindow; WindowGroupRef winGroup; + vlc_bool_t b_clipped_out; + Rect clipBounds, viewBounds; }; /***************************************************************************** @@ -119,7 +121,7 @@ int E_(OpenVideoGL) ( vlc_object_t * p_this ) var_Get( p_vout->p_libvlc, "drawable", &value_drawable ); if( value_drawable.i_int != 0 ) { - static const GLint ATTRIBUTES[] = { + static const GLint ATTRIBUTES[] = { AGL_WINDOW, AGL_RGBA, AGL_NO_RECOVERY, @@ -142,7 +144,7 @@ int E_(OpenVideoGL) ( vlc_object_t * p_this ) msg_Err( p_vout, "no screen renderer available for required attributes." ); return VLC_EGENERIC; } - + p_vout->p_sys->agl_ctx = aglCreateContext(pixFormat, NULL); aglDestroyPixelFormat(pixFormat); if( NULL == p_vout->p_sys->agl_ctx ) @@ -167,21 +169,21 @@ int E_(OpenVideoGL) ( vlc_object_t * p_this ) } else { + NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; + p_vout->p_sys->b_embedded = VLC_FALSE; - p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init]; + [VLCGLView performSelectorOnMainThread:@selector(initVout:) withObject:[NSValue valueWithPointer:p_vout] waitUntilDone:YES]; - /* Create the GL view */ - p_vout->p_sys->o_glview = [[VLCGLView alloc] initWithVout: p_vout]; - [p_vout->p_sys->o_glview autorelease]; + [o_pool release]; - /* Spawn the window */ + /* Check to see if initVout: was successfull */ - if( !(p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout - subView: p_vout->p_sys->o_glview frame: nil]) ) + if( !p_vout->p_sys->o_vout_view ) { return VLC_EGENERIC; } + p_vout->pf_init = Init; p_vout->pf_end = End; p_vout->pf_manage = Manage; @@ -207,7 +209,7 @@ void E_(CloseVideoGL) ( vlc_object_t * p_this ) NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init]; /* Close the window */ - [p_vout->p_sys->o_vout_view closeVout]; + [p_vout->p_sys->o_vout_view performSelectorOnMainThread:@selector(closeVout) withObject:NULL waitUntilDone:YES]; [o_pool release]; } @@ -290,8 +292,8 @@ static int Lock( vout_thread_t * p_vout ) { if( kCGLNoError == CGLLockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]) ) { - [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext]; - return 0; + [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext]; + return 0; } return 1; } @@ -305,10 +307,24 @@ static void Unlock( vout_thread_t * p_vout ) * VLCGLView implementation *****************************************************************************/ @implementation VLCGLView ++ (void)initVout:(NSValue *)arg +{ + vout_thread_t * p_vout = [arg pointerValue]; + + /* Create the GL view */ + p_vout->p_sys->o_glview = [[VLCGLView alloc] initWithVout: p_vout]; + [p_vout->p_sys->o_glview autorelease]; + + /* Spawn the window */ + p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout + subView: p_vout->p_sys->o_glview frame: nil]; +} /* This function will reset the o_vout_view. It's useful to go fullscreen. */ -+ (void)resetVout: (vout_thread_t *)p_vout ++ (void)resetVout:(NSData *)arg { + vout_thread_t * p_vout = [arg pointerValue]; + if( p_vout->b_fullscreen ) { /* Save window size and position */ @@ -324,7 +340,7 @@ static void Unlock( vout_thread_t * p_vout ) #define o_glview p_vout->p_sys->o_glview o_glview = [[VLCGLView alloc] initWithVout: p_vout]; [o_glview autorelease]; - + if( p_vout->p_sys->b_saved_frame ) { p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout @@ -335,13 +351,20 @@ static void Unlock( vout_thread_t * p_vout ) { p_vout->p_sys->o_vout_view = [VLCVoutView getVoutView: p_vout subView: o_glview frame: nil]; - + } #undef o_glview } - (id) initWithVout: (vout_thread_t *) vout { + /* Must be called from main thread: + * "The NSView class is generally thread-safe, with a few exceptions. You + * should create, destroy, resize, move, and perform other operations on NSView + * objects only from the main thread of an application. Drawing from secondary + * threads is thread-safe as long as you bracket drawing calls with calls to + * lockFocusIfCanDraw and unlockFocus." Cocoa Thread Safety */ + p_vout = vout; NSOpenGLPixelFormatAttribute attribs[] = @@ -416,6 +439,8 @@ static void Unlock( vout_thread_t * p_vout ) glViewport( ( bounds.size.width - x ) / 2, ( bounds.size.height - y ) / 2, x, y ); + [super reshape]; + if( p_vout->p_sys->b_got_frame ) { /* Ask the opengl module to redraw */ @@ -432,7 +457,6 @@ static void Unlock( vout_thread_t * p_vout ) glClear( GL_COLOR_BUFFER_BIT ); Unlock( p_vout ); } - [super reshape]; } - (void) update @@ -464,9 +488,9 @@ static int aglInit( vout_thread_t * p_vout ) { vlc_value_t val; - Rect viewBounds; + Rect viewBounds; Rect clipBounds; - + var_Get( p_vout->p_libvlc, "drawable", &val ); p_vout->p_sys->agl_drawable = (AGLDrawable)val.i_int; aglSetDrawable(p_vout->p_sys->agl_ctx, p_vout->p_sys->agl_drawable); @@ -488,11 +512,18 @@ static int aglInit( vout_thread_t * p_vout ) var_Get( p_vout->p_libvlc, "drawable-clip-right", &val ); clipBounds.right = val.i_int; - aglLock(p_vout); - aglSetViewport(p_vout, viewBounds, clipBounds); - aglReshape(p_vout); - aglUnlock(p_vout); - + p_vout->p_sys->b_clipped_out = (clipBounds.top == clipBounds.bottom) + || (clipBounds.left == clipBounds.right); + if( ! p_vout->p_sys->b_clipped_out ) + { + aglLock(p_vout); + aglSetViewport(p_vout, viewBounds, clipBounds); + aglReshape(p_vout); + aglUnlock(p_vout); + } + p_vout->p_sys->clipBounds = clipBounds; + p_vout->p_sys->viewBounds = viewBounds; + return VLC_SUCCESS; } @@ -508,7 +539,7 @@ static void aglReshape( vout_thread_t * p_vout ) unsigned int i_height = p_vout->p_sys->i_height; unsigned int i_width = p_vout->p_sys->i_width; - vout_PlacePicture(p_vout, i_width, i_height, &x, &y, &i_width, &i_height); + vout_PlacePicture(p_vout, i_width, i_height, &x, &y, &i_width, &i_height); glViewport( p_vout->p_sys->i_offx + x, p_vout->p_sys->i_offy + y, i_width, i_height ); @@ -529,7 +560,7 @@ static void aglReshape( vout_thread_t * p_vout ) } /* private event class */ -enum +enum { kEventClassVLCPlugin = 'vlcp', }; @@ -577,7 +608,7 @@ static int aglManage( vout_thread_t * p_vout ) { /* Close the fullscreen window and resume normal drawing */ vlc_value_t val; - Rect viewBounds; + Rect viewBounds; Rect clipBounds; var_Get( p_vout->p_libvlc, "drawable", &val ); @@ -610,10 +641,10 @@ static int aglManage( vout_thread_t * p_vout ) else { Rect deviceRect; - + GDHandle deviceHdl = GetMainDevice(); deviceRect = (*deviceHdl)->gdRect; - + if( !p_vout->p_sys->theWindow ) { /* Create a window */ @@ -623,7 +654,7 @@ static int aglManage( vout_thread_t * p_vout ) | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute | kWindowNoShadowAttribute; - + windowAttrs &= (~kWindowResizableAttribute); CreateNewWindow(kDocumentWindowClass, windowAttrs, &deviceRect, &p_vout->p_sys->theWindow); @@ -633,14 +664,14 @@ static int aglManage( vout_thread_t * p_vout ) SetWindowGroup(p_vout->p_sys->theWindow, p_vout->p_sys->winGroup); SetWindowGroupParent( p_vout->p_sys->winGroup, GetWindowGroupOfClass(kDocumentWindowClass) ) ; } - + // Window title CFStringRef titleKey = CFSTR("Fullscreen VLC media plugin"); CFStringRef windowTitle = CFCopyLocalizedString(titleKey, NULL); SetWindowTitleWithCFString(p_vout->p_sys->theWindow, windowTitle); CFRelease(titleKey); CFRelease(windowTitle); - + //Install event handler static const EventTypeSpec win_events[] = { { kEventClassMouse, kEventMouseDown }, @@ -692,13 +723,52 @@ static int aglControl( vout_thread_t *p_vout, int i_query, va_list args ) clipBounds.left = va_arg( args, int); clipBounds.bottom = va_arg( args, int); clipBounds.right = va_arg( args, int); - - if( !p_vout->b_fullscreen ) + + if( !p_vout->b_fullscreen ) + { + /* + ** check that the clip rect is not empty, as this is used + ** by Firefox to prevent a plugin from displaying during + ** a scrolling event. In this case we just prevent buffers + ** from being swapped and ignore clipping as this is less + ** disruptive than a GL geometry change + */ + + p_vout->p_sys->b_clipped_out = (clipBounds.top == clipBounds.bottom) + || (clipBounds.left == clipBounds.right); + if( ! p_vout->p_sys->b_clipped_out ) + { + /* ignore consecutive viewport update with identical parameters */ + if( memcmp(&clipBounds, &(p_vout->p_sys->clipBounds), sizeof(clipBounds) ) + && memcmp(&viewBounds, &(p_vout->p_sys->viewBounds), sizeof(viewBounds)) ) + { + aglLock( p_vout ); + aglSetViewport(p_vout, viewBounds, clipBounds); + aglReshape( p_vout ); + aglUnlock( p_vout ); + p_vout->p_sys->clipBounds = clipBounds; + p_vout->p_sys->viewBounds = viewBounds; + } + } + } + return VLC_SUCCESS; + } + + case VOUT_REDRAW_RECT: + { + vout_thread_t * p_parent; + Rect areaBounds; + + areaBounds.top = va_arg( args, int); + areaBounds.left = va_arg( args, int); + areaBounds.bottom = va_arg( args, int); + areaBounds.right = va_arg( args, int); + + /* Ask the opengl module to redraw */ + p_parent = (vout_thread_t *) p_vout->p_parent; + if( p_parent && p_parent->pf_display ) { - aglLock( p_vout ); - aglSetViewport(p_vout, viewBounds, clipBounds); - aglReshape( p_vout ); - aglUnlock( p_vout ); + p_parent->pf_display( p_parent, NULL ); } return VLC_SUCCESS; } @@ -721,8 +791,16 @@ static int aglControl( vout_thread_t *p_vout, int i_query, va_list args ) static void aglSwap( vout_thread_t * p_vout ) { - p_vout->p_sys->b_got_frame = VLC_TRUE; - aglSwapBuffers(p_vout->p_sys->agl_ctx); + if( ! p_vout->p_sys->b_clipped_out ) + { + p_vout->p_sys->b_got_frame = VLC_TRUE; + aglSwapBuffers(p_vout->p_sys->agl_ctx); + } + else + { + /* drop frame */ + glFlush(); + } } /* Enter this function with the p_vout locked */ @@ -756,7 +834,7 @@ static void aglSetViewport( vout_thread_t *p_vout, Rect viewBounds, Rect clipBou p_vout->p_sys->i_height = viewBounds.bottom-viewBounds.top; p_vout->p_sys->i_offx = -clipBounds.left - viewBounds.left; p_vout->p_sys->i_offy = clipBounds.bottom + viewBounds.top - - p_vout->p_sys->i_height; + - p_vout->p_sys->i_height; aglUpdateContext(p_vout->p_sys->agl_ctx); } @@ -766,7 +844,7 @@ static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, Event { OSStatus result = noErr; UInt32 class = GetEventClass (event); - UInt32 kind = GetEventKind (event); + UInt32 kind = GetEventKind (event); vout_thread_t *p_vout = (vout_thread_t *)userData; result = CallNextEventHandler(nextHandler, event); @@ -774,7 +852,7 @@ static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, Event { HICommand theHICommand; GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof( HICommand ), NULL, &theHICommand ); - + switch ( theHICommand.commandID ) { default: @@ -785,13 +863,13 @@ static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, Event { WindowRef window; Rect rectPort = {0,0,0,0}; - + GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window); if(window) { GetPortBounds(GetWindowPort(window), &rectPort); - } + } switch (kind) { @@ -799,7 +877,7 @@ static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, Event case kEventWindowZoomed: case kEventWindowBoundsChanged: break; - + default: result = eventNotHandledErr; } @@ -811,7 +889,7 @@ static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, Event case kEventMouseDown: { UInt16 button; - + GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); switch (button) { @@ -851,7 +929,7 @@ static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, Event case kEventMouseUp: { UInt16 button; - + GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); switch (button) { @@ -912,10 +990,10 @@ static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, Event unsigned int i_height = p_vout->p_sys->i_height; unsigned int i_width = p_vout->p_sys->i_width; - vout_PlacePicture(p_vout, i_width, i_height, &i_x, &i_y, &i_width, &i_height); + vout_PlacePicture(p_vout, i_width, i_height, &i_x, &i_y, &i_width, &i_height); GetEventParameter(event, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &ml); - + val.i_int = ( ((int)ml.h) - i_x ) * p_vout->render.i_width / i_width; var_Set( p_vout, "mouse-x", val ); @@ -930,7 +1008,7 @@ static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, Event break; } - + default: result = eventNotHandledErr; } @@ -974,7 +1052,7 @@ static int aglLock( vout_thread_t * p_vout ) #ifdef __ppc__ /* * before 10.4, we set the AGL context as current and - * then we retrieve and use the matching CGL context + * then we retrieve and use the matching CGL context */ aglSetCurrentContext(p_vout->p_sys->agl_ctx); return kCGLNoError != CGLLockContext( CGLGetCurrentContext() ); @@ -984,10 +1062,10 @@ static int aglLock( vout_thread_t * p_vout ) if( aglGetCGLContext(p_vout->p_sys->agl_ctx, (void**)&cglContext) ) { if( kCGLNoError == CGLLockContext( cglContext ) ) - { - aglSetCurrentContext(p_vout->p_sys->agl_ctx); - return 0; - } + { + aglSetCurrentContext(p_vout->p_sys->agl_ctx); + return 0; + } } return 1; #endif @@ -998,7 +1076,7 @@ static void aglUnlock( vout_thread_t * p_vout ) #ifdef __ppc__ /* * before 10.4, we assume that the AGL context is current. - * therefore, we use the current CGL context + * therefore, we use the current CGL context */ CGLUnlockContext( CGLGetCurrentContext() ); #else