* glx.c: don't scale the image with the chroma (supposed to speed up
[vlc.git] / modules / video_output / x11 / glx.c
1 /*****************************************************************************
2  * glx.c: GLX video output
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Cyril Deguet <asmax@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>                                                 /* ENOMEM */
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <string.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/intf.h>
33 #include <vlc/vout.h>
34
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37 #include <GL/glx.h>
38
39 /*****************************************************************************
40  * Local prototypes
41  *****************************************************************************/
42 static int  Create      ( vlc_object_t * );
43 static void Destroy     ( vlc_object_t * );
44
45 static int  Init        ( vout_thread_t * );
46 static void End         ( vout_thread_t * );
47 static int  Manage      ( vout_thread_t * );
48 static void Render      ( vout_thread_t *p_vout, picture_t *p_pic );
49 static void DisplayVideo( vout_thread_t *, picture_t * );
50
51 static int  OpenDisplay ( vout_thread_t * );
52 static void CloseDisplay( vout_thread_t * );
53 static int  InitGLX12   ( vout_thread_t *p_vout );
54 static int  InitGLX13   ( vout_thread_t *p_vout );
55 static void CreateWindow( vout_thread_t *p_vout, XVisualInfo *p_vi );
56 static void SwitchContext( vout_thread_t *p_vout );
57
58 static inline int GetAlignedSize( int i_size );
59
60 /*****************************************************************************
61  * Module descriptor
62  *****************************************************************************/
63 vlc_module_begin();
64     set_description( _("X11 OpenGL (GLX) video output") );
65     set_capability( "video output", 20 );
66     add_shortcut( "glx" );
67     set_callbacks( Create, Destroy );
68 vlc_module_end();
69
70 /*****************************************************************************
71  * vout_sys_t: GLX video output method descriptor
72  *****************************************************************************
73  * This structure is part of the video output thread descriptor.
74  * It describes the GLX specific properties of an output thread.
75  *****************************************************************************/
76 struct vout_sys_t
77 {
78     uint8_t     *p_buffer;
79     int         i_index;
80
81     int         i_tex_width;
82     int         i_tex_height;
83
84     int         i_width;
85     int         i_height;
86     int         b_fullscreen;
87
88     Display     *p_display;
89     int         b_glx13;
90     GLXContext  gwctx;
91     Window      wnd;
92     GLXWindow   gwnd;
93     Atom        wm_delete;
94
95     GLuint      texture;
96
97     int         i_effect; //XXX
98 };
99
100 #define MWM_HINTS_DECORATIONS   (1L << 1)
101 #define PROP_MWM_HINTS_ELEMENTS 5
102 typedef struct mwmhints_t
103 {
104     uint32_t flags;
105     uint32_t functions;
106     uint32_t decorations;
107     int32_t  input_mode;
108     uint32_t status;
109 } mwmhints_t;
110
111
112 /*****************************************************************************
113  * Create: allocates GLX video thread output method
114  *****************************************************************************
115  * This function allocates and initializes a GLX vout method.
116  *****************************************************************************/
117 static int Create( vlc_object_t *p_this )
118 {
119     vout_thread_t *p_vout = (vout_thread_t *)p_this;
120
121     /* Allocate structure */
122     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
123     if( p_vout->p_sys == NULL )
124     {
125         msg_Err( p_vout, "out of memory" );
126         return( 1 );
127     }
128
129     //XXX set to 0 to disable the cube effect
130     p_vout->p_sys->i_effect = 1;
131
132    /* p_vout->p_sys->i_width = p_vout->i_window_width;
133     p_vout->p_sys->i_height = p_vout->i_window_height; */
134     p_vout->p_sys->i_width = 700;
135     p_vout->p_sys->i_height = 700;
136     p_vout->p_sys->b_fullscreen = 0;
137
138     /* A texture must have a size aligned on a power of 2 */
139     p_vout->p_sys->i_tex_width  = GetAlignedSize( p_vout->render.i_width );
140     p_vout->p_sys->i_tex_height = GetAlignedSize( p_vout->render.i_height );
141
142     msg_Dbg( p_vout, "Texture size: %dx%d", p_vout->p_sys->i_tex_width,
143              p_vout->p_sys->i_tex_height );
144
145     /* Open and initialize device */
146     if( OpenDisplay( p_vout ) )
147     {
148         msg_Err( p_vout, "cannot open display" );
149         free( p_vout->p_sys );
150         return( 1 );
151     }
152
153     p_vout->pf_init = Init;
154     p_vout->pf_end = End;
155     p_vout->pf_manage = Manage;
156     p_vout->pf_render = Render;
157     p_vout->pf_display = DisplayVideo;
158
159     return( 0 );
160 }
161
162 /*****************************************************************************
163  * Init: initialize GLX video thread output method
164  *****************************************************************************/
165 static int Init( vout_thread_t *p_vout )
166 {
167     int i_index;
168     picture_t *p_pic;
169
170     /* No YUV textures :( */
171     p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
172     p_vout->output.i_rmask = 0x000000ff;
173     p_vout->output.i_gmask = 0x0000ff00;
174     p_vout->output.i_bmask = 0x00ff0000;
175
176     p_vout->output.i_width  = p_vout->render.i_width;
177     p_vout->output.i_height = p_vout->render.i_height;
178     p_vout->output.i_aspect = p_vout->render.i_aspect;
179
180     I_OUTPUTPICTURES = 0;
181
182     p_pic = NULL;
183
184     /* Find an empty picture slot */
185     for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
186     {
187         if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
188         {
189             p_pic = p_vout->p_picture + i_index;
190             break;
191         }
192     }
193
194     if( p_pic == NULL )
195     {
196         return -1;
197     }
198
199    /* We know the chroma, allocate a buffer which will be used
200      * directly by the decoder */
201     p_pic->i_planes = 1;
202
203
204     p_pic->p->p_pixels = p_vout->p_sys->p_buffer
205         + 2 * p_vout->p_sys->i_tex_width *
206           (p_vout->p_sys->i_tex_height - p_vout->output.i_height)
207         + 2 * (p_vout->p_sys->i_tex_width - p_vout->output.i_width);
208     p_pic->p->i_lines = p_vout->output.i_height;
209     p_pic->p->i_pitch = p_vout->p_sys->i_tex_width * 4;
210     p_pic->p->i_pixel_pitch = 4;
211     p_pic->p->i_visible_pitch = p_vout->output.i_width * 4;
212
213     p_pic->i_status = DESTROYED_PICTURE;
214     p_pic->i_type   = DIRECT_PICTURE;
215
216     PP_OUTPUTPICTURE[ 0 ] = p_pic;
217
218     I_OUTPUTPICTURES = 1;
219
220     SwitchContext( p_vout );
221
222     /* Set the texture parameters */
223     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
224     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
225
226     if( p_vout->p_sys->i_effect )
227     {
228         glEnable( GL_CULL_FACE);
229         /*glDisable( GL_DEPTH_TEST );
230         glEnable( GL_BLEND );
231         glBlendFunc( GL_SRC_ALPHA, GL_ONE );*/
232
233         /* Set the perpective */
234         glMatrixMode( GL_PROJECTION );
235         glLoadIdentity();
236         glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
237         glMatrixMode( GL_MODELVIEW );
238         glLoadIdentity();
239         glTranslatef( 0.0, 0.0, - 5.0 );
240     }
241
242     return 0;
243 }
244
245 /*****************************************************************************
246  * End: terminate GLX video thread output method
247  *****************************************************************************/
248 static void End( vout_thread_t *p_vout )
249 {
250     ;
251 }
252
253 /*****************************************************************************
254  * Destroy: destroy GLX video thread output method
255  *****************************************************************************
256  * Terminate an output method created by Create
257  *****************************************************************************/
258 static void Destroy( vlc_object_t *p_this )
259 {
260     vout_thread_t *p_vout = (vout_thread_t *)p_this;
261
262     CloseDisplay( p_vout );
263
264     /* Free the texture buffer*/
265     if( p_vout->p_sys->p_buffer )
266     {
267         free( p_vout->p_sys->p_buffer );
268     }
269
270     free( p_vout->p_sys );
271 }
272
273 /*****************************************************************************
274  * Manage: handle X11 events
275  *****************************************************************************
276  * This function should be called regularly by video output thread. It manages
277  * console events. It returns a non null value on error.
278  *****************************************************************************/
279 static int Manage( vout_thread_t *p_vout )
280 {
281     Display *p_display;
282
283     p_display = p_vout->p_sys->p_display;
284
285     /* loop on X11 events */
286     while( XPending( p_display ) > 0 )
287     {
288         XEvent evt;
289         XNextEvent( p_display, &evt );
290         switch( evt.type )
291         {
292             case ClientMessage:
293             {
294                 /* Delete notification */
295                 if( (evt.xclient.format == 32) &&
296                     ((Atom)evt.xclient.data.l[0] == p_vout->p_sys->wm_delete) )
297                 {
298                     /* the user wants to close the window */
299                     playlist_t * p_playlist =
300                         (playlist_t *)vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
301                                                        FIND_ANYWHERE );
302                     if( p_playlist != NULL )
303                     {
304                         playlist_Stop( p_playlist );
305                         vlc_object_release( p_playlist );
306                     }
307                 }
308                 break;
309             }
310         }
311     }
312     return 0;
313 }
314
315 /*****************************************************************************
316  * Render: render previously calculated output
317  *****************************************************************************/
318 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
319 {
320     glClear(GL_COLOR_BUFFER_BIT);
321     /*glTexImage2D (GL_TEXTURE_2D, 0, 3, p_vout->output.i_width,
322                   p_vout->output.i_height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
323                   p_vout->p_sys->p_buffer);*/
324     glTexImage2D (GL_TEXTURE_2D, 0, 3, p_vout->p_sys->i_tex_width,
325                   p_vout->p_sys->i_tex_height , 0, GL_RGBA, GL_UNSIGNED_BYTE,
326                   p_vout->p_sys->p_buffer);
327
328     if( !p_vout->p_sys->i_effect )
329     {
330         glEnable( GL_TEXTURE_2D);
331         glBegin( GL_POLYGON);
332         glTexCoord2f(0.0,0.0); glVertex2f(-1.0,1.0);
333         glTexCoord2f(1.0,0.0); glVertex2f(1.0,1.0);
334         glTexCoord2f(1.0,1.0); glVertex2f(1.0,-1.0);
335         glTexCoord2f(0.0,1.0); glVertex2f(-1.0,-1.0);
336         glEnd();
337     }
338     else
339     {
340         glRotatef( 1.0, 0.3, 0.5, 0.7 );
341
342         glEnable( GL_TEXTURE_2D);
343         glBegin( GL_QUADS );
344
345         float f_width = p_vout->output.i_width;
346         float f_height = p_vout->output.i_height;
347
348         /* Correct the aspect ratio */
349  /*       float f_aspect = (float)p_vout->output.i_aspect / VOUT_ASPECT_FACTOR;
350         if( f_aspect > 1.0 )
351         {
352             f_height *= f_aspect;
353         }
354         else
355         {
356             f_width *= f_aspect;
357         }*/
358
359         float f_offset_x = (1.0 - f_width / p_vout->p_sys->i_tex_width) / 2.0;
360         float f_offset_y = (1.0 - f_height / p_vout->p_sys->i_tex_height) / 2.0;
361
362         /* Front */
363         glTexCoord2f( f_offset_x, f_offset_y );
364         glVertex3f( - 1.0, 1.0, 1.0 );
365         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
366         glVertex3f( - 1.0, - 1.0, 1.0 );
367         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
368         glVertex3f( 1.0, - 1.0, 1.0 );
369         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
370         glVertex3f( 1.0, 1.0, 1.0 );
371
372         /* Left */
373         glTexCoord2f( f_offset_x, f_offset_y );
374         glVertex3f( - 1.0, 1.0, - 1.0 );
375         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
376         glVertex3f( - 1.0, - 1.0, - 1.0 );
377         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
378         glVertex3f( - 1.0, - 1.0, 1.0 );
379         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
380         glVertex3f( - 1.0, 1.0, 1.0 );
381
382         /* Back */
383         glTexCoord2f( f_offset_x, f_offset_y );
384         glVertex3f( 1.0, 1.0, - 1.0 );
385         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
386         glVertex3f( 1.0, - 1.0, - 1.0 );
387         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
388         glVertex3f( - 1.0, - 1.0, - 1.0 );
389         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
390         glVertex3f( - 1.0, 1.0, - 1.0 );
391
392         /* Right */
393         glTexCoord2f( f_offset_x, f_offset_y );
394         glVertex3f( 1.0, 1.0, 1.0 );
395         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
396         glVertex3f( 1.0, - 1.0, 1.0 );
397         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
398         glVertex3f( 1.0, - 1.0, - 1.0 );
399         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
400         glVertex3f( 1.0, 1.0, - 1.0 );
401
402         /* Top */
403         glTexCoord2f( f_offset_x, f_offset_y );
404         glVertex3f( - 1.0, 1.0, - 1.0 );
405         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
406         glVertex3f( - 1.0, 1.0, 1.0 );
407         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
408         glVertex3f( 1.0, 1.0, 1.0 );
409         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
410         glVertex3f( 1.0, 1.0, - 1.0 );
411
412         /* Bottom */
413         glTexCoord2f( f_offset_x, f_offset_y );
414         glVertex3f( - 1.0, - 1.0, 1.0 );
415         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
416         glVertex3f( - 1.0, - 1.0, - 1.0 );
417         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
418         glVertex3f( 1.0, - 1.0, - 1.0 );
419         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
420         glVertex3f( 1.0, - 1.0, 1.0 );
421         glEnd();
422     }
423     glDisable( GL_TEXTURE_2D);
424     
425   
426 }
427
428 /*****************************************************************************
429  * DisplayVideo: displays previously rendered output
430  *****************************************************************************/
431 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
432 {
433     if( p_vout->p_sys->b_glx13 )
434     {
435         glXSwapBuffers( p_vout->p_sys->p_display, p_vout->p_sys->gwnd );
436     }
437     else
438     {
439         glXSwapBuffers( p_vout->p_sys->p_display, p_vout->p_sys->wnd );
440     }
441
442 }
443
444 /* following functions are local */
445
446 /*****************************************************************************
447  * OpenDisplay: open and initialize OpenGL device
448  *****************************************************************************/
449
450 static int OpenDisplay( vout_thread_t *p_vout )
451 {
452     Display *p_display;
453     int i_opcode, i_evt, i_err;
454     int i_maj, i_min;
455
456     /* Open the display */
457     p_vout->p_sys->p_display = p_display = XOpenDisplay( NULL );
458     if( !p_display )
459     {
460         msg_Err( p_vout, "Cannot open display" );
461         return -1;
462     }
463
464     /* Check for GLX extension */
465     if( !XQueryExtension( p_display, "GLX", &i_opcode, &i_evt, &i_err ) )
466     {
467         msg_Err( p_vout, "GLX extension not supported" );
468         return -1;
469     }
470     if( !glXQueryExtension( p_display, &i_err, &i_evt ) )
471     {
472         msg_Err( p_vout, "glXQueryExtension failed" );
473         return -1;
474     }
475
476     /* Check GLX version */
477     if (!glXQueryVersion( p_display, &i_maj, &i_min ) )
478     {
479         msg_Err( p_vout, "glXQueryVersion failed" );
480         return -1;
481     }
482     if( i_maj <= 0 || ((i_maj == 1) && (i_min < 3)) )
483     {
484         p_vout->p_sys->b_glx13 = 0;
485         msg_Dbg( p_vout, "Using GLX 1.2 API" );
486         if( InitGLX12( p_vout ) == -1 )
487         {
488             return -1;
489         }
490     }
491     else
492     {
493         p_vout->p_sys->b_glx13 = 1;
494         msg_Dbg( p_vout, "Using GLX 1.3 API" );
495         if( InitGLX13( p_vout ) == -1 )
496         {
497             return -1;
498         }
499     }
500
501     XMapWindow( p_display, p_vout->p_sys->wnd );
502     if( p_vout->p_sys->b_fullscreen )
503     {
504         //XXX
505         XMoveWindow( p_display, p_vout->p_sys->wnd, 0, 0 );
506     }
507     XFlush( p_display );
508
509     /* Allocate the texture buffer */
510     p_vout->p_sys->p_buffer =
511         malloc( p_vout->p_sys->i_tex_width * p_vout->p_sys->i_tex_height * 4 );
512     if( !p_vout->p_sys->p_buffer )
513     {
514         msg_Err( p_vout, "Out of memory" );
515         return -1;
516     }
517     return 0;
518 }
519
520 /*****************************************************************************
521  * CloseDisplay: close and reset OpenGL device
522  *****************************************************************************
523  * Returns all resources allocated by OpenDisplay and restore the original
524  * state of the device.
525  *****************************************************************************/
526 static void CloseDisplay( vout_thread_t *p_vout )
527 {
528     Display *p_display;
529
530     glFlush();
531
532     p_display = p_vout->p_sys->p_display;
533     glXDestroyContext( p_display, p_vout->p_sys->gwctx );
534     if( p_vout->p_sys->b_glx13 )
535     {
536         glXDestroyWindow( p_display, p_vout->p_sys->gwnd );
537     }
538     XDestroyWindow( p_display, p_vout->p_sys->wnd );
539     XCloseDisplay( p_display );
540
541 }
542
543
544 int InitGLX12( vout_thread_t *p_vout )
545 {
546     Display *p_display;
547     XVisualInfo *p_vi;
548     GLXContext gwctx;
549     int p_attr[] = { GLX_RGBA, GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
550                      GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER,
551                      0 };
552
553     p_display = p_vout->p_sys->p_display;
554
555     p_vi = glXChooseVisual( p_display, DefaultScreen( p_display), p_attr );
556     if(! p_vi )
557     {
558         msg_Err( p_vout, "Cannot get GLX 1.2 visual" );
559         return -1;
560     }
561
562     /* Create the window */
563     CreateWindow( p_vout, p_vi );
564
565      /* Create an OpenGL context */
566     p_vout->p_sys->gwctx = gwctx = glXCreateContext( p_display, p_vi, 0, True );
567     if( !gwctx )
568     {
569         msg_Err( p_vout, "Cannot create OpenGL context");
570         XFree( p_vi );
571         return -1;
572     }
573     XFree( p_vi );
574
575     return 0;
576 }
577
578
579 int InitGLX13( vout_thread_t *p_vout )
580 {
581     Display *p_display;
582     int i_nbelem;
583     GLXFBConfig *p_fbconfs, fbconf;
584     XVisualInfo *p_vi;
585     GLXContext gwctx;
586     int p_attr[] = { GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
587                      GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER, True,
588                      GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 0 };
589
590     p_display = p_vout->p_sys->p_display;
591
592     /* Get the FB configuration */
593     p_fbconfs = glXChooseFBConfig( p_display, 0, p_attr, &i_nbelem );
594     if( (i_nbelem <= 0) || !p_fbconfs )
595     {
596         msg_Err( p_vout, "Cannot get FB configurations");
597         if( p_fbconfs )
598         {
599             XFree( p_fbconfs );
600         }
601         return -1;
602     }
603     fbconf = p_fbconfs[0];
604
605     /* Get the X11 visual */
606     p_vi = glXGetVisualFromFBConfig( p_display, fbconf );
607     if( !p_vi )
608     {
609         msg_Err( p_vout, "Cannot get X11 visual" );
610         XFree( p_fbconfs );
611         return -1;
612     }
613
614     /* Create the window */
615     CreateWindow( p_vout, p_vi );
616
617     XFree( p_vi );
618
619     /* Create the GLX window */
620     p_vout->p_sys->gwnd = glXCreateWindow( p_display, fbconf, p_vout->p_sys->wnd, NULL );
621     if( p_vout->p_sys->gwnd == None )
622     {
623         msg_Err( p_vout, "Cannot create GLX window" );
624         return -1;
625     }
626
627     /* Create an OpenGL context */
628     p_vout->p_sys->gwctx = gwctx = glXCreateNewContext( p_display, fbconf,
629                                                   GLX_RGBA_TYPE, NULL, True );
630     if( !gwctx )
631     {
632         msg_Err( p_vout, "Cannot create OpenGL context");
633         XFree( p_fbconfs );
634         return -1;
635     }
636     XFree( p_fbconfs );
637
638     return 0;
639 }
640
641
642
643 void CreateWindow( vout_thread_t *p_vout, XVisualInfo *p_vi )
644 {
645     Display *p_display;
646     XSetWindowAttributes xattr;
647     Window wnd;
648     Colormap cm;
649     XSizeHints* p_size_hints;
650     Atom prop;
651     mwmhints_t mwmhints;
652
653     p_display = p_vout->p_sys->p_display;
654
655     /* Create a colormap */
656     cm = XCreateColormap( p_display, RootWindow( p_display, p_vi->screen ),
657                           p_vi->visual, AllocNone );
658
659     /* Create the window */
660     xattr.background_pixel = BlackPixel( p_display, DefaultScreen(p_display) );
661     xattr.border_pixel = 0;
662     xattr.colormap = cm;
663     p_vout->p_sys->wnd = wnd = XCreateWindow( p_display, DefaultRootWindow(p_display),
664             0, 0, p_vout->p_sys->i_width, p_vout->p_sys->i_height, 0, p_vi->depth,
665             InputOutput, p_vi->visual,
666             CWBackPixel | CWBorderPixel | CWColormap, &xattr);
667
668     /* Allow the window to be deleted by the window manager */
669     p_vout->p_sys->wm_delete = XInternAtom( p_display, "WM_DELETE_WINDOW", False );
670     XSetWMProtocols( p_display, wnd, &p_vout->p_sys->wm_delete, 1 );
671
672     if( p_vout->p_sys->b_fullscreen )
673     {
674         mwmhints.flags = MWM_HINTS_DECORATIONS;
675         mwmhints.decorations = False;
676
677         prop = XInternAtom( p_display, "_MOTIF_WM_HINTS", False );
678         XChangeProperty( p_display, wnd, prop, prop, 32, PropModeReplace,
679                          (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
680     }
681     else
682     {
683         /* Prevent the window from being resized */
684         p_size_hints = XAllocSizeHints();
685         p_size_hints->flags = PMinSize | PMaxSize;
686         p_size_hints->min_width = p_vout->p_sys->i_width;
687         p_size_hints->min_height = p_vout->p_sys->i_height;
688         p_size_hints->max_width = p_vout->p_sys->i_width;
689         p_size_hints->max_height = p_vout->p_sys->i_height;
690         XSetWMNormalHints( p_display, wnd, p_size_hints );
691         XFree( p_size_hints );
692     }
693     XSelectInput( p_display, wnd, KeyPressMask );
694 }
695
696
697 void SwitchContext( vout_thread_t *p_vout )
698 {
699     /* Change the current OpenGL context */
700     if( p_vout->p_sys->b_glx13 )
701     {
702         glXMakeContextCurrent( p_vout->p_sys->p_display, p_vout->p_sys->gwnd,
703                                p_vout->p_sys->gwnd, p_vout->p_sys->gwctx );
704     }
705     else
706     {
707         glXMakeCurrent( p_vout->p_sys->p_display, p_vout->p_sys->wnd,
708                         p_vout->p_sys->gwctx );
709     }
710 }
711
712
713 int GetAlignedSize( int i_size )
714 {
715     /* Return the nearest power of 2 */
716     int i_result = 1;
717     while( i_result < i_size )
718     {
719         i_result *= 2;
720     }
721     return i_result;
722 }