Qt: new volume slider, optionnal. Totem like, for people who use Totem
[vlc.git] / 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         case VOUT_REPARENT:
371         {
372             AGLDrawable drawable = (AGLDrawable)va_arg( args, int);
373             if( !p_vout->b_fullscreen && drawable != p_vout->p_sys->agl_drawable )
374             {
375                 p_vout->p_sys->agl_drawable = drawable;
376                 aglSetDrawable(p_vout->p_sys->agl_ctx, drawable);
377             }
378             return VLC_SUCCESS;
379         }
380
381         default:
382             return vout_vaControlDefault( p_vout, i_query, args );
383     }
384 }
385
386 void aglSwap( vout_thread_t * p_vout )
387 {
388     if( ! p_vout->p_sys->b_clipped_out )
389     {
390         p_vout->p_sys->b_got_frame = true;
391         aglSwapBuffers(p_vout->p_sys->agl_ctx);
392     }
393     else
394     {
395         /* drop frame */
396         glFlush();
397     }
398 }
399
400 /* Enter this function with the p_vout locked */
401 static void aglSetViewport( vout_thread_t *p_vout, Rect viewBounds, Rect clipBounds )
402 {
403     // mozilla plugin provides coordinates based on port bounds
404     // however AGL coordinates are based on window structure region
405     // and are vertically flipped
406     GLint rect[4];
407     CGrafPtr port = (CGrafPtr)p_vout->p_sys->agl_drawable;
408     Rect winBounds, clientBounds;
409
410     GetWindowBounds(GetWindowFromPort(port),
411         kWindowStructureRgn, &winBounds);
412     GetWindowBounds(GetWindowFromPort(port),
413         kWindowContentRgn, &clientBounds);
414
415     /* update video clipping bounds in drawable */
416     rect[0] = (clientBounds.left-winBounds.left)
417             + clipBounds.left;                  // from window left edge
418     rect[1] = (winBounds.bottom-winBounds.top)
419             - (clientBounds.top-winBounds.top)
420             - clipBounds.bottom;                // from window bottom edge
421     rect[2] = clipBounds.right-clipBounds.left; // width
422     rect[3] = clipBounds.bottom-clipBounds.top; // height
423     aglSetInteger(p_vout->p_sys->agl_ctx, AGL_BUFFER_RECT, rect);
424     aglEnable(p_vout->p_sys->agl_ctx, AGL_BUFFER_RECT);
425
426     /* update video internal bounds in drawable */
427     p_vout->p_sys->i_width  = viewBounds.right-viewBounds.left;
428     p_vout->p_sys->i_height = viewBounds.bottom-viewBounds.top;
429     p_vout->p_sys->i_offx   = -clipBounds.left - viewBounds.left;
430     p_vout->p_sys->i_offy   = clipBounds.bottom + viewBounds.top
431                             - p_vout->p_sys->i_height;
432
433     aglUpdateContext(p_vout->p_sys->agl_ctx);
434 }
435
436 //default window event handler
437 static pascal OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
438 {
439     OSStatus result = noErr;
440     UInt32 class = GetEventClass (event);
441     UInt32 kind = GetEventKind (event);
442     vout_thread_t *p_vout = (vout_thread_t *)userData;
443
444     result = CallNextEventHandler(nextHandler, event);
445     if(class == kEventClassCommand)
446     {
447         HICommand theHICommand;
448         GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof( HICommand ), NULL, &theHICommand );
449  
450         switch ( theHICommand.commandID )
451         {
452             default:
453                 result = eventNotHandledErr;
454         }
455     }
456     else if(class == kEventClassWindow)
457     {
458         WindowRef     window;
459         Rect          rectPort = {0,0,0,0};
460  
461         GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window);
462
463         if(window)
464         {
465             GetPortBounds(GetWindowPort(window), &rectPort);
466         }
467
468         switch (kind)
469         {
470             case kEventWindowClosed:
471             case kEventWindowZoomed:
472             case kEventWindowBoundsChanged:
473                 break;
474  
475             default:
476                 result = eventNotHandledErr;
477         }
478     }
479     else if(class == kEventClassMouse)
480     {
481         switch (kind)
482         {
483             case kEventMouseDown:
484             {
485                 UInt16     button;
486  
487                 GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
488                 switch (button)
489                 {
490                     case kEventMouseButtonPrimary:
491                     {
492                         vlc_value_t val;
493
494                         var_Get( p_vout, "mouse-button-down", &val );
495                         val.i_int |= 1;
496                         var_Set( p_vout, "mouse-button-down", val );
497                         break;
498                     }
499                     case kEventMouseButtonSecondary:
500                     {
501                         vlc_value_t val;
502
503                         var_Get( p_vout, "mouse-button-down", &val );
504                         val.i_int |= 2;
505                         var_Set( p_vout, "mouse-button-down", val );
506                         break;
507                     }
508                     case kEventMouseButtonTertiary:
509                     {
510                         vlc_value_t val;
511
512                         var_Get( p_vout, "mouse-button-down", &val );
513                         val.i_int |= 4;
514                         var_Set( p_vout, "mouse-button-down", val );
515                         break;
516                     }
517                     default:
518                         result = eventNotHandledErr;
519                 }
520                 break;
521             }
522
523             case kEventMouseUp:
524             {
525                 UInt16     button;
526  
527                 GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
528                 switch (button)
529                 {
530                     case kEventMouseButtonPrimary:
531                     {
532                         UInt32 clickCount = 0;
533                         GetEventParameter(event, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount);
534                         if( clickCount > 1 )
535                         {
536                             vlc_value_t val;
537
538                             val.b_bool = false;
539                             var_Set((vout_thread_t *) p_vout->p_parent, "fullscreen", val);
540                         }
541                         else
542                         {
543                             vlc_value_t val;
544
545                             var_SetBool( p_vout, "mouse-clicked", true );
546
547                             var_Get( p_vout, "mouse-button-down", &val );
548                             val.i_int &= ~1;
549                             var_Set( p_vout, "mouse-button-down", val );
550                         }
551                         break;
552                     }
553                     case kEventMouseButtonSecondary:
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                     case kEventMouseButtonTertiary:
563                     {
564                         vlc_value_t val;
565
566                         var_Get( p_vout, "mouse-button-down", &val );
567                         val.i_int &= ~2;
568                         var_Set( p_vout, "mouse-button-down", val );
569                         break;
570                     }
571                     default:
572                         result = eventNotHandledErr;
573                 }
574                 break;
575             }
576
577             case kEventMouseMoved:
578             {
579                 Point ml;
580                 vlc_value_t val;
581
582                 unsigned int i_x, i_y;
583                 unsigned int i_height = p_vout->p_sys->i_height;
584                 unsigned int i_width  = p_vout->p_sys->i_width;
585
586                 vout_PlacePicture(p_vout, i_width, i_height, &i_x, &i_y, &i_width, &i_height);
587
588                 GetEventParameter(event, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &ml);
589  
590                 val.i_int = ( ((int)ml.h) - i_x ) *
591                             p_vout->render.i_width / i_width;
592                 var_Set( p_vout, "mouse-x", val );
593
594                 val.i_int = ( ((int)ml.v) - i_y ) *
595                             p_vout->render.i_height / i_height;
596
597                 var_Set( p_vout, "mouse-y", val );
598
599                 val.b_bool = true;
600                 var_Set( p_vout, "mouse-moved", val );
601
602                 break;
603             }
604  
605             default:
606                 result = eventNotHandledErr;
607         }
608     }
609     else if(class == kEventClassTextInput)
610     {
611         switch (kind)
612         {
613             case kEventTextInputUnicodeForKeyEvent:
614             {
615                 break;
616             }
617             default:
618                 result = eventNotHandledErr;
619         }
620     }
621     else if(class == kEventClassVLCPlugin)
622     {
623         switch (kind)
624         {
625             case kEventVLCPluginShowFullscreen:
626                 ShowWindow (p_vout->p_sys->theWindow);
627                 SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
628                 //CGDisplayHideCursor(kCGDirectMainDisplay);
629                 break;
630             case kEventVLCPluginHideFullscreen:
631                 HideWindow (p_vout->p_sys->theWindow);
632                 SetSystemUIMode( kUIModeNormal, 0);
633                 CGDisplayShowCursor(kCGDirectMainDisplay);
634                 break;
635             default:
636                 result = eventNotHandledErr;
637                 break;
638         }
639     }
640     return result;
641 }
642
643 int aglLock( vout_thread_t * p_vout )
644 {
645 #ifdef __ppc__
646     /*
647      * before 10.4, we set the AGL context as current and
648      * then we retrieve and use the matching CGL context
649      */
650     aglSetCurrentContext(p_vout->p_sys->agl_ctx);
651     return kCGLNoError != CGLLockContext( CGLGetCurrentContext() );
652 #else
653     /* since 10.4, this is the safe way to get the underlying CGL context */
654     CGLContextObj cglContext;
655     if( aglGetCGLContext(p_vout->p_sys->agl_ctx, (void**)&cglContext) )
656     {
657         if( kCGLNoError == CGLLockContext( cglContext ) )
658         {
659             aglSetCurrentContext(p_vout->p_sys->agl_ctx);
660             return 0;
661         }
662     }
663     return 1;
664 #endif
665 }
666
667 void aglUnlock( vout_thread_t * p_vout )
668 {
669 #ifdef __ppc__
670     /*
671      * before 10.4, we assume that the AGL context is current.
672      * therefore, we use the current CGL context
673      */
674     CGLUnlockContext( CGLGetCurrentContext() );
675 #else
676     /* since 10.4, this is the safe way to get the underlying CGL context */
677     CGLContextObj cglContext;
678     if( aglGetCGLContext(p_vout->p_sys->agl_ctx, (void**)&cglContext) )
679     {
680         CGLUnlockContext( cglContext );
681     }
682 #endif
683 }