]> git.sesse.net Git - vlc/blob - src/video_output/video_x11.c
Nettoyage, ajout du gamma, pr�paration de la yuv walken.
[vlc] / src / video_output / video_x11.c
1 /*******************************************************************************
2  * vout_x11.c: X11 video output display method
3  * (c)1998 VideoLAN
4  *******************************************************************************/
5
6 /*******************************************************************************
7  * Preamble
8  *******************************************************************************/
9
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/ipc.h>
15 #include <sys/shm.h>
16 #include <X11/Xlib.h>
17 #include <X11/Xutil.h>
18 #include <X11/extensions/XShm.h>
19
20 #include "config.h"
21 #include "common.h"
22 #include "mtime.h"
23 #include "vlc_thread.h"
24
25 #include "video.h"
26 #include "video_output.h"
27 #include "video_sys.h"
28 #include "intf_msg.h"
29
30 /*******************************************************************************
31  * vout_sys_t: video output X11 method descriptor
32  *******************************************************************************
33  * This structure is part of the video output thread descriptor.
34  * It describes the X11 specific properties of an output thread. X11 video 
35  * output is performed through regular resizable windows. Windows can be
36  * dynamically resized to adapt to the size of the streams.
37  *******************************************************************************/
38 typedef struct vout_sys_s
39 {
40     /* User settings */
41     boolean_t           b_shm;                 /* shared memory extension flag */
42
43     /* Internal settings and properties */
44     Display *           p_display;                          /* display pointer */
45     int                 i_screen;                             /* screen number */
46     Window              root_window;                            /* root window */
47     Window              window;                     /* window instance handler */
48     GC                  gc;                /* graphic context instance handler */    
49
50     /* Font information */
51     int                 i_char_bytes_per_line;      /* character width (bytes) */
52     int                 i_char_height;             /* character height (lines) */
53     int                 i_char_interspacing; /* space between centers (pixels) */
54     byte_t *            pi_font;                       /* pointer to font data */
55
56     /* Display buffers and shared memory information */
57     int                 i_buffer_index;                        /* buffer index */
58     XImage *            p_ximage[2];                         /* XImage pointer */   
59     XShmSegmentInfo     shm_info[2];         /* shared memory zone information */
60 } vout_sys_t;
61
62 /*******************************************************************************
63  * Local prototypes
64  *******************************************************************************/
65 static int  X11OpenDisplay      ( vout_thread_t *p_vout, char *psz_display, Window root_window );
66 static void X11CloseDisplay     ( vout_thread_t *p_vout );
67 static int  X11GetFont          ( vout_thread_t *p_vout );
68 static int  X11CreateWindow     ( vout_thread_t *p_vout );
69 static void X11DestroyWindow    ( vout_thread_t *p_vout );
70 static int  X11CreateImage      ( vout_thread_t *p_vout, XImage **pp_ximage );
71 static void X11DestroyImage     ( XImage *p_ximage );
72 static int  X11CreateShmImage   ( vout_thread_t *p_vout, XImage **pp_ximage, 
73                                   XShmSegmentInfo *p_shm_info );
74 static void X11DestroyShmImage  ( vout_thread_t *p_vout, XImage *p_ximage, 
75                                   XShmSegmentInfo *p_shm_info );
76
77
78 /*******************************************************************************
79  * vout_SysCreate: allocate X11 video thread output method
80  *******************************************************************************
81  * This function allocate and initialize a X11 vout method. It uses some of the
82  * vout properties to choose the window size, and change them according to the
83  * actual properties of the display.
84  *******************************************************************************/
85 int vout_SysCreate( vout_thread_t *p_vout, char *psz_display, Window root_window )
86 {
87     /* Allocate structure */
88     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );    
89     if( p_vout->p_sys == NULL )
90     {   
91         intf_ErrMsg("error: %s\n", strerror(ENOMEM) );        
92         return( 1 );        
93     }    
94
95     /* Open and initialize device. This function issues its own error messages.
96      * Since XLib is usually not thread-safe, we can't use the same display
97      * pointer than the interface or another thread. However, the root window
98      * id is still valid. */
99     if( X11OpenDisplay( p_vout, psz_display, root_window ) )
100     {
101         intf_ErrMsg("error: can't initialize X11 display\n" );
102         free( p_vout->p_sys );
103         return( 1 );               
104     }
105
106     return( 0 );
107 }
108
109 /*******************************************************************************
110  * vout_SysInit: initialize X11 video thread output method
111  *******************************************************************************
112  * This function create the XImages needed by the output thread. It is called
113  * at the beginning of the thread, but also each time the window is resized.
114  *******************************************************************************/
115 int vout_SysInit( vout_thread_t *p_vout )
116
117     int i_err;
118
119     /* Create XImages using XShm extension - on failure, fall back to regular 
120      * way (and destroy the first image if it was created successfully) */
121     if( p_vout->p_sys->b_shm )
122     {
123         /* Create first image */
124         i_err = X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[0], 
125                                    &p_vout->p_sys->shm_info[0] );
126         if( !i_err )                           /* first image has been created */
127         {
128             /* Create second image */
129             if( X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[1], 
130                                    &p_vout->p_sys->shm_info[1] ) )
131             {                               /* error creating the second image */
132                 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0], 
133                                     &p_vout->p_sys->shm_info[0] );
134                 i_err = 1;
135             }
136         }
137         if( i_err )                                        /* an error occured */
138         {                        
139             intf_Msg("warning: XShm video extension desactivated\n" );
140             p_vout->p_sys->b_shm = 0;
141         }
142     }
143
144     /* Create XImages without XShm extension */
145     if( !p_vout->p_sys->b_shm )
146     {
147         if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[0] ) )
148         {
149             intf_Msg("error: can't create images\n");
150             p_vout->p_sys->p_ximage[0] = NULL;
151             p_vout->p_sys->p_ximage[1] = NULL;
152             return( 1 );
153         }
154         if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[1] ) )
155         {
156             intf_Msg("error: can't create images\n");
157             X11DestroyImage( p_vout->p_sys->p_ximage[0] );
158             p_vout->p_sys->p_ximage[0] = NULL;
159             p_vout->p_sys->p_ximage[1] = NULL;
160             return( 1 );
161         }
162     }
163
164     /* Set bytes per line */
165     p_vout->i_bytes_per_line = p_vout->p_sys->p_ximage[0]->bytes_per_line;    
166
167     /* Set buffer index to 0 */
168     p_vout->p_sys->i_buffer_index = 0;
169     return( 0 );
170 }
171
172 /*******************************************************************************
173  * vout_SysEnd: terminate X11 video thread output method
174  *******************************************************************************
175  * Destroy the X11 XImages created by vout_SysInit. It is called at the end of 
176  * the thread, but also each time the window is resized.
177  *******************************************************************************/
178 void vout_SysEnd( vout_thread_t *p_vout )
179 {
180     if( p_vout->p_sys->b_shm )                              /* Shm XImages... */
181     {
182         X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0], 
183                             &p_vout->p_sys->shm_info[0] );
184         X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[1], 
185                             &p_vout->p_sys->shm_info[1] );
186     }
187     else                                          /* ...or regular XImages */
188     {
189         X11DestroyImage( p_vout->p_sys->p_ximage[0] );
190         X11DestroyImage( p_vout->p_sys->p_ximage[1] );
191     }
192 }
193
194 /*******************************************************************************
195  * vout_SysDestroy: destroy X11 video thread output method
196  *******************************************************************************
197  * Terminate an output method created by vout_X11CreateOutputMethod
198  *******************************************************************************/
199 void vout_SysDestroy( vout_thread_t *p_vout )
200 {
201     X11CloseDisplay( p_vout );
202     free( p_vout->p_sys );
203 }
204
205 /*******************************************************************************
206  * vout_SysManage: handle X11 events
207  *******************************************************************************
208  * This function should be called regularly by video output thread. It manages
209  * X11 events and allows window resizing. It returns a negative value if 
210  * something happened which does not allow the thread to continue, and a 
211  * positive one if the thread can go on, but the images have been modified and
212  * therefore it is useless to display them.
213  *******************************************************************************/
214 int vout_SysManage( vout_thread_t *p_vout )
215 {
216     if( (p_vout->i_width != p_vout->i_new_width) || 
217         (p_vout->i_height != p_vout->i_new_height) )
218     {
219         /* Resize window */
220         XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 
221                        p_vout->i_new_width, p_vout->i_new_height );
222
223         /* Destroy then recreate XImages to change their size */
224         vout_SysEnd( p_vout );
225         p_vout->i_width = p_vout->i_new_width;
226         p_vout->i_height = p_vout->i_new_height;
227         // ?? bpl
228         vout_SysInit( p_vout );        
229
230         /* Cancel current display */
231         return( 1 );        
232     }
233     
234     return 0;
235 }
236
237 /*******************************************************************************
238  * vout_SysDisplay: displays previously rendered output
239  *******************************************************************************
240  * This function send the currently rendered image to X11 server, wait until
241  * it is displayed and switch the two rendering buffer, preparing next frame.
242  *******************************************************************************/
243 void vout_SysDisplay( vout_thread_t *p_vout )
244 {
245     if( p_vout->p_sys->b_shm)                                  /* XShm is used */
246     {
247         /* Display rendered image using shared memory extension */
248         XShmPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc, 
249                      p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ], 
250                      0, 0, 0, 0,  
251                      p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,  
252                      p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height, True);
253
254         /* Send the order to the X server */
255         XFlush(p_vout->p_sys->p_display);
256     }
257     else                                  /* regular X11 capabilities are used */
258     {
259         XPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc, 
260                   p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ], 
261                   0, 0, 0, 0,  
262                   p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,  
263                   p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height);
264
265         /* Send the order to the X server */
266         XFlush(p_vout->p_sys->p_display);       /* ?? not needed ? */
267     }
268
269     /* Swap buffers */
270     p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
271 }
272
273 /*******************************************************************************
274  * vout_SysGetPicture: get current display buffer informations
275  *******************************************************************************
276  * This function returns the address of the current display buffer.
277  *******************************************************************************/
278 void * vout_SysGetPicture( vout_thread_t *p_vout )
279 {
280     return( p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data );        
281 }
282
283 /*******************************************************************************
284  * vout_SysPrint: print simple text on a picture
285  *******************************************************************************
286  * This function will print a simple text on the picture. It is designed to
287  * print debugging or general informations, not to render subtitles.
288  * Since there is no way to print text on an Ximage directly, this function
289  * copy directly the pixels from a font.
290  *******************************************************************************/
291 void vout_SysPrint( vout_thread_t *p_vout, int i_x, int i_y, int i_halign, 
292                     int i_valign, unsigned char *psz_text )
293 {
294     int                 i_line;                    /* line in character matrix */
295     int                 i_byte;               /* byte offset in character line */    
296     int                 i_height;                          /* character height */    
297     int                 i_char_bytes_per_line;         /* total bytes per line */
298     byte_t *            pi_pic;                                /* picture data */
299     byte_t *            pi_char;                             /* character data */
300
301     /* Update upper left coordinates according to alignment */
302     switch( i_halign )
303     {
304     case 0:                                                        /* centered */
305         i_x -= p_vout->p_sys->i_char_interspacing * strlen( psz_text ) / 2;
306         break;        
307     case 1:                                                   /* right aligned */
308         i_x -= p_vout->p_sys->i_char_interspacing * strlen( psz_text );
309         break;                
310     }
311     switch( i_valign )
312     {
313     case 0:                                                        /* centered */
314         i_y -= p_vout->p_sys->i_char_height / 2;
315         break;        
316     case 1:                                                   /* bottom aligned */
317         i_y -= p_vout->p_sys->i_char_height;
318         break;                
319     }
320
321     /* Copy used variables to local */
322     i_height =                  p_vout->p_sys->i_char_height;
323     i_char_bytes_per_line =     p_vout->p_sys->i_char_bytes_per_line;    
324
325     /* Print text */
326     for( ; *psz_text != '\0'; psz_text++ )
327     {
328         if( (*psz_text >= VOUT_MIN_CHAR) && (*psz_text < VOUT_MAX_CHAR) )
329         {            
330             /* Select character */
331             pi_char =   p_vout->p_sys->pi_font + (*psz_text - VOUT_MIN_CHAR) * 
332                 i_height * i_char_bytes_per_line;
333             pi_pic =    p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data +
334                 i_y * p_vout->i_bytes_per_line + i_x * p_vout->i_bytes_per_pixel;
335
336             /* Copy character */
337             for( i_line = 0; i_line < i_height; i_line++ )
338             {
339                 /* Copy line */
340                 for( i_byte = 0; i_byte < i_char_bytes_per_line; i_byte++ )
341                 {
342                     pi_pic[ i_byte  ] = *pi_char++;                                
343                 }
344                 
345                 /* Go to next line */
346                 pi_pic += p_vout->i_bytes_per_line;
347             }
348         }
349
350         /* Jump to next character */
351         i_x += p_vout->p_sys->i_char_interspacing;
352     }
353 }
354
355 /* following functions are local */
356
357 /*******************************************************************************
358  * X11OpenDisplay: open and initialize X11 device 
359  *******************************************************************************
360  * Create a window according to video output given size, and set other 
361  * properties according to the display properties.
362  *******************************************************************************/
363 static int X11OpenDisplay( vout_thread_t *p_vout, char *psz_display, Window root_window )
364 {
365     /* Open display */
366     p_vout->p_sys->p_display = XOpenDisplay( psz_display );
367     if( p_vout->p_sys->p_display == NULL )
368     {
369         intf_ErrMsg("error: can't open display %s\n", psz_display );        
370         return( 1 );        
371     }
372
373     /* Initialize structure */
374     p_vout->p_sys->root_window  = root_window;
375     p_vout->p_sys->b_shm        = VOUT_XSHM && 
376         (XShmQueryExtension(p_vout->p_sys->p_display) == True);
377     p_vout->p_sys->i_screen     = DefaultScreen( p_vout->p_sys->p_display );
378
379     /* Get the screen depth */
380     p_vout->i_screen_depth = DefaultDepth( p_vout->p_sys->p_display, 
381                                            p_vout->p_sys->i_screen );
382     switch( p_vout->i_screen_depth )
383     {
384     case 15:                        /* 15 bpp (16bpp with a missing green bit) */
385     case 16:                                          /* 16 bpp (65536 colors) */
386         p_vout->i_bytes_per_pixel = 2;
387         break;
388     case 24:                                    /* 24 bpp (millions of colors) */
389         p_vout->i_bytes_per_pixel = 3;
390         break;
391     case 32:                                    /* 32 bpp (millions of colors) */
392         p_vout->i_bytes_per_pixel = 4;
393         break;
394     default:                                       /* unsupported screen depth */
395         intf_ErrMsg("error: screen depth %d is not supported\n", 
396                     p_vout->i_screen_depth);    
397         XCloseDisplay( p_vout->p_sys->p_display );        
398         return( 1  );
399         break;
400     }    
401
402     /* Create a window */
403     if( X11CreateWindow( p_vout ) )
404     {
405         intf_ErrMsg("error: can't open a window\n");        
406         XCloseDisplay( p_vout->p_sys->p_display );        
407         return( 1 );
408     }
409
410     /* Get font information */
411     if( X11GetFont( p_vout ) )
412     {
413         intf_ErrMsg("error: can't read default font\n");
414         X11DestroyWindow( p_vout );
415         XCloseDisplay( p_vout->p_sys->p_display );
416         return( 1 );        
417     }
418
419     return( 0 );    
420 }
421
422 /*******************************************************************************
423  * X11CloseDisplay: close X11 device 
424  *******************************************************************************
425  * Returns all resources allocated by X11OpenDisplay and restore the original
426  * state of the display.
427  *******************************************************************************/
428 static void X11CloseDisplay( vout_thread_t *p_vout )
429 {
430     // Free font info
431     free( p_vout->p_sys->pi_font );    
432
433     // Destroy window and close display
434     X11DestroyWindow( p_vout );
435     XCloseDisplay( p_vout->p_sys->p_display );    
436 }
437
438 /*******************************************************************************
439  * X11GetFont: get default font bitmap informations
440  *******************************************************************************
441  * This function will convert a font into a bitmap for later use by the 
442  * vout_SysPrint function.
443  *******************************************************************************/
444 static int X11GetFont( vout_thread_t *p_vout )
445 {
446     XFontStruct *       p_font_info;             /* font information structure */
447     Pixmap              pixmap;              /* pixmap used to draw characters */
448     GC                  gc;                                 /* graphic context */        
449     XGCValues           gc_values;               /* graphic context properties */    
450     XImage *            p_ximage;                      /* ximage for character */    
451     unsigned char       i_char;                             /* character index */    
452     int                 i_char_width;              /* character width (pixels) */
453     int                 i_char_bytes;                  /* total character size */        
454     
455     /* Load font */
456     p_font_info = XLoadQueryFont( p_vout->p_sys->p_display, "fixed" );
457     if( p_font_info == NULL )
458     {
459         intf_ErrMsg("error: can't load 'fixed' font\n");
460         return( 1 );        
461     }
462     
463     /* Get character size */
464     i_char_width =                              p_font_info->max_bounds.lbearing + 
465         p_font_info->max_bounds.rbearing;
466     p_vout->p_sys->i_char_bytes_per_line =      i_char_width * p_vout->i_bytes_per_pixel;    
467     p_vout->p_sys->i_char_height =              p_font_info->max_bounds.ascent + 
468         p_font_info->max_bounds.descent;
469     i_char_bytes =                              p_vout->p_sys->i_char_bytes_per_line *
470         p_vout->p_sys->i_char_height;    
471     p_vout->p_sys->i_char_interspacing =        p_font_info->max_bounds.width;    
472
473     /* Allocate font descriptor */
474     p_vout->p_sys->pi_font = malloc( i_char_bytes * ( VOUT_MAX_CHAR - VOUT_MIN_CHAR ) );
475     if( p_vout->p_sys->pi_font == NULL )
476     {
477         intf_ErrMsg("error: %s\n", strerror( ENOMEM ) );
478         XFreeFont( p_vout->p_sys->p_display, p_font_info );
479         return( 1 );        
480     }   
481
482     /* Create drawable and graphic context */
483     gc_values.foreground =      XBlackPixel( p_vout->p_sys->p_display, 
484                                              p_vout->p_sys->i_screen );
485     gc_values.background =      XBlackPixel( p_vout->p_sys->p_display, 
486                                              p_vout->p_sys->i_screen );
487     gc_values.font =            p_font_info->fid;    
488     pixmap = XCreatePixmap( p_vout->p_sys->p_display, p_vout->p_sys->window,
489                             i_char_width,
490                             p_vout->p_sys->i_char_height *(VOUT_MAX_CHAR-VOUT_MIN_CHAR),
491                             p_vout->i_screen_depth );    
492     gc = XCreateGC( p_vout->p_sys->p_display, pixmap, 
493                     GCForeground | GCBackground | GCFont, &gc_values );
494
495     /* Clear pixmap and invert graphic context */
496     XFillRectangle( p_vout->p_sys->p_display, pixmap, gc, 0, 0, i_char_width, 
497                     p_vout->p_sys->i_char_height*(VOUT_MAX_CHAR-VOUT_MIN_CHAR) );    
498     XSetForeground( p_vout->p_sys->p_display, gc, 
499                     XWhitePixel( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
500     XSetBackground( p_vout->p_sys->p_display, gc, 
501                     XBlackPixel( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
502
503     /* Copy characters bitmaps to font descriptor */
504     for( i_char = VOUT_MIN_CHAR; i_char < VOUT_MAX_CHAR; i_char++ )
505     {    
506         XDrawString( p_vout->p_sys->p_display, pixmap, gc, 0,
507                      p_font_info->max_bounds.ascent + 
508                      (i_char-VOUT_MIN_CHAR) * p_vout->p_sys->i_char_height,
509                      &i_char, 1 );
510     }
511     p_ximage = XGetImage( p_vout->p_sys->p_display, pixmap, 0, 0, i_char_width,
512                           p_vout->p_sys->i_char_height*(VOUT_MAX_CHAR-VOUT_MIN_CHAR),
513                           -1, ZPixmap );        
514     memcpy( p_vout->p_sys->pi_font, p_ximage->data, 
515             i_char_bytes*(VOUT_MAX_CHAR-VOUT_MIN_CHAR));        
516
517     /* Free resources, unload font and return */        
518     XDestroyImage( p_ximage ); 
519     XFreeGC( p_vout->p_sys->p_display, gc );
520     XFreePixmap( p_vout->p_sys->p_display, pixmap );
521     XFreeFont( p_vout->p_sys->p_display, p_font_info );
522     return( 0 );    
523 }
524
525 /*******************************************************************************
526  * X11CreateWindow: create X11 vout window
527  *******************************************************************************
528  * The video output window will be created. Normally, this window is wether 
529  * full screen or part of a parent window. Therefore, it does not need a 
530  * title or other hints. Thery are still supplied in case the window would be
531  * spawned as a standalone one by the interface.
532  *******************************************************************************/
533 static int X11CreateWindow( vout_thread_t *p_vout )
534 {
535     XSetWindowAttributes    xwindow_attributes;
536     XGCValues               xgcvalues;
537     XEvent                  xevent;
538     boolean_t               b_expose;
539     boolean_t               b_map_notify;    
540
541     /* Prepare window attributes */
542     xwindow_attributes.backing_store = Always;         /* save the hidden part */
543  
544     /* Create the window and set hints */
545     p_vout->p_sys->window = XCreateSimpleWindow( p_vout->p_sys->p_display,
546                                                  p_vout->p_sys->root_window,
547                                                  0, 0, 
548                                                  p_vout->i_width, p_vout->i_height,
549                                                  0, 0, 0);
550     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window, 
551                   ExposureMask | StructureNotifyMask );
552     XChangeWindowAttributes( p_vout->p_sys->p_display, p_vout->p_sys->window, 
553                              CWBackingStore, &xwindow_attributes);
554
555     /* Creation of a graphic context that doesn't generate a GraphicsExpose event
556        when using functions like XCopyArea */
557     xgcvalues.graphics_exposures = False;    
558     p_vout->p_sys->gc =  XCreateGC( p_vout->p_sys->p_display, p_vout->p_sys->window,
559                                     GCGraphicsExposures, &xgcvalues);
560
561     /* Send orders to server, and wait until window is displayed - two events
562      * must be received: a MapNotify event, an Expose event allowing drawing in the
563      * window */
564     b_expose = 0;
565     b_map_notify = 0;
566     XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
567     do
568     {
569         XNextEvent( p_vout->p_sys->p_display, &xevent);
570         if( (xevent.type == Expose) 
571             && (xevent.xexpose.window == p_vout->p_sys->window) )
572         {
573             b_expose = 1;
574         }
575         else if( (xevent.type == MapNotify) 
576                  && (xevent.xmap.window == p_vout->p_sys->window) )
577         {
578             b_map_notify = 1;
579         }
580     }
581     while( !( b_expose && b_map_notify ) );
582     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window, 0 );
583
584     /* At this stage, the window is openned, displayed, and ready to receive 
585      * data */
586     return( 0 );
587 }
588
589 /*******************************************************************************
590  * X11DestroyWindow: destroy X11 window
591  *******************************************************************************
592  * Destroy an X11 window created by vout_X11CreateWindow
593  *******************************************************************************/
594 static void X11DestroyWindow( vout_thread_t *p_vout )
595 {
596     XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
597     XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
598     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
599 }
600
601 /*******************************************************************************
602  * X11CreateImage: create an XImage                                      
603  *******************************************************************************
604  * Create a simple XImage used as a buffer.
605  *******************************************************************************/
606 static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
607 {
608     byte_t *    pb_data;                            /* image data storage zone */
609     int         i_quantum;                       /* XImage quantum (see below) */
610   
611     /* Allocate memory for image */
612     p_vout->i_bytes_per_line = p_vout->i_width * p_vout->i_bytes_per_pixel;    
613     pb_data = (byte_t *) malloc( p_vout->i_bytes_per_line * p_vout->i_height );
614     if( !pb_data )                                                    /* error */
615     {
616         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
617         return( 1 );   
618     }
619
620     /* Optimize the quantum of a scanline regarding its size - the quantum is
621        a diviser of the number of bits between the start of two scanlines. */
622     if( !(( p_vout->i_bytes_per_line ) % 32) )
623     {
624         i_quantum = 32;
625     }
626     else    
627     {
628         if( !(( p_vout->i_bytes_per_line ) % 16) )
629         {
630             i_quantum = 16;
631         }
632         else
633         {
634             i_quantum = 8;
635         }
636     }
637     
638     /* Create XImage */
639     *pp_ximage = XCreateImage( p_vout->p_sys->p_display, 
640                                DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
641                                p_vout->i_screen_depth, ZPixmap, 0, pb_data, 
642                                p_vout->i_width, p_vout->i_height, i_quantum, 0);
643     if(! *pp_ximage )                                                 /* error */
644     {
645         intf_ErrMsg( "error: XCreateImage() failed\n" );
646         free( pb_data );
647         return( 1 );
648     }
649
650     return 0;
651 }
652
653 /*******************************************************************************
654  * X11CreateShmImage: create an XImage using shared memory extension
655  *******************************************************************************
656  * Prepare an XImage for DisplayX11ShmImage function.
657  * The order of the operations respects the recommandations of the mit-shm 
658  * document by J.Corbet and K.Packard. Most of the parameters were copied from 
659  * there.
660  *******************************************************************************/
661 static int X11CreateShmImage( vout_thread_t *p_vout, XImage **pp_ximage, 
662                               XShmSegmentInfo *p_shm_info)
663 {
664     /* Create XImage */
665     *pp_ximage = XShmCreateImage( p_vout->p_sys->p_display, 
666                                   DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
667                                   p_vout->i_screen_depth, ZPixmap, 0, 
668                                   p_shm_info, p_vout->i_width, p_vout->i_height );
669     if(! *pp_ximage )                                                 /* error */
670     {
671         intf_ErrMsg("error: XShmCreateImage() failed\n");
672         return( 1 );
673     }
674
675     /* Allocate shared memory segment - 0777 set the access permission
676      * rights (like umask), they are not yet supported by X servers */
677     p_shm_info->shmid = shmget( IPC_PRIVATE, 
678                                 (*pp_ximage)->bytes_per_line * (*pp_ximage)->height, 
679                                 IPC_CREAT | 0777);
680     if( p_shm_info->shmid < 0)                                        /* error */
681     {
682         intf_ErrMsg("error: can't allocate shared image data (%s)\n",
683                     strerror(errno));
684         XDestroyImage( *pp_ximage );
685         return( 1 );
686     }
687
688     /* Attach shared memory segment to process (read/write) */
689     p_shm_info->shmaddr = (*pp_ximage)->data = shmat(p_shm_info->shmid, 0, 0);
690     if(! p_shm_info->shmaddr )
691     {                                                                 /* error */
692         intf_ErrMsg("error: can't attach shared memory (%s)\n",
693                     strerror(errno));
694         shmctl( p_shm_info->shmid, IPC_RMID, 0 );        /* free shared memory */
695         XDestroyImage( *pp_ximage );
696         return( 1 );
697     }
698
699     /* Mark the shm segment to be removed when there will be no more
700      * attachements, so it is automatic on process exit or after shmdt */
701     shmctl( p_shm_info->shmid, IPC_RMID, 0 );
702
703     /* Attach shared memory segment to X server (read only) */
704     p_shm_info->readOnly = True;
705     if( XShmAttach( p_vout->p_sys->p_display, p_shm_info ) == False )    /* error */
706     {
707         intf_ErrMsg("error: can't attach shared memory to X11 server\n");
708         shmdt( p_shm_info->shmaddr );     /* detach shared memory from process
709                                            * and automatic free                */
710         XDestroyImage( *pp_ximage );
711         return( 1 );
712     }
713
714     /* Send image to X server. This instruction is required, since having 
715      * built a Shm XImage and not using it causes an error on XCloseDisplay */
716     XFlush( p_vout->p_sys->p_display );    
717     return( 0 );
718 }
719
720 /*******************************************************************************
721  * X11DestroyImage: destroy an XImage                                  
722  *******************************************************************************
723  * Destroy XImage AND associated data. If pointer is NULL, the image won't be
724  * destroyed (see vout_X11ManageOutputMethod())
725  *******************************************************************************/
726 static void X11DestroyImage( XImage *p_ximage )
727 {
728     if( p_ximage != NULL )
729     {
730         XDestroyImage( p_ximage );                       /* no free() required */
731     }
732 }
733
734 /*******************************************************************************
735  * X11DestroyShmImage                                                    
736  *******************************************************************************
737  * Destroy XImage AND associated data. Detach shared memory segment from
738  * server and process, then free it. If pointer is NULL, the image won't be
739  * destroyed (see vout_X11ManageOutputMethod()) 
740  *******************************************************************************/
741 static void X11DestroyShmImage( vout_thread_t *p_vout, XImage *p_ximage, 
742                                 XShmSegmentInfo *p_shm_info )
743 {
744     /* If pointer is NULL, do nothing */
745     if( p_ximage == NULL )
746     {
747         return;
748     }
749
750     XShmDetach( p_vout->p_sys->p_display, p_shm_info );     /* detach from server */
751     XDestroyImage( p_ximage );
752     if( shmdt( p_shm_info->shmaddr ) )    /* detach shared memory from process */
753     {                                     /* also automatic freeing...         */
754         intf_ErrMsg("error: can't detach shared memory (%s)\n", 
755                     strerror(errno));
756     }
757 }
758