]> git.sesse.net Git - vlc/blob - src/video_output/video_x11.c
A tout kass�.
[vlc] / src / video_output / video_x11.c
1 /*******************************************************************************
2  * vout_x11.c: X11 video output display method
3  * (c)1998 VideoLAN
4  *******************************************************************************
5  * The X11 method for video output thread. It's properties (and the vout_x11_t
6  * type) are defined in vout.h. The functions declared here should not be
7  * needed by any other module than vout.c.
8  *******************************************************************************/
9
10 /*******************************************************************************
11  * Preamble
12  *******************************************************************************/
13
14 #include "vlc.h"
15 /*
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <netinet/in.h>
21 #include <sys/shm.h>
22 #include <sys/soundcard.h>
23 #include <sys/uio.h>
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <X11/Xatom.h>
27 #include <X11/extensions/XShm.h>
28
29 #include "config.h"
30 #include "common.h"
31 #include "mtime.h"
32 #include "vlc_thread.h"
33 #include "xutils.h"
34
35 #include "input.h"
36 #include "input_vlan.h"
37
38 #include "audio_output.h"
39
40 #include "video.h"
41 #include "video_output.h"
42 #include "video_x11.h"
43
44 #include "xconsole.h"
45 #include "interface.h"
46 #include "intf_msg.h"
47 */
48
49 /*******************************************************************************
50  * vout_sys_t: video output X11 method descriptor
51  *******************************************************************************
52  * This structure is part of the video output thread descriptor.
53  * It describes the X11 specific properties of an output thread. X11 video 
54  * output is performed through regular resizable windows. Windows can be
55  * dynamically resized to adapt to the size of the streams.
56  *******************************************************************************/
57 typedef struct vout_sys_s
58 {
59     /* User settings */
60     boolean_t           b_shm;                 /* shared memory extension flag */
61
62     /* Internal settings and properties */
63     Display *           p_display;                          /* display pointer */
64     int                 i_screen;                             /* screen number */
65     Window              root_window;                            /* root window */
66     Window              window;                     /* window instance handler */
67     GC                  gc;                /* graphic context instance handler */    
68
69     /* Color maps and translation tables - some of those tables are shifted,
70      * see x11.c for more informations. */
71     u8 *                trans_16bpp_red;           /* red (16 bpp) (SHIFTED !) */
72     u8 *                trans_16bpp_green;       /* green (16 bpp) (SHIFTED !) */
73     u8 *                trans_16bpp_blue;         /* blue (16 bpp) (SHIFTED !) */
74
75     /* Display buffers and shared memory information */
76     int                 i_buffer_index;                        /* buffer index */
77     XImage *            p_ximage[2];                         /* XImage pointer */   
78     XShmSegmentInfo     shm_info[2];         /* shared memory zone information */
79
80     int                 i_completion_type;                               /* ?? */
81 } vout_sys_t;
82
83 /*******************************************************************************
84  * Local prototypes
85  *******************************************************************************/
86 static int  X11GetProperties        ( vout_thread_t *p_vout );
87 static int  X11CreateWindow         ( vout_thread_t *p_vout );
88 static int  X11CreateImages         ( vout_thread_t *p_vout );
89 static void X11DestroyImages        ( vout_thread_t *p_vout );
90 static void X11DestroyWindow        ( vout_thread_t *p_vout );
91 static int  X11CreateImage          ( vout_thread_t *p_vout, XImage **pp_ximage );
92 static void X11DestroyImage         ( XImage *p_ximage );
93 static int  X11CreateShmImage       ( vout_thread_t *p_vout, XImage **pp_ximage, 
94                                       XShmSegmentInfo *p_shm_info );
95 static void X11DestroyShmImage      ( vout_thread_t *p_vout, XImage *p_ximage, 
96                                       XShmSegmentInfo *p_shm_info );
97
98
99 /*******************************************************************************
100  * vout_SysCreate: allocate X11 video thread output method
101  *******************************************************************************
102  * This function allocate and initialize a X11 vout method.
103  *******************************************************************************/
104 int vout_SysCreate( vout_thread_t *p_vout, Display *p_display, Window root_window )
105 {
106     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );    
107     if( p_vout->p_sys != NULL )
108     {
109         p_vout->p_sys->p_display   = p_display;
110         p_vout->p_sys->root_window = root_window;
111         return( 0 );        
112     }
113
114     return( 1 );
115 }
116
117 /*******************************************************************************
118  * vout_SysInit: initialize X11 video thread output method
119  *******************************************************************************
120  * This function create a X11 window according to the user configuration.
121  *******************************************************************************/
122 int vout_SysInit( vout_thread_t *p_vout )
123 {
124     if( X11GetProperties( p_vout ) )                      /* get display properties */
125     {
126         return( 1 );
127     }
128     if( X11CreateWindow( p_vout ) )                           /* create window */
129     {
130         return( 1 );
131     }
132     if( X11CreateImages( p_vout ) )                           /* create images */
133     {
134         X11DestroyWindow( p_vout );
135         return( 1 );        
136     }
137     intf_DbgMsg("%p -> success, depth=%d bpp, Shm=%d\n", 
138                 p_vout, p_vout->i_screen_depth, p_vout->p_sys->b_shm );
139     return( 0 );
140 }
141
142 /*******************************************************************************
143  * vout_SysEnd: terminate X11 video thread output method
144  *******************************************************************************
145  * Terminate an output method created by vout_X11CreateOutputMethod
146  *******************************************************************************/
147 void vout_SysEnd( vout_thread_t *p_vout )
148 {
149     X11DestroyImages( p_vout );
150     X11DestroyWindow( p_vout );
151     intf_DbgMsg("%p\n", p_vout );
152 }
153
154 /*******************************************************************************
155  * vout_SysDestroy: destroy X11 video thread output method
156  *******************************************************************************
157  * Terminate an output method created by vout_X11CreateOutputMethod
158  *******************************************************************************/
159 void vout_SysDestroy( vout_thread_t *p_vout )
160 {
161     free( p_vout->p_sys );
162 }
163
164 /*******************************************************************************
165  * vout_SysManage: handle X11 events
166  *******************************************************************************
167  * This function should be called regularly by video output thread. It manages
168  * X11 events and allows window resizing. It returns a negative value if 
169  * something happened which does not allow the thread to continue, and a 
170  * positive one if the thread can go on, but the images have been modified and
171  * therefore it is useless to display them.
172  *******************************************************************************
173  * Messages type: vout, major code: 103
174  *******************************************************************************/
175 int vout_SysManage( vout_thread_t *p_vout )
176 {
177     boolean_t b_resized;
178     //??
179
180     /* ?? this function should not receive any usefull X11 messages, since they
181      * have tobe treated by the main interface window - check it. */
182     return 0; //??
183
184
185     /* If window has been resized, re-create images */
186     if( b_resized )
187     {
188         intf_DbgMsg("%p -> resizing window\n", p_vout);
189         X11DestroyImages( p_vout );
190         if( X11CreateImages( p_vout ) )
191         {
192             /* A fatal error occured: images could not be re-created. Note
193              * that in this case, the images pointers will be NULL, so the
194              * image destructor will know it does not need to destroy them. */
195             return( -1 );
196         }
197         return( 1 );        
198     }
199
200     return( 0 );
201 }
202
203 /*******************************************************************************
204  * vout_SysDisplay: displays previously rendered output
205  *******************************************************************************
206  * This function send the currently rendered image to X11 server, wait until
207  * it is displayed and switch the two rendering buffer, preparing next frame.
208  *******************************************************************************/
209 void vout_SysDisplay( vout_thread_t *p_vout )
210 {
211     if( p_vout->p_sys->b_shm)                                     /* XShm is used */
212     {
213         /* Display rendered image using shared memory extension */
214         XShmPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc, 
215                      p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ], 
216                      0, 0, 0, 0,  
217                      p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,  
218                      p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height, True);
219
220         /* Send the order to the X server */
221         XFlush(p_vout->p_sys->p_display);
222         
223         /* ?? wait until effective display ? */
224 /*        do XNextEvent(Display_Ptr, &xev);
225         while(xev.type!=CompletionType);*/
226     }
227     else                                  /* regular X11 capabilities are used */
228     {
229         XPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc, 
230                   p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ], 
231                   0, 0, 0, 0,  
232                   p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,  
233                   p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height);
234
235         /* Send the order to the X server */
236         XFlush(p_vout->p_sys->p_display);       /* ?? not needed ? */
237     }
238
239     /* Swap buffers */
240     p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
241 }
242
243 /* following functions are local */
244
245 /*******************************************************************************
246  * X11GetProperties: get properties of a given display
247  *******************************************************************************
248  * Opens an X11 display and try to detect usable X extensions.
249  *******************************************************************************/
250 static int X11GetProperties( vout_thread_t *p_vout )
251 {
252     /* Check if extensions are supported */
253     p_vout->p_sys->b_shm = VOUT_XSHM && (XShmQueryExtension(p_vout->p_sys->p_display) == True);
254
255     /* Get the screen number and depth (bpp) - select functions depending 
256      * of this value. i_bytes_per_pixel is required since on some hardware,
257      * depth as 15bpp are used, which can cause problems with later memory
258      * allocation. */
259     p_vout->p_sys->i_screen =   DefaultScreen( p_vout->p_sys->p_display );
260     p_vout->i_screen_depth = DefaultDepth( p_vout->p_sys->p_display, 
261                                            p_vout->p_sys->i_screen );
262     switch( p_vout->i_screen_depth )
263     {
264     case 15:                        /* 15 bpp (16bpp with a missing green bit) */
265         p_vout->i_bytes_per_pixel = 2;              
266         /*
267          ?? */
268         break;
269
270     case 16:                                          /* 16 bpp (65536 colors) */
271         p_vout->i_bytes_per_pixel = 2;
272        /*
273         Process_Frame=Translate_Frame;
274         Process_Top_Field=Translate_Top_Field;
275         Process_Bottom_Field=Translate_Bottom_Field;
276         Process_Top_Field420=Translate_Top_Field420;
277         Process_Bottom_Field420=Translate_Bottom_Field420; ?? */
278         break;
279
280     case 24:                                    /* 24 bpp (millions of colors) */
281         p_vout->i_bytes_per_pixel = 3;
282
283         /*
284         Process_Frame=Translate_Frame;
285         Process_Top_Field=Translate_Top_Field;
286         Process_Bottom_Field=Translate_Bottom_Field;
287         Process_Top_Field420=Translate_Top_Field420;
288         Process_Bottom_Field420=Translate_Bottom_Field420; ?? */
289         break;
290
291     case 32:                                    /* 32 bpp (millions of colors) */
292         p_vout->i_bytes_per_pixel = 4;
293         /*
294         Process_Frame=Translate_Frame;
295         Process_Top_Field=Translate_Top_Field;
296         Process_Bottom_Field=Translate_Bottom_Field;
297         Process_Top_Field420=Translate_Top_Field420;
298         Process_Bottom_Field420=Translate_Bottom_Field420; ?? */
299         break;
300
301     default:                                       /* unsupported screen depth */
302         intf_ErrMsg("vout error 106-2: screen depth %i is not supported\n", 
303                      p_vout->i_screen_depth);
304         return( 1  );
305         break;
306     }
307     return( 0 ); 
308 }
309
310 /*******************************************************************************
311  * X11CreateWindow: create X11 vout window
312  *******************************************************************************
313  * The video output window will be created. Normally, this window is wether 
314  * full screen or part of a parent window. Therefore, it does not need a 
315  * title or other hints. Thery are still supplied in case the window would be
316  * spawned as a standalone one by the interface.
317  *******************************************************************************/
318 static int X11CreateWindow( vout_thread_t *p_vout )
319 {
320     XSetWindowAttributes    xwindow_attributes;
321     XGCValues               xgcvalues;
322     XEvent                  xevent;
323     boolean_t               b_expose;
324     boolean_t               b_map_notify;    
325
326     /* Prepare window attributes */
327     xwindow_attributes.backing_store = Always;         /* save the hidden part */  
328  
329     /* Create the window and set hints - the window must receive ConfigureNotify
330      * events, and, until it is displayed, Expose and MapNotify events. */
331     p_vout->p_sys->window = XCreateSimpleWindow( p_vout->p_sys->p_display,
332                                                  p_vout->p_sys->root_window,
333                                                  0, 0, 
334                                                  p_vout->i_width, p_vout->i_height,
335                                                  0, 0, 0);
336     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window, 
337                   ExposureMask | StructureNotifyMask );
338     XChangeWindowAttributes( p_vout->p_sys->p_display, p_vout->p_sys->window, 
339                              CWBackingStore, &xwindow_attributes);
340
341     /* Creation of a graphic context that doesn't generate a GraphicsExpose event
342        when using functions like XCopyArea */
343     xgcvalues.graphics_exposures = False;    
344     p_vout->p_sys->gc =  XCreateGC( p_vout->p_sys->p_display, p_vout->p_sys->window,
345                                     GCGraphicsExposures, &xgcvalues);
346
347     /* Send orders to server, and wait until window is displayed - two events
348      * must be received: a MapNotify event, an Expose event allowing drawing in the
349      * window */
350     b_expose = 0;
351     b_map_notify = 0;
352     XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
353     do
354     {
355         XNextEvent( p_vout->p_sys->p_display, &xevent);
356         if( (xevent.type == Expose) 
357             && (xevent.xexpose.window == p_vout->p_sys->window) )
358         {
359             b_expose = 1;
360         }
361         else if( (xevent.type == MapNotify) 
362                  && (xevent.xmap.window == p_vout->p_sys->window) )
363         {
364             b_map_notify = 1;
365         }
366     }
367     while( !( b_expose && b_map_notify ) );
368     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window, 0 );
369
370     /* At this stage, the window is openned, displayed, and ready to receive data */
371     p_vout->b_active = 1;    
372     return( 0 );
373 }
374
375 /*******************************************************************************
376  * X11CreateImages: create X11 rendering buffers
377  *******************************************************************************
378  * Create two XImages which will be used as rendering buffers. On error, non 0
379  * will be returned and the images pointer will be set to NULL (see 
380  * vout_X11ManageOutputMethod()).
381  *******************************************************************************
382  * Messages type: vout, major code: 108
383  *******************************************************************************/
384 static int X11CreateImages( vout_thread_t *p_vout )
385 {
386     int i_err;
387
388     /* Create XImages using XShm extension - on failure, fall back to regular 
389      * way (and destroy the first image if it was created successfully) */
390     if( p_vout->p_sys->b_shm )
391     {
392         /* Create first image */
393         i_err = X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[0], 
394                                    &p_vout->p_sys->shm_info[0] );
395         if( !i_err )                           /* first image has been created */
396         {
397             /* Create second image */
398             if( X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[1], 
399                                    &p_vout->p_sys->shm_info[1] ) )
400             {                               /* error creating the second image */
401                 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0], 
402                                     &p_vout->p_sys->shm_info[0] );
403                 i_err = 1;
404             }
405         }
406         if( i_err )                                        /* an error occured */
407         {                        
408             intf_Msg("vout: XShm extension desactivated\n" );
409             p_vout->p_sys->b_shm = 0;
410         }
411     }
412
413     /* Create XImages without XShm extension */
414     if( !p_vout->p_sys->b_shm )
415     {
416         if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[0] ) )
417         {
418             intf_Msg("vout error 108-1: can't create images\n");
419             p_vout->p_sys->p_ximage[0] = NULL;
420             p_vout->p_sys->p_ximage[1] = NULL;
421             return( -1 );
422         }
423         if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[1] ) )
424         {
425             intf_Msg("vout error 108-2: can't create images\n");
426             X11DestroyImage( p_vout->p_sys->p_ximage[0] );
427             p_vout->p_sys->p_ximage[0] = NULL;
428             p_vout->p_sys->p_ximage[1] = NULL;
429             return( -1 );
430         }
431     }
432
433     /* Set buffer index to 0 */
434     p_vout->p_sys->i_buffer_index = 0;
435
436     return( 0 );
437 }
438
439 /*******************************************************************************
440  * X11DestroyImages: destroy X11 rendering buffers
441  *******************************************************************************
442  * Destroy buffers created by vout_X11CreateImages().
443  *******************************************************************************
444  * Messages type: vout, major code: 109
445  *******************************************************************************/
446 static void X11DestroyImages( vout_thread_t *p_vout )
447 {
448     if( p_vout->p_sys->b_shm )                              /* Shm XImages... */
449     {
450         X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0], 
451                             &p_vout->p_sys->shm_info[0] );
452                 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[1], 
453                             &p_vout->p_sys->shm_info[1] );
454         }
455         else                                              /* ...or regular XImages */
456         {
457                 X11DestroyImage( p_vout->p_sys->p_ximage[0] );
458                 X11DestroyImage( p_vout->p_sys->p_ximage[1] );
459         }
460 }
461
462 /*******************************************************************************
463  * X11DestroyWindow: destroy X11 window
464  *******************************************************************************
465  * Destroy an X11 window created by vout_X11CreateWindow
466  *******************************************************************************
467  * Messages type: vout, major code: 110
468  *******************************************************************************/
469 static void X11DestroyWindow( vout_thread_t *p_vout )
470 {
471     intf_DbgMsg("vout window: 0x%x\n", p_vout->p_sys->window );
472     XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
473     XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
474     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
475 }
476
477 /*******************************************************************************
478  * X11CreateImage: create an XImage                                      
479  *******************************************************************************
480  * Messages type: vout, major code 112
481  *******************************************************************************/
482 static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
483 {
484     byte_t *    pb_data;                            /* image data storage zone */
485     int         i_quantum;                       /* XImage quantum (see below) */
486   
487     /* Allocate memory for image */
488     pb_data = (byte_t *) malloc( p_vout->i_bytes_per_pixel
489                                  * p_vout->i_width 
490                                  * p_vout->i_height );
491     if( !pb_data )                                                    /* error */
492     {
493         intf_ErrMsg("vout error 112-1: %s\n", strerror(ENOMEM));
494         return( -1 );   
495     }
496
497     /* Optimize the quantum of a scanline regarding its size - the quantum is
498        a diviser of the number of bits between the start of two scanlines. */
499     if( !(( p_vout->i_width * p_vout->i_bytes_per_pixel ) % 32) )
500     {
501         i_quantum = 32;
502     }
503     else    
504     {
505         if( !(( p_vout->i_width * p_vout->i_bytes_per_pixel ) % 16) )
506         {
507             i_quantum = 16;
508         }
509         else
510         {
511             i_quantum = 8;
512         }
513     }
514     
515     /* Create XImage */
516     *pp_ximage = XCreateImage( p_vout->p_sys->p_display, 
517                                DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
518                                p_vout->i_screen_depth, ZPixmap, 0, pb_data, 
519                                p_vout->i_width, p_vout->i_height, i_quantum, 0);
520     if(! *pp_ximage )                                                 /* error */
521     {
522         intf_ErrMsg( "vout error 112-2: XCreateImage() failed\n" );
523         free( pb_data );
524         return( -1 );
525     }
526
527     return 0;
528 }
529
530 /*******************************************************************************
531  * X11CreateShmImage: create an XImage using shared memory extension
532  *******************************************************************************
533  * Prepare an XImage for DisplayX11ShmImage function.
534  * The order of the operations respects the recommandations of the mit-shm 
535  * document by J.Corbet and K.Packard. Most of the parameters were copied from 
536  * there.
537  * ?? error on failure:
538  * X Error of failed request:  BadAccess (attempt to access private resource denied)
539  *  Major opcode of failed request:  129 (MIT-SHM)
540  *  Minor opcode of failed request:  1 (X_ShmAttach)
541  *  Serial number of failed request:  17
542  *  Current serial number in output stream:  18         
543  *******************************************************************************
544  * Messages type: vout, major code 113
545  *******************************************************************************/
546 static int X11CreateShmImage( vout_thread_t *p_vout, XImage **pp_ximage, 
547                               XShmSegmentInfo *p_shm_info)
548 {
549     /* Create XImage */
550     *pp_ximage = XShmCreateImage( p_vout->p_sys->p_display, 
551                                   DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
552                                   p_vout->i_screen_depth, ZPixmap, 0, 
553                                   p_shm_info, p_vout->i_width, p_vout->i_height );
554     if(! *pp_ximage )                                                 /* error */
555     {
556         intf_ErrMsg("vout error 113-1: XShmCreateImage() failed\n");
557         return( -1 );
558     }
559
560     /* Allocate shared memory segment - 0777 set the access permission
561      * rights (like umask), they are not yet supported by X servers */
562     p_shm_info->shmid = shmget( IPC_PRIVATE, 
563                                 (*pp_ximage)->bytes_per_line * (*pp_ximage)->height, 
564                                 IPC_CREAT | 0777);
565     if( p_shm_info->shmid < 0)                                        /* error */
566     {
567         intf_ErrMsg("vout error 113-2: can't allocate shared image data (%s)\n",
568                     strerror(errno));
569         XDestroyImage( *pp_ximage );
570         return( -1 );
571     }
572
573     /* Attach shared memory segment to process (read/write) */
574     p_shm_info->shmaddr = (*pp_ximage)->data = shmat(p_shm_info->shmid, 0, 0);
575     if(! p_shm_info->shmaddr )
576     {                                                                 /* error */
577         intf_ErrMsg("vout error 113-3: can't attach shared memory (%s)\n",
578                     strerror(errno));
579         shmctl( p_shm_info->shmid, IPC_RMID, 0 );        /* free shared memory */
580         XDestroyImage( *pp_ximage );
581         return( -1 );
582     }
583
584     /* Mark the shm segment to be removed when there will be no more
585      * attachements, so it is automatic on process exit or after shmdt */
586     shmctl( p_shm_info->shmid, IPC_RMID, 0 );
587
588     /* Attach shared memory segment to X server (read only) */
589     p_shm_info->readOnly = True;
590     if( XShmAttach( p_vout->p_sys->p_display, p_shm_info ) == False )    /* error */
591     {
592         intf_ErrMsg("vout error 113-4: can't attach shared memory to server\n");
593         shmdt( p_shm_info->shmaddr );     /* detach shared memory from process
594                                            * and automatic free                */
595         XDestroyImage( *pp_ximage );
596         return( -1 );
597     }
598
599     /* ?? don't know what it is. Function XShmGetEventBase prototype is defined
600      * in mit-shm document, but does not appears in any header. */
601     p_vout->p_sys->i_completion_type = XShmGetEventBase(p_vout->p_sys->p_display) + ShmCompletion;
602
603     return( 0 );
604 }
605
606 /*******************************************************************************
607  * X11DestroyImage: destroy an XImage                                  
608  *******************************************************************************
609  * Destroy XImage AND associated data. If pointer is NULL, the image won't be
610  * destroyed (see vout_X11ManageOutputMethod())
611  *******************************************************************************
612  * Messages type: vout, major code 114
613  *******************************************************************************/
614 static void X11DestroyImage( XImage *p_ximage )
615 {
616     if( p_ximage != NULL )
617     {
618         XDestroyImage( p_ximage );                       /* no free() required */
619     }
620 }
621
622 /*******************************************************************************
623  * X11DestroyShmImage                                                    
624  *******************************************************************************
625  * Destroy XImage AND associated data. Detach shared memory segment from
626  * server and process, then free it. If pointer is NULL, the image won't be
627  * destroyed (see vout_X11ManageOutputMethod()) 
628  *******************************************************************************
629  * Messages type: vout, major code 115
630  *******************************************************************************/
631 static void X11DestroyShmImage( vout_thread_t *p_vout, XImage *p_ximage, 
632                                 XShmSegmentInfo *p_shm_info )
633 {
634     /* If pointer is NULL, do nothing */
635     if( p_ximage == NULL )
636     {
637         return;
638     }
639
640     XShmDetach( p_vout->p_sys->p_display, p_shm_info );     /* detach from server */
641     XDestroyImage( p_ximage );
642     if( shmdt( p_shm_info->shmaddr ) )    /* detach shared memory from process */
643     {                                     /* also automatic freeing...         */
644         intf_ErrMsg("vout error 115-1: can't detach shared memory (%s)\n", 
645                     strerror(errno));
646     }
647 }
648
649 /* following functions are local rendering functions */
650