Changeset 2db86f65c1e34d2c7c53473d92d7c5db98330b0d

Show
Ignore:
Timestamp:
12/03/07 00:08:15 (2 years ago)
Author:
Damien Fouilleul <damienf@videolan.org>
git-committer:
Damien Fouilleul <damienf@videolan.org> 1173654495 +0000
git-parent:

[b30bdcf7f67c4d436361a69ce254fe64a322eb71]

git-author:
Damien Fouilleul <damienf@videolan.org> 1173654495 +0000
Message:

- voutgl.m: misc cleanup, reworked context locking as well as enabling double buffering for faster rendering

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • modules/gui/macosx/voutgl.m

    r36bb24a r2db86f6  
    1111 *          Eric Petit <titer@m0k.org> 
    1212 *          Benjamin Pracht <bigben at videolan dot org> 
     13 *          Damien Fouilleul <damienf at videolan dot org> 
    1314 * 
    1415 * This program is free software; you can redistribute it and/or modify 
     
    6465    NSRect              s_frame; 
    6566    vlc_bool_t          b_got_frame; 
    66     vlc_mutex_t         lock; 
    6767    /* Mozilla plugin-related variables */ 
    6868    vlc_bool_t          b_embedded; 
     
    7171    int                 i_offx, i_offy; 
    7272    int                 i_width, i_height; 
     73    WindowRef           theWindow; 
     74    WindowGroupRef      winGroup; 
    7375}; 
    7476 
     
    9092static int  aglControl( vout_thread_t *, int, va_list ); 
    9193static void aglSwap   ( vout_thread_t * p_vout ); 
     94static int  aglLock   ( vout_thread_t * p_vout ); 
     95static void aglUnlock ( vout_thread_t * p_vout ); 
    9296 
    9397int E_(OpenVideoGL)  ( vlc_object_t * p_this ) 
     
    112116 
    113117    memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) ); 
    114  
    115     vlc_mutex_init( p_vout, &p_vout->p_sys->lock ); 
    116118 
    117119    var_Get( p_vout->p_libvlc, "drawable", &value_drawable ); 
     
    161163        p_vout->pf_control          = aglControl; 
    162164        p_vout->pf_swap             = aglSwap; 
    163         p_vout->pf_lock             = Lock; 
    164         p_vout->pf_unlock           = Unlock; 
     165        p_vout->pf_lock             = aglLock; 
     166        p_vout->pf_unlock           = aglUnlock; 
    165167    } 
    166168    else 
     
    211213    } 
    212214    /* Clean up */ 
    213     vlc_mutex_destroy( &p_vout->p_sys->lock ); 
    214215    free( p_vout->p_sys ); 
    215216} 
     
    283284{ 
    284285    p_vout->p_sys->b_got_frame = VLC_TRUE; 
    285     [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext]; 
    286     glFlush(); 
     286    [[p_vout->p_sys->o_glview openGLContext] flushBuffer]; 
    287287} 
    288288 
    289289static int Lock( vout_thread_t * p_vout ) 
    290290{ 
    291     vlc_mutex_lock( &p_vout->p_sys->lock ); 
    292     CGLLockContext( (CGLContextObj)p_vout->p_sys->agl_ctx ); 
    293     return 0; 
     291    if( kCGLNoError == CGLLockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]) ) 
     292    { 
     293    [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext]; 
     294    return 0; 
     295    } 
     296    return 1; 
    294297} 
    295298 
    296299static void Unlock( vout_thread_t * p_vout ) 
    297300{ 
    298     CGLUnlockContext( (CGLContextObj)p_vout->p_sys->agl_ctx ); 
    299     vlc_mutex_unlock( &p_vout->p_sys->lock ); 
     301    CGLUnlockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]); 
    300302} 
    301303 
     
    336338         
    337339    } 
    338      
    339     [[o_glview openGLContext] makeCurrentContext]; 
    340340#undef o_glview 
    341341} 
     
    347347    NSOpenGLPixelFormatAttribute attribs[] = 
    348348    { 
     349        NSOpenGLPFADoubleBuffer, 
    349350        NSOpenGLPFAAccelerated, 
    350351        NSOpenGLPFANoRecovery, 
     
    388389    NSRect bounds = [self bounds]; 
    389390 
    390     [[self openGLContext] makeCurrentContext]; 
    391  
    392391    var_Get( p_vout, "macosx-stretch", &val ); 
    393392    if( val.b_bool ) 
     
    447446{ 
    448447    Lock( p_vout ); 
    449     [[self openGLContext] makeCurrentContext]; 
    450     /* FIXME: we should use CGLFlushDrawable instead, as glFlush is pretty slow */ 
    451     glFlush(); 
     448    [[p_vout->p_sys->o_glview openGLContext] flushBuffer]; 
    452449    [super drawRect:rect]; 
    453450    Unlock( p_vout ); 
     
    462459static void aglSetViewport( vout_thread_t *p_vout, Rect viewBounds, Rect clipBounds ); 
    463460static void aglReshape( vout_thread_t * p_vout ); 
     461static OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData); 
    464462 
    465463static int aglInit( vout_thread_t * p_vout ) 
     
    491489    clipBounds.right = val.i_int; 
    492490 
     491    aglLock(p_vout); 
    493492    aglSetViewport(p_vout, viewBounds, clipBounds); 
    494  
    495     aglSetCurrentContext(p_vout->p_sys->agl_ctx); 
     493    aglReshape(p_vout); 
     494    aglUnlock(p_vout); 
     495     
    496496    return VLC_SUCCESS; 
    497497} 
     
    500500{ 
    501501    aglSetCurrentContext(NULL); 
     502    if( p_vout->p_sys->theWindow ) DisposeWindow( p_vout->p_sys->theWindow ); 
    502503} 
    503504 
     
    508509    unsigned int i_width  = p_vout->p_sys->i_width; 
    509510 
    510     Lock( p_vout ); 
    511  
    512511    vout_PlacePicture(p_vout, i_width, i_height, &x, &y, &i_width, &i_height);  
    513  
    514     aglSetCurrentContext(p_vout->p_sys->agl_ctx); 
    515512 
    516513    glViewport( p_vout->p_sys->i_offx + x, p_vout->p_sys->i_offy + y, i_width, i_height ); 
     
    521518        vout_thread_t * p_parent; 
    522519        p_parent = (vout_thread_t *) p_vout->p_parent; 
    523         Unlock( p_vout ); 
    524520        if( p_parent && p_parent->pf_display ) 
    525521        { 
     
    530526    { 
    531527        glClear( GL_COLOR_BUFFER_BIT ); 
    532         Unlock( p_vout ); 
     528    } 
     529
     530 
     531/* private event class */ 
     532enum  
     533
     534    kEventClassVLCPlugin = 'vlcp', 
     535}; 
     536/* private event kinds */ 
     537enum 
     538
     539    kEventVLCPluginShowFullscreen = 32768, 
     540    kEventVLCPluginHideFullscreen, 
     541}; 
     542 
     543static void sendEventToMainThread(EventTargetRef target, UInt32 class, UInt32 kind) 
     544
     545    EventRef myEvent; 
     546    if( noErr == CreateEvent(NULL, class, kind, 0, kEventAttributeNone, &myEvent) ) 
     547    { 
     548        if( noErr == SetEventParameter(myEvent, kEventParamPostTarget, typeEventTargetRef, sizeof(EventTargetRef), &target) ) 
     549        { 
     550            PostEventToQueue(GetMainEventQueue(), myEvent, kEventPriorityStandard); 
     551        } 
     552        ReleaseEvent(myEvent); 
    533553    } 
    534554} 
     
    538558    if( p_vout->i_changes & VOUT_ASPECT_CHANGE ) 
    539559    { 
     560        aglLock( p_vout ); 
    540561        aglReshape(p_vout); 
     562        aglUnlock( p_vout ); 
    541563        p_vout->i_changes &= ~VOUT_ASPECT_CHANGE; 
    542564    } 
    543565    if( p_vout->i_changes & VOUT_CROP_CHANGE ) 
    544566    { 
     567        aglLock( p_vout ); 
    545568        aglReshape(p_vout); 
     569        aglUnlock( p_vout ); 
    546570        p_vout->i_changes &= ~VOUT_CROP_CHANGE; 
    547571    } 
     572    if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) 
     573    { 
     574        aglSetDrawable(p_vout->p_sys->agl_ctx, NULL); 
     575        aglLock( p_vout ); 
     576        if( p_vout->b_fullscreen ) 
     577        { 
     578            /* Close the fullscreen window and resume normal drawing */ 
     579            vlc_value_t val; 
     580            Rect viewBounds;     
     581            Rect clipBounds; 
     582 
     583            var_Get( p_vout->p_libvlc, "drawable", &val ); 
     584            p_vout->p_sys->agl_drawable = (AGLDrawable)val.i_int; 
     585            aglSetDrawable(p_vout->p_sys->agl_ctx, p_vout->p_sys->agl_drawable); 
     586 
     587            var_Get( p_vout->p_libvlc, "drawable-view-top", &val ); 
     588            viewBounds.top = val.i_int; 
     589            var_Get( p_vout->p_libvlc, "drawable-view-left", &val ); 
     590            viewBounds.left = val.i_int; 
     591            var_Get( p_vout->p_libvlc, "drawable-view-bottom", &val ); 
     592            viewBounds.bottom = val.i_int; 
     593            var_Get( p_vout->p_libvlc, "drawable-view-right", &val ); 
     594            viewBounds.right = val.i_int; 
     595            var_Get( p_vout->p_libvlc, "drawable-clip-top", &val ); 
     596            clipBounds.top = val.i_int; 
     597            var_Get( p_vout->p_libvlc, "drawable-clip-left", &val ); 
     598            clipBounds.left = val.i_int; 
     599            var_Get( p_vout->p_libvlc, "drawable-clip-bottom", &val ); 
     600            clipBounds.bottom = val.i_int; 
     601            var_Get( p_vout->p_libvlc, "drawable-clip-right", &val ); 
     602            clipBounds.right = val.i_int; 
     603 
     604            aglSetCurrentContext(p_vout->p_sys->agl_ctx); 
     605            aglSetViewport(p_vout, viewBounds, clipBounds); 
     606 
     607            /* Most Carbon APIs are not thread-safe, therefore delagate some GUI visibilty update to the main thread */ 
     608            sendEventToMainThread(GetWindowEventTarget(p_vout->p_sys->theWindow), kEventClassVLCPlugin, kEventVLCPluginHideFullscreen); 
     609        } 
     610        else 
     611        { 
     612            Rect deviceRect; 
     613             
     614            GDHandle deviceHdl = GetMainDevice(); 
     615            deviceRect = (*deviceHdl)->gdRect; 
     616             
     617            if( !p_vout->p_sys->theWindow ) 
     618            { 
     619                /* Create a window */ 
     620                WindowAttributes    windowAttrs; 
     621 
     622                windowAttrs = kWindowStandardDocumentAttributes 
     623                            | kWindowStandardHandlerAttribute 
     624                            | kWindowLiveResizeAttribute 
     625                            | kWindowNoShadowAttribute; 
     626                                             
     627                windowAttrs &= (~kWindowResizableAttribute); 
     628 
     629                CreateNewWindow(kDocumentWindowClass, windowAttrs, &deviceRect, &p_vout->p_sys->theWindow); 
     630                if( !p_vout->p_sys->winGroup ) 
     631                { 
     632                    CreateWindowGroup(0, &p_vout->p_sys->winGroup); 
     633                    SetWindowGroup(p_vout->p_sys->theWindow, p_vout->p_sys->winGroup); 
     634                    SetWindowGroupParent( p_vout->p_sys->winGroup, GetWindowGroupOfClass(kDocumentWindowClass) ) ; 
     635                } 
     636                 
     637                // Window title 
     638                CFStringRef titleKey    = CFSTR("Fullscreen VLC media plugin"); 
     639                CFStringRef windowTitle = CFCopyLocalizedString(titleKey, NULL); 
     640                SetWindowTitleWithCFString(p_vout->p_sys->theWindow, windowTitle); 
     641                CFRelease(titleKey); 
     642                CFRelease(windowTitle); 
     643                 
     644                //Install event handler 
     645                static const EventTypeSpec win_events[] = { 
     646                    { kEventClassMouse, kEventMouseDown }, 
     647                    { kEventClassMouse, kEventMouseMoved }, 
     648                    { kEventClassMouse, kEventMouseUp }, 
     649                    { kEventClassWindow, kEventWindowClosed }, 
     650                    { kEventClassWindow, kEventWindowBoundsChanged }, 
     651                    { kEventClassCommand, kEventCommandProcess }, 
     652                    { kEventClassVLCPlugin, kEventVLCPluginShowFullscreen }, 
     653                    { kEventClassVLCPlugin, kEventVLCPluginHideFullscreen }, 
     654                }; 
     655                InstallWindowEventHandler (p_vout->p_sys->theWindow, NewEventHandlerUPP (WindowEventHandler), GetEventTypeCount(win_events), win_events, p_vout, NULL); 
     656            } 
     657            else 
     658            { 
     659                /* just in case device resolution changed */ 
     660                SetWindowBounds(p_vout->p_sys->theWindow, kWindowContentRgn, &deviceRect); 
     661            } 
     662            glClear( GL_COLOR_BUFFER_BIT ); 
     663            p_vout->p_sys->agl_drawable = (AGLDrawable)GetWindowPort(p_vout->p_sys->theWindow); 
     664            aglSetDrawable(p_vout->p_sys->agl_ctx, p_vout->p_sys->agl_drawable); 
     665            aglSetCurrentContext(p_vout->p_sys->agl_ctx); 
     666            aglSetViewport(p_vout, deviceRect, deviceRect); 
     667            //aglSetFullScreen(p_vout->p_sys->agl_ctx, device_width, device_height, 0, 0); 
     668 
     669            /* Most Carbon APIs are not thread-safe, therefore delagate some GUI visibilty update to the main thread */ 
     670            sendEventToMainThread(GetWindowEventTarget(p_vout->p_sys->theWindow), kEventClassVLCPlugin, kEventVLCPluginShowFullscreen); 
     671        } 
     672        aglReshape(p_vout); 
     673        aglUnlock( p_vout ); 
     674        p_vout->b_fullscreen = !p_vout->b_fullscreen; 
     675        p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; 
     676    } 
    548677    return VLC_SUCCESS; 
    549678} 
     
    554683    { 
    555684        case VOUT_SET_VIEWPORT: 
    556    
    557        Rect viewBounds, clipBounds; 
     685       
     686            Rect viewBounds, clipBounds; 
    558687            viewBounds.top = va_arg( args, int); 
    559688            viewBounds.left = va_arg( args, int); 
     
    564693            clipBounds.bottom = va_arg( args, int); 
    565694            clipBounds.right = va_arg( args, int); 
    566         aglSetViewport(p_vout, viewBounds, clipBounds); 
     695             
     696            if( !p_vout->b_fullscreen )  
     697            { 
     698                aglLock( p_vout ); 
     699                aglSetViewport(p_vout, viewBounds, clipBounds); 
     700                aglReshape( p_vout ); 
     701                aglUnlock( p_vout ); 
     702            } 
    567703            return VLC_SUCCESS; 
    568    
     704       
    569705 
    570706        case VOUT_REPARENT: 
    571    
    572        AGLDrawable drawable = (AGLDrawable)va_arg( args, int); 
    573        if( drawable != p_vout->p_sys->agl_drawable ) 
    574        { 
    575        p_vout->p_sys->agl_drawable = drawable; 
    576        aglSetDrawable(p_vout->p_sys->agl_ctx, drawable); 
    577        } 
     707       
     708            AGLDrawable drawable = (AGLDrawable)va_arg( args, int); 
     709            if( !p_vout->b_fullscreen && drawable != p_vout->p_sys->agl_drawable ) 
     710            { 
     711                p_vout->p_sys->agl_drawable = drawable; 
     712                aglSetDrawable(p_vout->p_sys->agl_ctx, drawable); 
     713            } 
    578714            return VLC_SUCCESS; 
    579    
     715       
    580716 
    581717        default: 
     
    590726} 
    591727 
     728/* Enter this function with the p_vout locked */ 
    592729static void aglSetViewport( vout_thread_t *p_vout, Rect viewBounds, Rect clipBounds ) 
    593730{ 
     
    623760 
    624761    aglUpdateContext(p_vout->p_sys->agl_ctx); 
    625     aglReshape( p_vout ); 
    626 
    627  
     762
     763 
     764//default window event handler 
     765static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData) 
     766
     767    OSStatus result = noErr; 
     768    UInt32 class = GetEventClass (event); 
     769    UInt32 kind = GetEventKind (event);  
     770    vout_thread_t *p_vout = (vout_thread_t *)userData; 
     771 
     772    result = CallNextEventHandler(nextHandler, event); 
     773    if(class == kEventClassCommand) 
     774    { 
     775        HICommand theHICommand; 
     776        GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof( HICommand ), NULL, &theHICommand ); 
     777         
     778        switch ( theHICommand.commandID ) 
     779        { 
     780            default: 
     781                result = eventNotHandledErr; 
     782        } 
     783    } 
     784    else if(class == kEventClassWindow) 
     785    { 
     786        WindowRef     window; 
     787        Rect          rectPort = {0,0,0,0}; 
     788         
     789        GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window); 
     790 
     791        if(window) 
     792        { 
     793            GetPortBounds(GetWindowPort(window), &rectPort); 
     794        }    
     795 
     796        switch (kind) 
     797        { 
     798            case kEventWindowClosed: 
     799            case kEventWindowZoomed: 
     800            case kEventWindowBoundsChanged: 
     801                break; 
     802             
     803            default: 
     804                result = eventNotHandledErr; 
     805        } 
     806    } 
     807    else if(class == kEventClassMouse) 
     808    { 
     809        switch (kind) 
     810        { 
     811            case kEventMouseDown: 
     812            { 
     813                UInt16     button; 
     814         
     815                GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); 
     816                switch (button) 
     817                { 
     818                    case kEventMouseButtonPrimary: 
     819                    { 
     820                        vlc_value_t val; 
     821 
     822                        var_Get( p_vout, "mouse-button-down", &val ); 
     823                        val.i_int |= 1; 
     824                        var_Set( p_vout, "mouse-button-down", val ); 
     825                        break; 
     826                    } 
     827                    case kEventMouseButtonSecondary: 
     828                    { 
     829                        vlc_value_t val; 
     830 
     831                        var_Get( p_vout, "mouse-button-down", &val ); 
     832                        val.i_int |= 2; 
     833                        var_Set( p_vout, "mouse-button-down", val ); 
     834                        break; 
     835                    } 
     836                    case kEventMouseButtonTertiary: 
     837                    { 
     838                        vlc_value_t val; 
     839 
     840                        var_Get( p_vout, "mouse-button-down", &val ); 
     841                        val.i_int |= 4; 
     842                        var_Set( p_vout, "mouse-button-down", val ); 
     843                        break; 
     844                    } 
     845                    default: 
     846                        result = eventNotHandledErr; 
     847                } 
     848                break; 
     849            } 
     850 
     851            case kEventMouseUp: 
     852            { 
     853                UInt16     button; 
     854         
     855                GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); 
     856                switch (button) 
     857                { 
     858                    case kEventMouseButtonPrimary: 
     859                    { 
     860                        UInt32 clickCount = 0; 
     861                        GetEventParameter(event, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount); 
     862                        if( clickCount > 1 ) 
     863                        { 
     864                            vlc_value_t val; 
     865 
     866                            val.b_bool = VLC_FALSE; 
     867                            var_Set((vout_thread_t *) p_vout->p_parent, "fullscreen", val); 
     868                        } 
     869                        else 
     870                        { 
     871                            vlc_value_t val; 
     872 
     873                            val.b_bool = VLC_TRUE; 
     874                            var_Set( p_vout, "mouse-clicked", val ); 
     875 
     876                            var_Get( p_vout, "mouse-button-down", &val ); 
     877                            val.i_int &= ~1; 
     878                            var_Set( p_vout, "mouse-button-down", val ); 
     879                        } 
     880                        break; 
     881                    } 
     882                    case kEventMouseButtonSecondary: 
     883                    { 
     884                        vlc_value_t val; 
     885 
     886                        var_Get( p_vout, "mouse-button-down", &val ); 
     887                        val.i_int &= ~2; 
     888                        var_Set( p_vout, "mouse-button-down", val ); 
     889                        break; 
     890                    } 
     891                    case kEventMouseButtonTertiary: 
     892                    { 
     893                        vlc_value_t val; 
     894 
     895                        var_Get( p_vout, "mouse-button-down", &val ); 
     896                        val.i_int &= ~2; 
     897                        var_Set( p_vout, "mouse-button-down", val ); 
     898                        break; 
     899                    } 
     900                    default: 
     901                        result = eventNotHandledErr; 
     902                } 
     903                break; 
     904            } 
     905 
     906            case kEventMouseMoved: 
     907            { 
     908                Point ml; 
     909                vlc_value_t val; 
     910 
     911                unsigned int i_x, i_y; 
     912                unsigned int i_height = p_vout->p_sys->i_height; 
     913                unsigned int i_width  = p_vout->p_sys->i_width; 
     914 
     915                vout_PlacePicture(p_vout, i_width, i_height, &i_x, &i_y, &i_width, &i_height);  
     916 
     917                GetEventParameter(event, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &ml); 
     918                 
     919                val.i_int = ( ((int)ml.h) - i_x ) * 
     920                            p_vout->render.i_width / i_width; 
     921                var_Set( p_vout, "mouse-x", val ); 
     922 
     923                val.i_int = ( ((int)ml.v) - i_y ) * 
     924                            p_vout->render.i_height / i_height; 
     925 
     926                var_Set( p_vout, "mouse-y", val ); 
     927 
     928                val.b_bool = VLC_TRUE; 
     929                var_Set( p_vout, "mouse-moved", val ); 
     930 
     931                break; 
     932            } 
     933             
     934            default: 
     935                result = eventNotHandledErr; 
     936        } 
     937    } 
     938    else if(class == kEventClassTextInput) 
     939    { 
     940        switch (kind) 
     941        { 
     942            case kEventTextInputUnicodeForKeyEvent: 
     943            { 
     944                break; 
     945            } 
     946            default: 
     947                result = eventNotHandledErr; 
     948        } 
     949    } 
     950    else if(class == kEventClassVLCPlugin) 
     951    { 
     952        switch (kind) 
     953        { 
     954            case kEventVLCPluginShowFullscreen: 
     955                ShowWindow (p_vout->p_sys->theWindow); 
     956                SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar); 
     957                //CGDisplayHideCursor(kCGDirectMainDisplay); 
     958                break; 
     959            case kEventVLCPluginHideFullscreen: 
     960                HideWindow (p_vout->p_sys->theWindow); 
     961                SetSystemUIMode( kUIModeNormal, 0); 
     962                CGDisplayShowCursor(kCGDirectMainDisplay); 
     963                break; 
     964            default: 
     965                result = eventNotHandledErr; 
     966                break; 
     967        } 
     968    } 
     969    return result; 
     970
     971 
     972static int aglLock( vout_thread_t * p_vout ) 
     973
     974#ifdef __ppc__ 
     975    /* 
     976     * before 10.4, we set the AGL context as current and 
     977     * then we retrieve and use the matching CGL context  
     978     */ 
     979    aglSetCurrentContext(p_vout->p_sys->agl_ctx); 
     980    return kCGLNoError != CGLLockContext( CGLGetCurrentContext() ); 
     981#else 
     982    /* since 10.4, this is the safe way to get the underlying CGL context */ 
     983    CGLContextObj cglContext; 
     984    if( aglGetCGLContext(p_vout->p_sys->agl_ctx, (void**)&cglContext) ) 
     985    { 
     986        if( kCGLNoError == CGLLockContext( cglContext ) ) 
     987    { 
     988        aglSetCurrentContext(p_vout->p_sys->agl_ctx); 
     989        return 0; 
     990    } 
     991    } 
     992    return 1; 
     993#endif 
     994
     995 
     996static void aglUnlock( vout_thread_t * p_vout ) 
     997
     998#ifdef __ppc__ 
     999    /* 
     1000     * before 10.4, we assume that the AGL context is current. 
     1001     * therefore, we use the current CGL context  
     1002     */ 
     1003    CGLUnlockContext( CGLGetCurrentContext() ); 
     1004#else 
     1005    /* since 10.4, this is the safe way to get the underlying CGL context */ 
     1006    CGLContextObj cglContext; 
     1007    if( aglGetCGLContext(p_vout->p_sys->agl_ctx, (void**)&cglContext) ) 
     1008    { 
     1009        CGLUnlockContext( cglContext ); 
     1010    } 
     1011#endif 
     1012
     1013 
     1014