]> git.sesse.net Git - vlc/blob - plugins/x11/vout_x11.c
* Fixed compilation with dvdcss disabled.
[vlc] / plugins / x11 / vout_x11.c
1 /*****************************************************************************
2  * vout_x11.c: X11 video output display method
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id: vout_x11.c,v 1.34 2001/12/09 17:01:37 sam Exp $
6  *
7  * Authors: Vincent Seguin <seguin@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          David Kennedy <dkennedy@tinytoad.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 #define MODULE_NAME x11
27 #include "modules_inner.h"
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #include "defs.h"
33
34 #include <errno.h>                                                 /* ENOMEM */
35 #include <stdlib.h>                                                /* free() */
36 #include <string.h>                                            /* strerror() */
37
38 #ifdef HAVE_MACHINE_PARAM_H
39 /* BSD */
40 #include <machine/param.h>
41 #include <sys/types.h>                                     /* typedef ushort */
42 #include <sys/ipc.h>
43 #endif
44
45 #ifndef WIN32
46 #include <netinet/in.h>                               /* BSD: struct in_addr */
47 #endif
48
49 #include <sys/shm.h>                                   /* shmget(), shmctl() */
50 #include <X11/Xlib.h>
51 #include <X11/Xutil.h>
52 #include <X11/keysym.h>
53 #include <X11/extensions/XShm.h>
54
55 #include "common.h"
56 #include "intf_msg.h"
57 #include "threads.h"
58 #include "mtime.h"
59 #include "tests.h"
60
61 #include "video.h"
62 #include "video_output.h"
63 #include "vout_common.h"
64
65 #include "interface.h"
66 #include "netutils.h"                                 /* network_ChannelJoin */
67
68 #include "modules.h"
69 #include "modules_export.h"
70
71 /*****************************************************************************
72  * Local prototypes
73  *****************************************************************************/
74 static int  vout_Probe     ( probedata_t *p_data );
75 static int  vout_Create    ( struct vout_thread_s * );
76 static int  vout_Init      ( struct vout_thread_s * );
77 static void vout_End       ( struct vout_thread_s * );
78 static void vout_Destroy   ( struct vout_thread_s * );
79 static void vout_Display   ( struct vout_thread_s * );
80 static void vout_SetPalette( struct vout_thread_s *, u16*, u16*, u16*, u16* );
81
82 static int  X11InitDisplay      ( vout_thread_t *p_vout, char *psz_display );
83
84 static int  X11CreateImage      ( vout_thread_t *p_vout, XImage **pp_ximage );
85 static void X11DestroyImage     ( XImage *p_ximage );
86 static int  X11CreateShmImage   ( vout_thread_t *p_vout, XImage **pp_ximage,
87                                   XShmSegmentInfo *p_shm_info );
88 static void X11DestroyShmImage  ( vout_thread_t *p_vout, XImage *p_ximage,
89                                   XShmSegmentInfo *p_shm_info );
90
91 /*****************************************************************************
92  * Functions exported as capabilities. They are declared as static so that
93  * we don't pollute the namespace too much.
94  *****************************************************************************/
95 void _M( vout_getfunctions )( function_list_t * p_function_list )
96 {
97     p_function_list->pf_probe = vout_Probe;
98     p_function_list->functions.vout.pf_create     = vout_Create;
99     p_function_list->functions.vout.pf_init       = vout_Init;
100     p_function_list->functions.vout.pf_end        = vout_End;
101     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
102     p_function_list->functions.vout.pf_manage     = _M( vout_Manage );
103     p_function_list->functions.vout.pf_display    = vout_Display;
104     p_function_list->functions.vout.pf_setpalette = vout_SetPalette;
105 }
106
107 /*****************************************************************************
108  * vout_Probe: probe the video driver and return a score
109  *****************************************************************************
110  * This function tries to initialize SDL and returns a score to the
111  * plugin manager so that it can select the best plugin.
112  *****************************************************************************/
113 static int vout_Probe( probedata_t *p_data )
114 {
115     if( TestMethod( VOUT_METHOD_VAR, "x11" ) )
116     {
117         return( 999 );
118     }
119
120     return( 50 );
121 }
122
123 /*****************************************************************************
124  * vout_Create: allocate X11 video thread output method
125  *****************************************************************************
126  * This function allocate and initialize a X11 vout method. It uses some of the
127  * vout properties to choose the window size, and change them according to the
128  * actual properties of the display.
129  *****************************************************************************/
130 static int vout_Create( vout_thread_t *p_vout )
131 {
132     char *psz_display;
133     XColor cursor_color;
134
135     /* Allocate structure */
136     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
137     if( p_vout->p_sys == NULL )
138     {
139         intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
140         return( 1 );
141     }
142
143     /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
144     psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
145     p_vout->p_sys->p_display = XOpenDisplay( psz_display );
146
147     if( p_vout->p_sys->p_display == NULL )                          /* error */
148     {
149         intf_ErrMsg( "vout error: cannot open display %s", psz_display );
150         free( p_vout->p_sys );
151         return( 1 );
152     }
153     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
154
155     /* Spawn base window - this window will include the video output window,
156      * but also command buttons, subtitles and other indicators */
157
158     if( _M( XCommonCreateWindow ) ( p_vout ) )
159     {
160         intf_ErrMsg( "vout error: cannot create X11 window" );
161         XCloseDisplay( p_vout->p_sys->p_display );
162         free( p_vout->p_sys );
163         return( 1 );
164     }
165
166     /* Open and initialize device. This function issues its own error messages.
167      * Since XLib is usually not thread-safe, we can't use the same display
168      * pointer than the interface or another thread. However, the root window
169      * id is still valid. */
170     if( X11InitDisplay( p_vout, psz_display ) )
171     {
172         intf_ErrMsg( "vout error: cannot initialize X11 display" );
173         XCloseDisplay( p_vout->p_sys->p_display );
174         free( p_vout->p_sys );
175         return( 1 );
176     }
177
178     /* Create blank cursor (for mouse cursor autohiding) */
179     p_vout->p_sys->b_mouse_pointer_visible = 1;
180     p_vout->p_sys->cursor_pixmap = XCreatePixmap( p_vout->p_sys->p_display,
181                                                   DefaultRootWindow(
182                                                      p_vout->p_sys->p_display),
183                                                   1, 1, 1 );
184     
185     XParseColor( p_vout->p_sys->p_display,
186                  XCreateColormap( p_vout->p_sys->p_display,
187                                   DefaultRootWindow(
188                                                     p_vout->p_sys->p_display ),
189                                   DefaultVisual(
190                                                 p_vout->p_sys->p_display,
191                                                 p_vout->p_sys->i_screen ),
192                                   AllocNone ),
193                  "black", &cursor_color );
194     
195     p_vout->p_sys->blank_cursor = XCreatePixmapCursor(
196                                       p_vout->p_sys->p_display,
197                                       p_vout->p_sys->cursor_pixmap,
198                                       p_vout->p_sys->cursor_pixmap,
199                                       &cursor_color,
200                                       &cursor_color, 1, 1 );    
201
202     /* Disable screen saver and return */
203     _M( XCommonDisableScreenSaver ) ( p_vout );
204
205     return( 0 );
206 }
207
208 /*****************************************************************************
209  * vout_Init: initialize X11 video thread output method
210  *****************************************************************************
211  * This function create the XImages needed by the output thread. It is called
212  * at the beginning of the thread, but also each time the window is resized.
213  *****************************************************************************/
214 static int vout_Init( vout_thread_t *p_vout )
215 {
216     int i_err;
217
218 #ifdef SYS_DARWIN
219     /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
220     p_vout->p_sys->b_shm = 0;
221 #endif
222
223     /* Create XImages using XShm extension - on failure, fall back to regular
224      * way (and destroy the first image if it was created successfully) */
225     if( p_vout->p_sys->b_shm )
226     {
227         /* Create first image */
228         i_err = X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[0],
229                                    &p_vout->p_sys->shm_info[0] );
230         if( !i_err )                         /* first image has been created */
231         {
232             /* Create second image */
233             if( X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[1],
234                                    &p_vout->p_sys->shm_info[1] ) )
235             {                             /* error creating the second image */
236                 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0],
237                                     &p_vout->p_sys->shm_info[0] );
238                 i_err = 1;
239             }
240         }
241         if( i_err )                                      /* an error occured */
242         {
243             intf_Msg( "vout: XShm video extension unavailable" );
244             p_vout->p_sys->b_shm = 0;
245         }
246     }
247
248     /* Create XImages without XShm extension */
249     if( !p_vout->p_sys->b_shm )
250     {
251         if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[0] ) )
252         {
253             intf_ErrMsg( "vout error: cannot create images" );
254             p_vout->p_sys->p_ximage[0] = NULL;
255             p_vout->p_sys->p_ximage[1] = NULL;
256             return( 1 );
257         }
258         if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[1] ) )
259         {
260             intf_ErrMsg( "vout error: cannot create images" );
261             X11DestroyImage( p_vout->p_sys->p_ximage[0] );
262             p_vout->p_sys->p_ximage[0] = NULL;
263             p_vout->p_sys->p_ximage[1] = NULL;
264             return( 1 );
265         }
266     }
267
268     /* Set bytes per line and initialize buffers */
269     p_vout->i_bytes_per_line = p_vout->p_sys->p_ximage[0]->bytes_per_line;
270     p_vout->pf_setbuffers( p_vout, p_vout->p_sys->p_ximage[ 0 ]->data,
271                                    p_vout->p_sys->p_ximage[ 1 ]->data );
272
273     /* Set date for autohiding cursor */
274     p_vout->p_sys->i_lastmoved = mdate();
275     
276     return( 0 );
277 }
278
279 /*****************************************************************************
280  * vout_End: terminate X11 video thread output method
281  *****************************************************************************
282  * Destroy the X11 XImages created by vout_Init. It is called at the end of
283  * the thread, but also each time the window is resized.
284  *****************************************************************************/
285 static void vout_End( vout_thread_t *p_vout )
286 {
287     if( p_vout->p_sys->b_shm )                             /* Shm XImages... */
288     {
289         X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0],
290                             &p_vout->p_sys->shm_info[0] );
291         X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[1],
292                             &p_vout->p_sys->shm_info[1] );
293     }
294     else                                          /* ...or regular XImages */
295     {
296         X11DestroyImage( p_vout->p_sys->p_ximage[0] );
297         X11DestroyImage( p_vout->p_sys->p_ximage[1] );
298     }
299 }
300
301 /*****************************************************************************
302  * vout_Destroy: destroy X11 video thread output method
303  *****************************************************************************
304  * Terminate an output method created by vout_CreateOutputMethod
305  *****************************************************************************/
306 static void vout_Destroy( vout_thread_t *p_vout )
307 {
308     /* Enable screen saver */
309     _M( XCommonEnableScreenSaver ) ( p_vout );
310
311     /* Restore cursor if it was blanked */
312     if( !p_vout->p_sys->b_mouse_pointer_visible )
313     {
314         _M( XCommonToggleMousePointer ) ( p_vout );
315     }
316
317     /* Destroy blank cursor pixmap */
318     XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
319
320     /* Destroy colormap */
321     if( p_vout->i_screen_depth == 8 )
322     {
323         XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap );
324     }
325
326     /* Destroy window */
327     XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
328     XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
329     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
330
331     XCloseDisplay( p_vout->p_sys->p_display );
332
333     /* Destroy structure */
334     free( p_vout->p_sys );
335 }
336
337 /*****************************************************************************
338  * vout_Display: displays previously rendered output
339  *****************************************************************************
340  * This function send the currently rendered image to X11 server, wait until
341  * it is displayed and switch the two rendering buffer, preparing next frame.
342  *****************************************************************************/
343 static void vout_Display( vout_thread_t *p_vout )
344 {
345     if( p_vout->p_sys->b_shm)                                /* XShm is used */
346     {
347         /* Display rendered image using shared memory extension */
348         XShmPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
349                      p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ],
350                      0, 0, 0, 0,
351                      p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->width,
352                      p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->height, False);
353
354         /* Send the order to the X server */
355         XSync(p_vout->p_sys->p_display, False);
356     }
357     else                                /* regular X11 capabilities are used */
358     {
359         XPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
360                   p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ],
361                   0, 0, 0, 0,
362                   p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->width,
363                   p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->height);
364
365         /* Send the order to the X server */
366         XSync(p_vout->p_sys->p_display, False);
367     }
368 }
369
370 /*****************************************************************************
371  * vout_SetPalette: sets an 8 bpp palette
372  *****************************************************************************
373  * This function sets the palette given as an argument. It does not return
374  * anything, but could later send information on which colors it was unable
375  * to set.
376  *****************************************************************************/
377 static void vout_SetPalette( p_vout_thread_t p_vout,
378                              u16 *red, u16 *green, u16 *blue, u16 *transp )
379 {
380     int i, j;
381     XColor p_colors[255];
382
383     intf_DbgMsg( "vout: Palette change called" );
384
385     /* allocate palette */
386     for( i = 0, j = 255; i < 255; i++, j-- )
387     {
388         /* kludge: colors are indexed reversely because color 255 seems
389          * to be reserved for black even if we try to set it to white */
390         p_colors[ i ].pixel = j;
391         p_colors[ i ].pad   = 0;
392         p_colors[ i ].flags = DoRed | DoGreen | DoBlue;
393         p_colors[ i ].red   = red[ j ];
394         p_colors[ i ].blue  = blue[ j ];
395         p_colors[ i ].green = green[ j ];
396     }
397
398     XStoreColors( p_vout->p_sys->p_display,
399                   p_vout->p_sys->colormap, p_colors, 256 );
400 }
401
402 /* following functions are local */
403
404 /*****************************************************************************
405  * X11InitDisplay: open and initialize X11 device
406  *****************************************************************************
407  * Create a window according to video output given size, and set other
408  * properties according to the display properties.
409  *****************************************************************************/
410 static int X11InitDisplay( vout_thread_t *p_vout, char *psz_display )
411 {
412     XPixmapFormatValues *       p_formats;                 /* pixmap formats */
413     XVisualInfo *               p_xvisual;           /* visuals informations */
414     XVisualInfo                 xvisual_template;         /* visual template */
415     int                         i_count;                       /* array size */
416
417
418     /* Initialize structure */
419     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
420     p_vout->p_sys->b_shm    = ( XShmQueryExtension( p_vout->p_sys->p_display )
421                                  == True );
422     if( !p_vout->p_sys->b_shm )
423     {
424         intf_Msg( "vout: XShm video extension is not available" );
425     }
426
427     /* Get screen depth */
428     p_vout->i_screen_depth = XDefaultDepth( p_vout->p_sys->p_display,
429                                             p_vout->p_sys->i_screen );
430     switch( p_vout->i_screen_depth )
431     {
432     case 8:
433         /*
434          * Screen depth is 8bpp. Use PseudoColor visual with private colormap.
435          */
436         xvisual_template.screen =   p_vout->p_sys->i_screen;
437         xvisual_template.class =    DirectColor;
438         p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
439                                     VisualScreenMask | VisualClassMask,
440                                     &xvisual_template, &i_count );
441         if( p_xvisual == NULL )
442         {
443             intf_ErrMsg( "vout error: no PseudoColor visual available" );
444             return( 1 );
445         }
446         p_vout->i_bytes_per_pixel = 1;
447         break;
448     case 15:
449     case 16:
450     case 24:
451     default:
452         /*
453          * Screen depth is higher than 8bpp. TrueColor visual is used.
454          */
455         xvisual_template.screen =   p_vout->p_sys->i_screen;
456         xvisual_template.class =    TrueColor;
457         p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
458                                     VisualScreenMask | VisualClassMask,
459                                     &xvisual_template, &i_count );
460         if( p_xvisual == NULL )
461         {
462             intf_ErrMsg( "vout error: no TrueColor visual available" );
463             return( 1 );
464         }
465         p_vout->i_red_mask =        p_xvisual->red_mask;
466         p_vout->i_green_mask =      p_xvisual->green_mask;
467         p_vout->i_blue_mask =       p_xvisual->blue_mask;
468
469         /* There is no difference yet between 3 and 4 Bpp. The only way
470          * to find the actual number of bytes per pixel is to list supported
471          * pixmap formats. */
472         p_formats = XListPixmapFormats( p_vout->p_sys->p_display, &i_count );
473         p_vout->i_bytes_per_pixel = 0;
474
475         for( ; i_count-- ; p_formats++ )
476         {
477             /* Under XFree4.0, the list contains pixmap formats available
478              * through all video depths ; so we have to check against current
479              * depth. */
480             if( p_formats->depth == p_vout->i_screen_depth )
481             {
482                 if( p_formats->bits_per_pixel / 8
483                         > p_vout->i_bytes_per_pixel )
484                 {
485                     p_vout->i_bytes_per_pixel = p_formats->bits_per_pixel / 8;
486                 }
487             }
488         }
489         break;
490     }
491     p_vout->p_sys->p_visual = p_xvisual->visual;
492     XFree( p_xvisual );
493
494     return( 0 );
495 }
496
497 /*****************************************************************************
498  * X11CreateImage: create an XImage
499  *****************************************************************************
500  * Create a simple XImage used as a buffer.
501  *****************************************************************************/
502 static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
503 {
504     byte_t *    pb_data;                          /* image data storage zone */
505     int         i_quantum;                     /* XImage quantum (see below) */
506
507     /* Allocate memory for image */
508     p_vout->i_bytes_per_line = p_vout->i_width * p_vout->i_bytes_per_pixel;
509     pb_data = (byte_t *) malloc( p_vout->i_bytes_per_line * p_vout->i_height );
510     if( !pb_data )                                                  /* error */
511     {
512         intf_ErrMsg( "vout error: %s", strerror(ENOMEM));
513         return( 1 );
514     }
515
516     /* Optimize the quantum of a scanline regarding its size - the quantum is
517        a diviser of the number of bits between the start of two scanlines. */
518     if( !(( p_vout->i_bytes_per_line ) % 32) )
519     {
520         i_quantum = 32;
521     }
522     else
523     {
524         if( !(( p_vout->i_bytes_per_line ) % 16) )
525         {
526             i_quantum = 16;
527         }
528         else
529         {
530             i_quantum = 8;
531         }
532     }
533
534     /* Create XImage */
535     *pp_ximage = XCreateImage( p_vout->p_sys->p_display,
536                                p_vout->p_sys->p_visual, p_vout->i_screen_depth,
537                                ZPixmap, 0, pb_data,
538                                p_vout->i_width, p_vout->i_height, i_quantum, 0);
539     if(! *pp_ximage )                                               /* error */
540     {
541         intf_ErrMsg( "vout error: XCreateImage() failed" );
542         free( pb_data );
543         return( 1 );
544     }
545
546     return 0;
547 }
548
549 /*****************************************************************************
550  * X11CreateShmImage: create an XImage using shared memory extension
551  *****************************************************************************
552  * Prepare an XImage for DisplayX11ShmImage function.
553  * The order of the operations respects the recommandations of the mit-shm
554  * document by J.Corbet and K.Packard. Most of the parameters were copied from
555  * there.
556  *****************************************************************************/
557 static int X11CreateShmImage( vout_thread_t *p_vout, XImage **pp_ximage,
558                               XShmSegmentInfo *p_shm_info)
559 {
560     /* Create XImage */
561     *pp_ximage =
562         XShmCreateImage( p_vout->p_sys->p_display, p_vout->p_sys->p_visual,
563                          p_vout->i_screen_depth, ZPixmap, 0,
564                          p_shm_info, p_vout->i_width, p_vout->i_height );
565     if(! *pp_ximage )                                               /* error */
566     {
567         intf_ErrMsg( "vout error: XShmCreateImage() failed" );
568         return( 1 );
569     }
570
571     /* Allocate shared memory segment - 0777 set the access permission
572      * rights (like umask), they are not yet supported by X servers */
573     p_shm_info->shmid =
574         shmget( IPC_PRIVATE, (*pp_ximage)->bytes_per_line
575                                  * (*pp_ximage)->height, IPC_CREAT | 0777);
576     if( p_shm_info->shmid < 0)                                      /* error */
577     {
578         intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
579                     strerror(errno));
580         XDestroyImage( *pp_ximage );
581         return( 1 );
582     }
583
584     /* Attach shared memory segment to process (read/write) */
585     p_shm_info->shmaddr = (*pp_ximage)->data = shmat(p_shm_info->shmid, 0, 0);
586     if(! p_shm_info->shmaddr )
587     {                                                               /* error */
588         intf_ErrMsg( "vout error: cannot attach shared memory (%s)",
589                     strerror(errno));
590         shmctl( p_shm_info->shmid, IPC_RMID, 0 );      /* free shared memory */
591         XDestroyImage( *pp_ximage );
592         return( 1 );
593     }
594
595 #if 0
596     /* Mark the shm segment to be removed when there will be no more
597      * attachements, so it is automatic on process exit or after shmdt */
598     shmctl( p_shm_info->shmid, IPC_RMID, 0 );
599 #endif
600
601     /* Attach shared memory segment to X server (read only) */
602     p_shm_info->readOnly = True;
603     if( XShmAttach( p_vout->p_sys->p_display, p_shm_info )
604          == False )                                                 /* error */
605     {
606         intf_ErrMsg( "vout error: cannot attach shared memory to X11 server" );
607         shmctl( p_shm_info->shmid, IPC_RMID, 0 );      /* free shared memory */
608         shmdt( p_shm_info->shmaddr );   /* detach shared memory from process
609                                          * and automatic free */
610         XDestroyImage( *pp_ximage );
611         return( 1 );
612     }
613
614     /* Send image to X server. This instruction is required, since having
615      * built a Shm XImage and not using it causes an error on XCloseDisplay */
616     XFlush( p_vout->p_sys->p_display );
617     return( 0 );
618 }
619
620 /*****************************************************************************
621  * X11DestroyImage: destroy an XImage
622  *****************************************************************************
623  * Destroy XImage AND associated data. If pointer is NULL, the image won't be
624  * destroyed (see vout_ManageOutputMethod())
625  *****************************************************************************/
626 static void X11DestroyImage( XImage *p_ximage )
627 {
628     if( p_ximage != NULL )
629     {
630         XDestroyImage( p_ximage );                     /* no free() required */
631     }
632 }
633
634 /*****************************************************************************
635  * X11DestroyShmImage
636  *****************************************************************************
637  * Destroy XImage AND associated data. Detach shared memory segment from
638  * server and process, then free it. If pointer is NULL, the image won't be
639  * destroyed (see vout_ManageOutputMethod())
640  *****************************************************************************/
641 static void X11DestroyShmImage( vout_thread_t *p_vout, XImage *p_ximage,
642                                 XShmSegmentInfo *p_shm_info )
643 {
644     /* If pointer is NULL, do nothing */
645     if( p_ximage == NULL )
646     {
647         return;
648     }
649
650     XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
651     XDestroyImage( p_ximage );
652
653     shmctl( p_shm_info->shmid, IPC_RMID, 0 );          /* free shared memory */
654
655     if( shmdt( p_shm_info->shmaddr ) )  /* detach shared memory from process */
656     {
657         intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
658                      strerror(errno) );
659     }
660 }
661