]> git.sesse.net Git - vlc/blob - src/video_output/video_x11.c
Ajout d'une fonction de deboguage � UnlinkPicture
[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, int i_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, i_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("Video: XShm 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_ErrMsg("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_ErrMsg("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 non null value on 
210  * error.
211  *******************************************************************************/
212 int vout_SysManage( vout_thread_t *p_vout )
213 {
214     if( p_vout->i_changes & VOUT_SIZE_CHANGE ) 
215     {        
216         intf_DbgMsg("resizing window\n");      
217         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;        
218
219         /* Resize window */
220         XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 
221                        p_vout->i_width, p_vout->i_height );
222
223         /* Destroy XImages to change their size */
224         vout_SysEnd( p_vout );
225
226         /* Recreate XImages. If SysInit failed, the thread can't go on. */
227         if( vout_SysInit( p_vout ) )
228         {
229             intf_ErrMsg("error: can't resize display\n");
230             return( 1 );            
231         }
232         intf_Msg("Video: display resized to %dx%d\n", p_vout->i_width, p_vout->i_height);            
233     }
234     
235     return 0;
236 }
237
238 /*******************************************************************************
239  * vout_SysDisplay: displays previously rendered output
240  *******************************************************************************
241  * This function send the currently rendered image to X11 server, wait until
242  * it is displayed and switch the two rendering buffer, preparing next frame.
243  *******************************************************************************/
244 void vout_SysDisplay( vout_thread_t *p_vout )
245 {
246     if( p_vout->p_sys->b_shm)                                  /* XShm is used */
247     {
248         /* Display rendered image using shared memory extension */
249         XShmPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc, 
250                      p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ], 
251                      0, 0, 0, 0,  
252                      p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,  
253                      p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height, True);
254
255         /* Send the order to the X server */
256         XFlush(p_vout->p_sys->p_display);
257     }
258     else                                  /* regular X11 capabilities are used */
259     {
260         XPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc, 
261                   p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ], 
262                   0, 0, 0, 0,  
263                   p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,  
264                   p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height);
265
266         /* Send the order to the X server */
267         XFlush(p_vout->p_sys->p_display);
268     }
269
270     /* Swap buffers */
271     p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
272 }
273
274 /*******************************************************************************
275  * vout_SysGetPicture: get current display buffer informations
276  *******************************************************************************
277  * This function returns the address of the current display buffer.
278  *******************************************************************************/
279 void * vout_SysGetPicture( vout_thread_t *p_vout )
280 {
281     return( p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data );        
282 }
283
284 /*******************************************************************************
285  * vout_SysPrint: print simple text on a picture
286  *******************************************************************************
287  * This function will print a simple text on the picture. It is designed to
288  * print debugging or general informations, not to render subtitles.
289  * Since there is no way to print text on an Ximage directly, this function
290  * copy directly the pixels from a font.
291  *******************************************************************************/
292 void vout_SysPrint( vout_thread_t *p_vout, int i_x, int i_y, int i_halign, 
293                     int i_valign, unsigned char *psz_text )
294 {
295     int                 i_line;                    /* line in character matrix */
296     int                 i_byte;               /* byte offset in character line */    
297     int                 i_height;                          /* character height */    
298     int                 i_char_bytes_per_line;         /* total bytes per line */
299     int                 i_text_width;                      /* total text width */
300     byte_t *            pi_pic;                                /* picture data */
301     byte_t *            pi_char;                             /* character data */
302
303     /* Update upper left coordinates according to alignment */
304     i_text_width = p_vout->p_sys->i_char_interspacing * strlen( psz_text );    
305     switch( i_halign )
306     {
307     case 0:                                                        /* centered */
308         i_x -= i_text_width / 2;
309         break;        
310     case 1:                                                   /* right aligned */
311         i_x -= i_text_width;
312         break;                
313     }
314     switch( i_valign )
315     {
316     case 0:                                                        /* centered */
317         i_y -= p_vout->p_sys->i_char_height / 2;
318         break;        
319     case 1:                                                   /* bottom aligned */
320         i_y -= p_vout->p_sys->i_char_height;
321         break;                
322     }
323
324     /* Copy used variables to local */
325     i_height =                  p_vout->p_sys->i_char_height;
326     i_char_bytes_per_line =     p_vout->p_sys->i_char_bytes_per_line;    
327
328     /* Check that the text is in the screen vertically and horizontally */
329     if( (i_y < 0) || (i_y + i_height > p_vout->i_height) || (i_x < 0) ||
330         (i_x + i_text_width > p_vout->i_width) )
331     {
332         intf_DbgMsg("text '%s' would print outside the screen\n", psz_text);        
333         return;        
334     }    
335
336     /* Print text */
337     for( ; *psz_text != '\0'; psz_text++ )
338     {
339         /* Check that the character is valid and in the screen horizontally */
340         if( (*psz_text >= VOUT_MIN_CHAR) && (*psz_text < VOUT_MAX_CHAR) )
341         {       
342             /* Select character */
343             pi_char =   p_vout->p_sys->pi_font + (*psz_text - VOUT_MIN_CHAR) * 
344                 i_height * i_char_bytes_per_line;
345             pi_pic =    p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data +
346                 i_y * p_vout->i_bytes_per_line + i_x * p_vout->i_bytes_per_pixel;
347
348             /* Copy character */
349             for( i_line = 0; i_line < i_height; i_line++ )
350             {
351                 /* Copy line */
352                 for( i_byte = 0; i_byte < i_char_bytes_per_line; i_byte++ )
353                 {
354                     pi_pic[ i_byte  ] = *pi_char++;                                
355                 }
356                 
357                 /* Go to next line */
358                 pi_pic += p_vout->i_bytes_per_line;
359             }
360         }
361
362         /* Jump to next character */
363         i_x += p_vout->p_sys->i_char_interspacing;
364     }
365 }
366
367 /* following functions are local */
368
369 /*******************************************************************************
370  * X11OpenDisplay: open and initialize X11 device 
371  *******************************************************************************
372  * Create a window according to video output given size, and set other 
373  * properties according to the display properties.
374  *******************************************************************************/
375 static int X11OpenDisplay( vout_thread_t *p_vout, char *psz_display, Window root_window )
376 {
377     /* Open display */
378     p_vout->p_sys->p_display = XOpenDisplay( psz_display );
379     if( p_vout->p_sys->p_display == NULL )
380     {
381         intf_ErrMsg("error: can't open display %s\n", psz_display );        
382         return( 1 );        
383     }
384
385     /* Initialize structure */
386     p_vout->p_sys->root_window  = root_window;
387     p_vout->p_sys->b_shm        = (XShmQueryExtension(p_vout->p_sys->p_display) == True);
388     p_vout->p_sys->i_screen     = DefaultScreen( p_vout->p_sys->p_display );
389     if( !p_vout->p_sys->b_shm )
390     {        
391         intf_Msg("Video: XShm extension is not available\n");    
392     }    
393
394     /* Get the screen depth */
395     p_vout->i_screen_depth = DefaultDepth( p_vout->p_sys->p_display, 
396                                            p_vout->p_sys->i_screen );
397     switch( p_vout->i_screen_depth )
398     {
399     case 15:                        /* 15 bpp (16bpp with a missing green bit) */
400     case 16:                                          /* 16 bpp (65536 colors) */
401         p_vout->i_bytes_per_pixel = 2;
402         break;
403     case 24:                                    /* 24 bpp (millions of colors) */
404         p_vout->i_bytes_per_pixel = 3;
405         break;
406     case 32:                                    /* 32 bpp (millions of colors) */
407         p_vout->i_bytes_per_pixel = 4;
408         break;
409     default:                                       /* unsupported screen depth */
410         intf_ErrMsg("error: screen depth %d is not supported\n", 
411                     p_vout->i_screen_depth);    
412         XCloseDisplay( p_vout->p_sys->p_display );        
413         return( 1  );
414         break;
415     }    
416
417     /* Create a window */
418     if( X11CreateWindow( p_vout ) )
419     {
420         intf_ErrMsg("error: can't open a window\n");        
421         XCloseDisplay( p_vout->p_sys->p_display );        
422         return( 1 );
423     }
424
425     /* Get font information */
426     if( X11GetFont( p_vout ) )
427     {
428         intf_ErrMsg("error: can't read default font\n");
429         X11DestroyWindow( p_vout );
430         XCloseDisplay( p_vout->p_sys->p_display );
431         return( 1 );        
432     }
433
434     return( 0 );    
435 }
436
437 /*******************************************************************************
438  * X11CloseDisplay: close X11 device 
439  *******************************************************************************
440  * Returns all resources allocated by X11OpenDisplay and restore the original
441  * state of the display.
442  *******************************************************************************/
443 static void X11CloseDisplay( vout_thread_t *p_vout )
444 {
445     // Free font info
446     free( p_vout->p_sys->pi_font );    
447
448     // Destroy window and close display
449     X11DestroyWindow( p_vout );
450     XCloseDisplay( p_vout->p_sys->p_display );    
451 }
452
453 /*******************************************************************************
454  * X11GetFont: get default font bitmap informations
455  *******************************************************************************
456  * This function will convert a font into a bitmap for later use by the 
457  * vout_SysPrint function.
458  *******************************************************************************/
459 static int X11GetFont( vout_thread_t *p_vout )
460 {
461     XFontStruct *       p_font_info;             /* font information structure */
462     Pixmap              pixmap;              /* pixmap used to draw characters */
463     GC                  gc;                                 /* graphic context */        
464     XGCValues           gc_values;               /* graphic context properties */    
465     XImage *            p_ximage;                      /* ximage for character */    
466     unsigned char       i_char;                             /* character index */    
467     int                 i_char_width;              /* character width (pixels) */
468     int                 i_char_bytes;                  /* total character size */        
469     
470     /* Load font */
471     p_font_info = XLoadQueryFont( p_vout->p_sys->p_display, "fixed" );
472     if( p_font_info == NULL )
473     {
474         intf_ErrMsg("error: can't load 'fixed' font\n");
475         return( 1 );        
476     }
477     
478     /* Get character size */
479     i_char_width =                              p_font_info->max_bounds.lbearing + 
480         p_font_info->max_bounds.rbearing;
481     p_vout->p_sys->i_char_bytes_per_line =      i_char_width * p_vout->i_bytes_per_pixel;    
482     p_vout->p_sys->i_char_height =              p_font_info->max_bounds.ascent + 
483         p_font_info->max_bounds.descent;
484     i_char_bytes =                              p_vout->p_sys->i_char_bytes_per_line *
485         p_vout->p_sys->i_char_height;    
486     p_vout->p_sys->i_char_interspacing =        p_font_info->max_bounds.width;    
487
488     /* Allocate font descriptor */
489     p_vout->p_sys->pi_font = malloc( i_char_bytes * ( VOUT_MAX_CHAR - VOUT_MIN_CHAR ) );
490     if( p_vout->p_sys->pi_font == NULL )
491     {
492         intf_ErrMsg("error: %s\n", strerror( ENOMEM ) );
493         XFreeFont( p_vout->p_sys->p_display, p_font_info );
494         return( 1 );        
495     }   
496
497     /* Create drawable and graphic context */
498     gc_values.foreground =      XBlackPixel( p_vout->p_sys->p_display, 
499                                              p_vout->p_sys->i_screen );
500     gc_values.background =      XBlackPixel( p_vout->p_sys->p_display, 
501                                              p_vout->p_sys->i_screen );
502     gc_values.font =            p_font_info->fid;    
503     pixmap = XCreatePixmap( p_vout->p_sys->p_display, p_vout->p_sys->window,
504                             i_char_width,
505                             p_vout->p_sys->i_char_height *(VOUT_MAX_CHAR-VOUT_MIN_CHAR),
506                             p_vout->i_screen_depth );    
507     gc = XCreateGC( p_vout->p_sys->p_display, pixmap, 
508                     GCForeground | GCBackground | GCFont, &gc_values );
509
510     /* Clear pixmap and invert graphic context */
511     XFillRectangle( p_vout->p_sys->p_display, pixmap, gc, 0, 0, i_char_width, 
512                     p_vout->p_sys->i_char_height*(VOUT_MAX_CHAR-VOUT_MIN_CHAR) );    
513     XSetForeground( p_vout->p_sys->p_display, gc, 
514                     XWhitePixel( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
515     XSetBackground( p_vout->p_sys->p_display, gc, 
516                     XBlackPixel( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
517
518     /* Copy characters bitmaps to font descriptor */
519     for( i_char = VOUT_MIN_CHAR; i_char < VOUT_MAX_CHAR; i_char++ )
520     {    
521         XDrawString( p_vout->p_sys->p_display, pixmap, gc, 0,
522                      p_font_info->max_bounds.ascent + 
523                      (i_char-VOUT_MIN_CHAR) * p_vout->p_sys->i_char_height,
524                      &i_char, 1 );
525     }
526     p_ximage = XGetImage( p_vout->p_sys->p_display, pixmap, 0, 0, i_char_width,
527                           p_vout->p_sys->i_char_height*(VOUT_MAX_CHAR-VOUT_MIN_CHAR),
528                           -1, ZPixmap );        
529     memcpy( p_vout->p_sys->pi_font, p_ximage->data, 
530             i_char_bytes*(VOUT_MAX_CHAR-VOUT_MIN_CHAR));        
531
532     /* Free resources, unload font and return */        
533     XDestroyImage( p_ximage ); 
534     XFreeGC( p_vout->p_sys->p_display, gc );
535     XFreePixmap( p_vout->p_sys->p_display, pixmap );
536     XFreeFont( p_vout->p_sys->p_display, p_font_info );
537     return( 0 );    
538 }
539
540 /*******************************************************************************
541  * X11CreateWindow: create X11 vout window
542  *******************************************************************************
543  * The video output window will be created. Normally, this window is wether 
544  * full screen or part of a parent window. Therefore, it does not need a 
545  * title or other hints. Thery are still supplied in case the window would be
546  * spawned as a standalone one by the interface.
547  *******************************************************************************/
548 static int X11CreateWindow( vout_thread_t *p_vout )
549 {
550     XSetWindowAttributes    xwindow_attributes;
551     XGCValues               xgcvalues;
552     XEvent                  xevent;
553     boolean_t               b_expose;
554     boolean_t               b_map_notify;    
555
556     /* Prepare window attributes */
557     xwindow_attributes.backing_store = Always;         /* save the hidden part */
558  
559     /* Create the window and set hints */
560     p_vout->p_sys->window = XCreateSimpleWindow( p_vout->p_sys->p_display,
561                                                  p_vout->p_sys->root_window,
562                                                  0, 0, 
563                                                  p_vout->i_width, p_vout->i_height,
564                                                  0, 0, 0);
565     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window, 
566                   ExposureMask | StructureNotifyMask );
567     XChangeWindowAttributes( p_vout->p_sys->p_display, p_vout->p_sys->window, 
568                              CWBackingStore, &xwindow_attributes);
569
570     /* Creation of a graphic context that doesn't generate a GraphicsExpose event
571        when using functions like XCopyArea */
572     xgcvalues.graphics_exposures = False;    
573     p_vout->p_sys->gc =  XCreateGC( p_vout->p_sys->p_display, p_vout->p_sys->window,
574                                     GCGraphicsExposures, &xgcvalues);
575
576     /* Send orders to server, and wait until window is displayed - two events
577      * must be received: a MapNotify event, an Expose event allowing drawing in the
578      * window */
579     b_expose = 0;
580     b_map_notify = 0;
581     XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
582     do
583     {
584         XNextEvent( p_vout->p_sys->p_display, &xevent);
585         if( (xevent.type == Expose) 
586             && (xevent.xexpose.window == p_vout->p_sys->window) )
587         {
588             b_expose = 1;
589         }
590         else if( (xevent.type == MapNotify) 
591                  && (xevent.xmap.window == p_vout->p_sys->window) )
592         {
593             b_map_notify = 1;
594         }
595     }
596     while( !( b_expose && b_map_notify ) );
597     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window, 0 );
598
599     /* At this stage, the window is openned, displayed, and ready to receive 
600      * data */
601     return( 0 );
602 }
603
604 /*******************************************************************************
605  * X11DestroyWindow: destroy X11 window
606  *******************************************************************************
607  * Destroy an X11 window created by vout_X11CreateWindow
608  *******************************************************************************/
609 static void X11DestroyWindow( vout_thread_t *p_vout )
610 {
611     XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
612     XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
613     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
614 }
615
616 /*******************************************************************************
617  * X11CreateImage: create an XImage                                      
618  *******************************************************************************
619  * Create a simple XImage used as a buffer.
620  *******************************************************************************/
621 static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
622 {
623     byte_t *    pb_data;                            /* image data storage zone */
624     int         i_quantum;                       /* XImage quantum (see below) */
625   
626     /* Allocate memory for image */
627     p_vout->i_bytes_per_line = p_vout->i_width * p_vout->i_bytes_per_pixel;    
628     pb_data = (byte_t *) malloc( p_vout->i_bytes_per_line * p_vout->i_height );
629     if( !pb_data )                                                    /* error */
630     {
631         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
632         return( 1 );   
633     }
634
635     /* Optimize the quantum of a scanline regarding its size - the quantum is
636        a diviser of the number of bits between the start of two scanlines. */
637     if( !(( p_vout->i_bytes_per_line ) % 32) )
638     {
639         i_quantum = 32;
640     }
641     else    
642     {
643         if( !(( p_vout->i_bytes_per_line ) % 16) )
644         {
645             i_quantum = 16;
646         }
647         else
648         {
649             i_quantum = 8;
650         }
651     }
652     
653     /* Create XImage */
654     *pp_ximage = XCreateImage( p_vout->p_sys->p_display, 
655                                DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
656                                p_vout->i_screen_depth, ZPixmap, 0, pb_data, 
657                                p_vout->i_width, p_vout->i_height, i_quantum, 0);
658     if(! *pp_ximage )                                                 /* error */
659     {
660         intf_ErrMsg( "error: XCreateImage() failed\n" );
661         free( pb_data );
662         return( 1 );
663     }
664
665     return 0;
666 }
667
668 /*******************************************************************************
669  * X11CreateShmImage: create an XImage using shared memory extension
670  *******************************************************************************
671  * Prepare an XImage for DisplayX11ShmImage function.
672  * The order of the operations respects the recommandations of the mit-shm 
673  * document by J.Corbet and K.Packard. Most of the parameters were copied from 
674  * there.
675  *******************************************************************************/
676 static int X11CreateShmImage( vout_thread_t *p_vout, XImage **pp_ximage, 
677                               XShmSegmentInfo *p_shm_info)
678 {
679     /* Create XImage */
680     *pp_ximage = XShmCreateImage( p_vout->p_sys->p_display, 
681                                   DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
682                                   p_vout->i_screen_depth, ZPixmap, 0, 
683                                   p_shm_info, p_vout->i_width, p_vout->i_height );
684     if(! *pp_ximage )                                                 /* error */
685     {
686         intf_ErrMsg("error: XShmCreateImage() failed\n");
687         return( 1 );
688     }
689
690     /* Allocate shared memory segment - 0777 set the access permission
691      * rights (like umask), they are not yet supported by X servers */
692     p_shm_info->shmid = shmget( IPC_PRIVATE, 
693                                 (*pp_ximage)->bytes_per_line * (*pp_ximage)->height, 
694                                 IPC_CREAT | 0777);
695     if( p_shm_info->shmid < 0)                                        /* error */
696     {
697         intf_ErrMsg("error: can't allocate shared image data (%s)\n",
698                     strerror(errno));
699         XDestroyImage( *pp_ximage );
700         return( 1 );
701     }
702
703     /* Attach shared memory segment to process (read/write) */
704     p_shm_info->shmaddr = (*pp_ximage)->data = shmat(p_shm_info->shmid, 0, 0);
705     if(! p_shm_info->shmaddr )
706     {                                                                 /* error */
707         intf_ErrMsg("error: can't attach shared memory (%s)\n",
708                     strerror(errno));
709         shmctl( p_shm_info->shmid, IPC_RMID, 0 );        /* free shared memory */
710         XDestroyImage( *pp_ximage );
711         return( 1 );
712     }
713
714     /* Mark the shm segment to be removed when there will be no more
715      * attachements, so it is automatic on process exit or after shmdt */
716     shmctl( p_shm_info->shmid, IPC_RMID, 0 );
717
718     /* Attach shared memory segment to X server (read only) */
719     p_shm_info->readOnly = True;
720     if( XShmAttach( p_vout->p_sys->p_display, p_shm_info ) == False )    /* error */
721     {
722         intf_ErrMsg("error: can't attach shared memory to X11 server\n");
723         shmdt( p_shm_info->shmaddr );     /* detach shared memory from process
724                                            * and automatic free                */
725         XDestroyImage( *pp_ximage );
726         return( 1 );
727     }
728
729     /* Send image to X server. This instruction is required, since having 
730      * built a Shm XImage and not using it causes an error on XCloseDisplay */
731     XFlush( p_vout->p_sys->p_display );    
732     return( 0 );
733 }
734
735 /*******************************************************************************
736  * X11DestroyImage: destroy an XImage                                  
737  *******************************************************************************
738  * Destroy XImage AND associated data. If pointer is NULL, the image won't be
739  * destroyed (see vout_X11ManageOutputMethod())
740  *******************************************************************************/
741 static void X11DestroyImage( XImage *p_ximage )
742 {
743     if( p_ximage != NULL )
744     {
745         XDestroyImage( p_ximage );                       /* no free() required */
746     }
747 }
748
749 /*******************************************************************************
750  * X11DestroyShmImage                                                    
751  *******************************************************************************
752  * Destroy XImage AND associated data. Detach shared memory segment from
753  * server and process, then free it. If pointer is NULL, the image won't be
754  * destroyed (see vout_X11ManageOutputMethod()) 
755  *******************************************************************************/
756 static void X11DestroyShmImage( vout_thread_t *p_vout, XImage *p_ximage, 
757                                 XShmSegmentInfo *p_shm_info )
758 {
759     /* If pointer is NULL, do nothing */
760     if( p_ximage == NULL )
761     {
762         return;
763     }
764
765     XShmDetach( p_vout->p_sys->p_display, p_shm_info );     /* detach from server */
766     XDestroyImage( p_ximage );
767     if( shmdt( p_shm_info->shmaddr ) )    /* detach shared memory from process */
768     {                                     /* also automatic freeing...         */
769         intf_ErrMsg("error: can't detach shared memory (%s)\n", 
770                     strerror(errno));
771     }
772 }
773