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