* set svn:keywords correctly and fixed some minor stuff here and there
[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 = VLC_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 = VLC_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 = VLC_FALSE;
539                             var_Set((vout_thread_t *) p_vout->p_parent, "fullscreen", val);
540                         }
541                         else
542                         {
543                             vlc_value_t val;
544
545                             val.b_bool = VLC_TRUE;
546                             var_Set( p_vout, "mouse-clicked", val );
547
548                             var_Get( p_vout, "mouse-button-down", &val );
549                             val.i_int &= ~1;
550                             var_Set( p_vout, "mouse-button-down", val );
551                         }
552                         break;
553                     }
554                     case kEventMouseButtonSecondary:
555                     {
556                         vlc_value_t val;
557
558                         var_Get( p_vout, "mouse-button-down", &val );
559                         val.i_int &= ~2;
560                         var_Set( p_vout, "mouse-button-down", val );
561                         break;
562                     }
563                     case kEventMouseButtonTertiary:
564                     {
565                         vlc_value_t val;
566
567                         var_Get( p_vout, "mouse-button-down", &val );
568                         val.i_int &= ~2;
569                         var_Set( p_vout, "mouse-button-down", val );
570                         break;
571                     }
572                     default:
573                         result = eventNotHandledErr;
574                 }
575                 break;
576             }
577
578             case kEventMouseMoved:
579             {
580                 Point ml;
581                 vlc_value_t val;
582
583                 unsigned int i_x, i_y;
584                 unsigned int i_height = p_vout->p_sys->i_height;
585                 unsigned int i_width  = p_vout->p_sys->i_width;
586
587                 vout_PlacePicture(p_vout, i_width, i_height, &i_x, &i_y, &i_width, &i_height); 
588
589                 GetEventParameter(event, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &ml);
590                 
591                 val.i_int = ( ((int)ml.h) - i_x ) *
592                             p_vout->render.i_width / i_width;
593                 var_Set( p_vout, "mouse-x", val );
594
595                 val.i_int = ( ((int)ml.v) - i_y ) *
596                             p_vout->render.i_height / i_height;
597
598                 var_Set( p_vout, "mouse-y", val );
599
600                 val.b_bool = VLC_TRUE;
601                 var_Set( p_vout, "mouse-moved", val );
602
603                 break;
604             }
605             
606             default:
607                 result = eventNotHandledErr;
608         }
609     }
610     else if(class == kEventClassTextInput)
611     {
612         switch (kind)
613         {
614             case kEventTextInputUnicodeForKeyEvent:
615             {
616                 break;
617             }
618             default:
619                 result = eventNotHandledErr;
620         }
621     }
622     else if(class == kEventClassVLCPlugin)
623     {
624         switch (kind)
625         {
626             case kEventVLCPluginShowFullscreen:
627                 ShowWindow (p_vout->p_sys->theWindow);
628                 SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
629                 //CGDisplayHideCursor(kCGDirectMainDisplay);
630                 break;
631             case kEventVLCPluginHideFullscreen:
632                 HideWindow (p_vout->p_sys->theWindow);
633                 SetSystemUIMode( kUIModeNormal, 0);
634                 CGDisplayShowCursor(kCGDirectMainDisplay);
635                 break;
636             default:
637                 result = eventNotHandledErr;
638                 break;
639         }
640     }
641     return result;
642 }
643
644 int aglLock( vout_thread_t * p_vout )
645 {
646 #ifdef __ppc__
647     /*
648      * before 10.4, we set the AGL context as current and
649      * then we retrieve and use the matching CGL context 
650      */
651     aglSetCurrentContext(p_vout->p_sys->agl_ctx);
652     return kCGLNoError != CGLLockContext( CGLGetCurrentContext() );
653 #else
654     /* since 10.4, this is the safe way to get the underlying CGL context */
655     CGLContextObj cglContext;
656     if( aglGetCGLContext(p_vout->p_sys->agl_ctx, (void**)&cglContext) )
657     {
658         if( kCGLNoError == CGLLockContext( cglContext ) )
659         {
660             aglSetCurrentContext(p_vout->p_sys->agl_ctx);
661             return 0;
662         }
663     }
664     return 1;
665 #endif
666 }
667
668 void aglUnlock( vout_thread_t * p_vout )
669 {
670 #ifdef __ppc__
671     /*
672      * before 10.4, we assume that the AGL context is current.
673      * therefore, we use the current CGL context 
674      */
675     CGLUnlockContext( CGLGetCurrentContext() );
676 #else
677     /* since 10.4, this is the safe way to get the underlying CGL context */
678     CGLContextObj cglContext;
679     if( aglGetCGLContext(p_vout->p_sys->agl_ctx, (void**)&cglContext) )
680     {
681         CGLUnlockContext( cglContext );
682     }
683 #endif
684 }