]> git.sesse.net Git - vlc/blob - modules/gui/minimal_macosx/voutagl.m
848dd0df0c5e2b8ec742af48d2a395f9e3a7dcc7
[vlc] / modules / gui / minimal_macosx / voutagl.m
1 /*****************************************************************************
2  * voutagl.c: MacOS X agl OpenGL provider (used by webbrowser.plugin)
3  *****************************************************************************
4  * Copyright (C) 2001-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Colin Delacroix <colin@zoy.org>
8  *          Florian G. Pflug <fgp@phlo.org>
9  *          Jon Lech Johansen <jon-vl@nanocrew.net>
10  *          Derk-Jan Hartman <hartman at videolan dot org>
11  *          Eric Petit <titer@m0k.org>
12  *          Benjamin Pracht <bigben at videolan dot org>
13  *          Damien Fouilleul <damienf 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 #include "intf.h"
31 #include "voutgl.h"
32 #include "voutagl.h"
33
34 /*****************************************************************************
35  * embedded AGL context implementation
36  *****************************************************************************/
37
38 static void aglSetViewport( vout_thread_t *p_vout, Rect viewBounds, Rect clipBounds );
39 static void aglReshape( vout_thread_t * p_vout );
40 static OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
41
42 int aglInit( vout_thread_t * p_vout )
43 {
44     vlc_value_t val;
45
46     Rect viewBounds;
47     Rect clipBounds;
48
49     static const GLint ATTRIBUTES[] = {
50         AGL_WINDOW,
51         AGL_RGBA,
52         AGL_NO_RECOVERY,
53         AGL_ACCELERATED,
54         AGL_DOUBLEBUFFER,
55         AGL_RED_SIZE,   8,
56         AGL_GREEN_SIZE, 8,
57         AGL_BLUE_SIZE,  8,
58         AGL_ALPHA_SIZE, 8,
59         AGL_DEPTH_SIZE, 24,
60         AGL_NONE };
61
62     AGLPixelFormat pixFormat;
63
64     p_vout->p_sys->b_embedded = true;
65
66     pixFormat = aglChoosePixelFormat(NULL, 0, ATTRIBUTES);
67     if( NULL == pixFormat )
68     {
69         msg_Err( p_vout, "No screen renderer available for required attributes." );
70         return VLC_EGENERIC;
71     }
72  
73     p_vout->p_sys->agl_ctx = aglCreateContext(pixFormat, NULL);
74     aglDestroyPixelFormat(pixFormat);
75     if( NULL == p_vout->p_sys->agl_ctx )
76     {
77         msg_Err( p_vout, "Cannot create AGL context." );
78         return VLC_EGENERIC;
79     }
80     else
81     {
82         // tell opengl not to sync buffer swap with vertical retrace (too inefficient)
83         GLint param = 0;
84         aglSetInteger(p_vout->p_sys->agl_ctx, AGL_SWAP_INTERVAL, &param);
85         aglEnable(p_vout->p_sys->agl_ctx, AGL_SWAP_INTERVAL);
86     }
87
88     var_Get( p_vout->p_libvlc, "drawable-agl", &val );
89     p_vout->p_sys->agl_drawable = (AGLDrawable)val.i_int;
90     aglSetDrawable(p_vout->p_sys->agl_ctx, p_vout->p_sys->agl_drawable);
91
92     var_Get( p_vout->p_libvlc, "drawable-view-top", &val );
93     viewBounds.top = val.i_int;
94     var_Get( p_vout->p_libvlc, "drawable-view-left", &val );
95     viewBounds.left = val.i_int;
96     var_Get( p_vout->p_libvlc, "drawable-view-bottom", &val );
97     viewBounds.bottom = val.i_int;
98     var_Get( p_vout->p_libvlc, "drawable-view-right", &val );
99     viewBounds.right = val.i_int;
100     var_Get( p_vout->p_libvlc, "drawable-clip-top", &val );
101     clipBounds.top = val.i_int;
102     var_Get( p_vout->p_libvlc, "drawable-clip-left", &val );
103     clipBounds.left = val.i_int;
104     var_Get( p_vout->p_libvlc, "drawable-clip-bottom", &val );
105     clipBounds.bottom = val.i_int;
106     var_Get( p_vout->p_libvlc, "drawable-clip-right", &val );
107     clipBounds.right = val.i_int;
108
109     p_vout->p_sys->b_clipped_out = (clipBounds.top == clipBounds.bottom)
110                                  || (clipBounds.left == clipBounds.right);
111     if( ! p_vout->p_sys->b_clipped_out )
112     {
113         aglLock(p_vout);
114         aglSetViewport(p_vout, viewBounds, clipBounds);
115         aglReshape(p_vout);
116         aglUnlock(p_vout);
117     }
118     p_vout->p_sys->clipBounds = clipBounds;
119     p_vout->p_sys->viewBounds = viewBounds;
120
121     return VLC_SUCCESS;
122 }
123
124 void aglEnd( vout_thread_t * p_vout )
125 {
126     aglSetCurrentContext(NULL);
127     if( p_vout->p_sys->theWindow )
128         DisposeWindow( p_vout->p_sys->theWindow );
129     aglDestroyContext(p_vout->p_sys->agl_ctx);
130 }
131
132 void aglReshape( vout_thread_t * p_vout )
133 {
134     unsigned int x, y;
135     unsigned int i_height = p_vout->p_sys->i_height;
136     unsigned int i_width  = p_vout->p_sys->i_width;
137
138     vout_PlacePicture(p_vout, i_width, i_height, &x, &y, &i_width, &i_height);
139
140     glViewport( p_vout->p_sys->i_offx + x, p_vout->p_sys->i_offy + y, i_width, i_height );
141
142     if( p_vout->p_sys->b_got_frame )
143     {
144         /* Ask the opengl module to redraw */
145         vout_thread_t * p_parent;
146         p_parent = (vout_thread_t *) p_vout->p_parent;
147         if( p_parent && p_parent->pf_display )
148         {
149             p_parent->pf_display( p_parent, NULL );
150         }
151     }
152     else
153     {
154         glClear( GL_COLOR_BUFFER_BIT );
155     }
156 }
157
158 /* private event class */
159 enum
160 {
161     kEventClassVLCPlugin = 'vlcp',
162 };
163 /* private event kinds */
164 enum
165 {
166     kEventVLCPluginShowFullscreen = 32768,
167     kEventVLCPluginHideFullscreen,
168 };
169
170 static void sendEventToMainThread(EventTargetRef target, UInt32 class, UInt32 kind)
171 {
172     EventRef myEvent;
173     if( noErr == CreateEvent(NULL, class, kind, 0, kEventAttributeNone, &myEvent) )
174     {
175         if( noErr == SetEventParameter(myEvent, kEventParamPostTarget, typeEventTargetRef, sizeof(EventTargetRef), &target) )
176         {
177             PostEventToQueue(GetMainEventQueue(), myEvent, kEventPriorityStandard);
178         }
179         ReleaseEvent(myEvent);
180     }
181 }
182
183 int aglManage( vout_thread_t * p_vout )
184 {
185     if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
186     {
187         aglLock( p_vout );
188         aglReshape(p_vout);
189         aglUnlock( p_vout );
190         p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
191     }
192     if( p_vout->i_changes & VOUT_CROP_CHANGE )
193     {
194         aglLock( p_vout );
195         aglReshape(p_vout);
196         aglUnlock( p_vout );
197         p_vout->i_changes &= ~VOUT_CROP_CHANGE;
198     }
199     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
200     {
201         aglSetDrawable(p_vout->p_sys->agl_ctx, NULL);
202         aglLock( p_vout );
203         if( p_vout->b_fullscreen )
204         {
205             /* Close the fullscreen window and resume normal drawing */
206             vlc_value_t val;
207             Rect viewBounds;
208             Rect clipBounds;
209
210             var_Get( p_vout->p_libvlc, "drawable-agl", &val );
211             p_vout->p_sys->agl_drawable = (AGLDrawable)val.i_int;
212             aglSetDrawable(p_vout->p_sys->agl_ctx, p_vout->p_sys->agl_drawable);
213
214             var_Get( p_vout->p_libvlc, "drawable-view-top", &val );
215             viewBounds.top = val.i_int;
216             var_Get( p_vout->p_libvlc, "drawable-view-left", &val );
217             viewBounds.left = val.i_int;
218             var_Get( p_vout->p_libvlc, "drawable-view-bottom", &val );
219             viewBounds.bottom = val.i_int;
220             var_Get( p_vout->p_libvlc, "drawable-view-right", &val );
221             viewBounds.right = val.i_int;
222             var_Get( p_vout->p_libvlc, "drawable-clip-top", &val );
223             clipBounds.top = val.i_int;
224             var_Get( p_vout->p_libvlc, "drawable-clip-left", &val );
225             clipBounds.left = val.i_int;
226             var_Get( p_vout->p_libvlc, "drawable-clip-bottom", &val );
227             clipBounds.bottom = val.i_int;
228             var_Get( p_vout->p_libvlc, "drawable-clip-right", &val );
229             clipBounds.right = val.i_int;
230
231             aglSetCurrentContext(p_vout->p_sys->agl_ctx);
232             aglSetViewport(p_vout, viewBounds, clipBounds);
233
234             /* Most Carbon APIs are not thread-safe, therefore delagate some GUI visibilty update to the main thread */
235             sendEventToMainThread(GetWindowEventTarget(p_vout->p_sys->theWindow), kEventClassVLCPlugin, kEventVLCPluginHideFullscreen);
236         }
237         else
238         {
239             Rect deviceRect;
240  
241             GDHandle deviceHdl = GetMainDevice();
242             deviceRect = (*deviceHdl)->gdRect;
243  
244             if( !p_vout->p_sys->theWindow )
245             {
246                 /* Create a window */
247                 WindowAttributes    windowAttrs;
248
249                 windowAttrs = kWindowStandardDocumentAttributes
250                             | kWindowStandardHandlerAttribute
251                             | kWindowLiveResizeAttribute
252                             | kWindowNoShadowAttribute;
253  
254                 windowAttrs &= (~kWindowResizableAttribute);
255
256                 CreateNewWindow(kDocumentWindowClass, windowAttrs, &deviceRect, &p_vout->p_sys->theWindow);
257                 if( !p_vout->p_sys->winGroup )
258                 {
259                     CreateWindowGroup(0, &p_vout->p_sys->winGroup);
260                     SetWindowGroup(p_vout->p_sys->theWindow, p_vout->p_sys->winGroup);
261                     SetWindowGroupParent( p_vout->p_sys->winGroup, GetWindowGroupOfClass(kDocumentWindowClass) ) ;
262                 }
263  
264                 // Window title
265                 CFStringRef titleKey    = CFSTR("Fullscreen VLC media plugin");
266                 CFStringRef windowTitle = CFCopyLocalizedString(titleKey, NULL);
267                 SetWindowTitleWithCFString(p_vout->p_sys->theWindow, windowTitle);
268                 CFRelease(titleKey);
269                 CFRelease(windowTitle);
270  
271                 //Install event handler
272                 static const EventTypeSpec win_events[] = {
273                     { kEventClassMouse, kEventMouseDown },
274                     { kEventClassMouse, kEventMouseMoved },
275                     { kEventClassMouse, kEventMouseUp },
276                     { kEventClassWindow, kEventWindowClosed },
277                     { kEventClassWindow, kEventWindowBoundsChanged },
278                     { kEventClassCommand, kEventCommandProcess },
279                     { kEventClassVLCPlugin, kEventVLCPluginShowFullscreen },
280                     { kEventClassVLCPlugin, kEventVLCPluginHideFullscreen },
281                 };
282                 InstallWindowEventHandler (p_vout->p_sys->theWindow, NewEventHandlerUPP (WindowEventHandler), GetEventTypeCount(win_events), win_events, p_vout, NULL);
283             }
284             else
285             {
286                 /* just in case device resolution changed */
287                 SetWindowBounds(p_vout->p_sys->theWindow, kWindowContentRgn, &deviceRect);
288             }
289             glClear( GL_COLOR_BUFFER_BIT );
290             p_vout->p_sys->agl_drawable = (AGLDrawable)GetWindowPort(p_vout->p_sys->theWindow);
291             aglSetDrawable(p_vout->p_sys->agl_ctx, p_vout->p_sys->agl_drawable);
292             aglSetCurrentContext(p_vout->p_sys->agl_ctx);
293             aglSetViewport(p_vout, deviceRect, deviceRect);
294             //aglSetFullScreen(p_vout->p_sys->agl_ctx, device_width, device_height, 0, 0);
295
296             /* Most Carbon APIs are not thread-safe, therefore delagate some GUI visibilty update to the main thread */
297             sendEventToMainThread(GetWindowEventTarget(p_vout->p_sys->theWindow), kEventClassVLCPlugin, kEventVLCPluginShowFullscreen);
298         }
299         aglReshape(p_vout);
300         aglUnlock( p_vout );
301         p_vout->b_fullscreen = !p_vout->b_fullscreen;
302         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
303     }
304     return VLC_SUCCESS;
305 }
306
307 int aglControl( vout_thread_t *p_vout, int i_query, va_list args )
308 {
309     switch( i_query )
310     {
311         case VOUT_SET_VIEWPORT:
312         {
313             Rect viewBounds, clipBounds;
314             viewBounds.top = va_arg( args, int);
315             viewBounds.left = va_arg( args, int);
316             viewBounds.bottom = va_arg( args, int);
317             viewBounds.right = va_arg( args, int);
318             clipBounds.top = va_arg( args, int);
319             clipBounds.left = va_arg( args, int);
320             clipBounds.bottom = va_arg( args, int);
321             clipBounds.right = va_arg( args, int);
322  
323             if( !p_vout->b_fullscreen )
324             {
325                 /*
326                 ** check that the clip rect is not empty, as this is used
327                 ** by Firefox to prevent a plugin from displaying during
328                 ** a scrolling event. In this case we just prevent buffers
329                 ** from being swapped and ignore clipping as this is less
330                 ** disruptive than a GL geometry change
331                 */
332
333                 p_vout->p_sys->b_clipped_out = (clipBounds.top == clipBounds.bottom)
334                                              || (clipBounds.left == clipBounds.right);
335                 if( ! p_vout->p_sys->b_clipped_out )
336                 {
337                     /* ignore consecutive viewport update with identical parameters */
338                     if( memcmp(&clipBounds, &(p_vout->p_sys->clipBounds), sizeof(clipBounds) )
339                      && memcmp(&viewBounds, &(p_vout->p_sys->viewBounds), sizeof(viewBounds)) )
340                     {
341                         aglLock( p_vout );
342                         aglSetViewport(p_vout, viewBounds, clipBounds);
343                         aglReshape( p_vout );
344                         aglUnlock( p_vout );
345                         p_vout->p_sys->clipBounds = clipBounds;
346                         p_vout->p_sys->viewBounds = viewBounds;
347                     }
348                 }
349             }
350             return VLC_SUCCESS;
351         }
352
353         case VOUT_REDRAW_RECT:
354         {
355             vout_thread_t * p_parent;
356             Rect areaBounds;
357
358             areaBounds.top = va_arg( args, int);
359             areaBounds.left = va_arg( args, int);
360             areaBounds.bottom = va_arg( args, int);
361             areaBounds.right = va_arg( args, int);
362
363             /* Ask the opengl module to redraw */
364             p_parent = (vout_thread_t *) p_vout->p_parent;
365             if( p_parent && p_parent->pf_display )
366             {
367                 p_parent->pf_display( p_parent, NULL );
368             }
369             return VLC_SUCCESS;
370         }
371
372         default:
373             return VLC_EGENERIC;
374     }
375 }
376
377 void aglSwap( vout_thread_t * p_vout )
378 {
379     if( ! p_vout->p_sys->b_clipped_out )
380     {
381         p_vout->p_sys->b_got_frame = true;
382         aglSwapBuffers(p_vout->p_sys->agl_ctx);
383     }
384     else
385     {
386         /* drop frame */
387         glFlush();
388     }
389 }
390
391 /* Enter this function with the p_vout locked */
392 static void aglSetViewport( vout_thread_t *p_vout, Rect viewBounds, Rect clipBounds )
393 {
394     // mozilla plugin provides coordinates based on port bounds
395     // however AGL coordinates are based on window structure region
396     // and are vertically flipped
397     GLint rect[4];
398     CGrafPtr port = (CGrafPtr)p_vout->p_sys->agl_drawable;
399     Rect winBounds, clientBounds;
400
401     GetWindowBounds(GetWindowFromPort(port),
402         kWindowStructureRgn, &winBounds);
403     GetWindowBounds(GetWindowFromPort(port),
404         kWindowContentRgn, &clientBounds);
405
406     /* update video clipping bounds in drawable */
407     rect[0] = (clientBounds.left-winBounds.left)
408             + clipBounds.left;                  // from window left edge
409     rect[1] = (winBounds.bottom-winBounds.top)
410             - (clientBounds.top-winBounds.top)
411             - clipBounds.bottom;                // from window bottom edge
412     rect[2] = clipBounds.right-clipBounds.left; // width
413     rect[3] = clipBounds.bottom-clipBounds.top; // height
414     aglSetInteger(p_vout->p_sys->agl_ctx, AGL_BUFFER_RECT, rect);
415     aglEnable(p_vout->p_sys->agl_ctx, AGL_BUFFER_RECT);
416
417     /* update video internal bounds in drawable */
418     p_vout->p_sys->i_width  = viewBounds.right-viewBounds.left;
419     p_vout->p_sys->i_height = viewBounds.bottom-viewBounds.top;
420     p_vout->p_sys->i_offx   = -clipBounds.left - viewBounds.left;
421     p_vout->p_sys->i_offy   = clipBounds.bottom + viewBounds.top
422                             - p_vout->p_sys->i_height;
423
424     aglUpdateContext(p_vout->p_sys->agl_ctx);
425 }
426
427 //default window event handler
428 static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
429 {
430     OSStatus result = noErr;
431     UInt32 class = GetEventClass (event);
432     UInt32 kind = GetEventKind (event);
433     vout_thread_t *p_vout = (vout_thread_t *)userData;
434
435     result = CallNextEventHandler(nextHandler, event);
436     if(class == kEventClassCommand)
437     {
438         HICommand theHICommand;
439         GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof( HICommand ), NULL, &theHICommand );
440  
441         switch ( theHICommand.commandID )
442         {
443             default:
444                 result = eventNotHandledErr;
445         }
446     }
447     else if(class == kEventClassWindow)
448     {
449         WindowRef     window;
450         Rect          rectPort = {0,0,0,0};
451  
452         GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window);
453
454         if(window)
455         {
456             GetPortBounds(GetWindowPort(window), &rectPort);
457         }
458
459         switch (kind)
460         {
461             case kEventWindowClosed:
462             case kEventWindowZoomed:
463             case kEventWindowBoundsChanged:
464                 break;
465  
466             default:
467                 result = eventNotHandledErr;
468         }
469     }
470     else if(class == kEventClassMouse)
471     {
472         switch (kind)
473         {
474             case kEventMouseDown:
475             {
476                 UInt16     button;
477  
478                 GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
479                 switch (button)
480                 {
481                     case kEventMouseButtonPrimary:
482                     {
483                         vlc_value_t val;
484
485                         var_Get( p_vout, "mouse-button-down", &val );
486                         val.i_int |= 1;
487                         var_Set( p_vout, "mouse-button-down", val );
488                         break;
489                     }
490                     case kEventMouseButtonSecondary:
491                     {
492                         vlc_value_t val;
493
494                         var_Get( p_vout, "mouse-button-down", &val );
495                         val.i_int |= 2;
496                         var_Set( p_vout, "mouse-button-down", val );
497                         break;
498                     }
499                     case kEventMouseButtonTertiary:
500                     {
501                         vlc_value_t val;
502
503                         var_Get( p_vout, "mouse-button-down", &val );
504                         val.i_int |= 4;
505                         var_Set( p_vout, "mouse-button-down", val );
506                         break;
507                     }
508                     default:
509                         result = eventNotHandledErr;
510                 }
511                 break;
512             }
513
514             case kEventMouseUp:
515             {
516                 UInt16     button;
517  
518                 GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
519                 switch (button)
520                 {
521                     case kEventMouseButtonPrimary:
522                     {
523                         UInt32 clickCount = 0;
524                         GetEventParameter(event, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount);
525                         if( clickCount > 1 )
526                         {
527                             vlc_value_t val;
528
529                             val.b_bool = false;
530                             var_Set((vout_thread_t *) p_vout->p_parent, "fullscreen", val);
531                         }
532                         else
533                         {
534                             vlc_value_t val;
535
536                             var_SetBool( p_vout, "mouse-clicked", true );
537
538                             var_Get( p_vout, "mouse-button-down", &val );
539                             val.i_int &= ~1;
540                             var_Set( p_vout, "mouse-button-down", val );
541                         }
542                         break;
543                     }
544                     case kEventMouseButtonSecondary:
545                     {
546                         vlc_value_t val;
547
548                         var_Get( p_vout, "mouse-button-down", &val );
549                         val.i_int &= ~2;
550                         var_Set( p_vout, "mouse-button-down", val );
551                         break;
552                     }
553                     case kEventMouseButtonTertiary:
554                     {
555                         vlc_value_t val;
556
557                         var_Get( p_vout, "mouse-button-down", &val );
558                         val.i_int &= ~2;
559                         var_Set( p_vout, "mouse-button-down", val );
560                         break;
561                     }
562                     default:
563                         result = eventNotHandledErr;
564                 }
565                 break;
566             }
567
568             case kEventMouseMoved:
569             {
570                 Point ml;
571                 vlc_value_t val;
572
573                 unsigned int i_x, i_y;
574                 unsigned int i_height = p_vout->p_sys->i_height;
575                 unsigned int i_width  = p_vout->p_sys->i_width;
576
577                 vout_PlacePicture(p_vout, i_width, i_height, &i_x, &i_y, &i_width, &i_height);
578
579                 GetEventParameter(event, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &ml);
580  
581                 val.i_int = ( ((int)ml.h) - i_x ) *
582                             p_vout->render.i_width / i_width;
583                 var_Set( p_vout, "mouse-x", val );
584
585                 val.i_int = ( ((int)ml.v) - i_y ) *
586                             p_vout->render.i_height / i_height;
587
588                 var_Set( p_vout, "mouse-y", val );
589
590                 val.b_bool = true;
591                 var_Set( p_vout, "mouse-moved", val );
592
593                 break;
594             }
595  
596             default:
597                 result = eventNotHandledErr;
598         }
599     }
600     else if(class == kEventClassTextInput)
601     {
602         switch (kind)
603         {
604             case kEventTextInputUnicodeForKeyEvent:
605             {
606                 break;
607             }
608             default:
609                 result = eventNotHandledErr;
610         }
611     }
612     else if(class == kEventClassVLCPlugin)
613     {
614         switch (kind)
615         {
616             case kEventVLCPluginShowFullscreen:
617                 ShowWindow (p_vout->p_sys->theWindow);
618                 SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
619                 //CGDisplayHideCursor(kCGDirectMainDisplay);
620                 break;
621             case kEventVLCPluginHideFullscreen:
622                 HideWindow (p_vout->p_sys->theWindow);
623                 SetSystemUIMode( kUIModeNormal, 0);
624                 CGDisplayShowCursor(kCGDirectMainDisplay);
625                 break;
626             default:
627                 result = eventNotHandledErr;
628                 break;
629         }
630     }
631     return result;
632 }
633
634 int aglLock( vout_thread_t * p_vout )
635 {
636 #ifdef __ppc__
637     /*
638      * before 10.4, we set the AGL context as current and
639      * then we retrieve and use the matching CGL context
640      */
641     aglSetCurrentContext(p_vout->p_sys->agl_ctx);
642     return kCGLNoError != CGLLockContext( CGLGetCurrentContext() );
643 #else
644     /* since 10.4, this is the safe way to get the underlying CGL context */
645     CGLContextObj cglContext;
646     if( aglGetCGLContext(p_vout->p_sys->agl_ctx, (void**)&cglContext) )
647     {
648         if( kCGLNoError == CGLLockContext( cglContext ) )
649         {
650             aglSetCurrentContext(p_vout->p_sys->agl_ctx);
651             return 0;
652         }
653     }
654     return 1;
655 #endif
656 }
657
658 void aglUnlock( vout_thread_t * p_vout )
659 {
660 #ifdef __ppc__
661     /*
662      * before 10.4, we assume that the AGL context is current.
663      * therefore, we use the current CGL context
664      */
665     CGLUnlockContext( CGLGetCurrentContext() );
666 #else
667     /* since 10.4, this is the safe way to get the underlying CGL context */
668     CGLContextObj cglContext;
669     if( aglGetCGLContext(p_vout->p_sys->agl_ctx, (void**)&cglContext) )
670     {
671         CGLUnlockContext( cglContext );
672     }
673 #endif
674 }