]> git.sesse.net Git - vlc/blob - plugins/x11/xcommon.c
392aabb9311c3e6b4217989bb0a9f7b05ec02393
[vlc] / plugins / x11 / xcommon.c
1 /*****************************************************************************
2  * xcommon.c: Functions common to the X11 and XVideo plugins
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id: xcommon.c,v 1.4 2002/01/02 14:37:42 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 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <errno.h>                                                 /* ENOMEM */
30 #include <stdlib.h>                                                /* free() */
31 #include <string.h>                                            /* strerror() */
32
33 #include <videolan/vlc.h>
34
35 #ifdef HAVE_MACHINE_PARAM_H
36 /* BSD */
37 #include <machine/param.h>
38 #include <sys/types.h>                                     /* typedef ushort */
39 #include <sys/ipc.h>
40 #endif
41
42 #ifndef WIN32
43 #include <netinet/in.h>                               /* BSD: struct in_addr */
44 #endif
45
46 #include <sys/shm.h>                                   /* shmget(), shmctl() */
47 #include <X11/Xlib.h>
48 #include <X11/Xutil.h>
49 #include <X11/keysym.h>
50 #include <X11/extensions/XShm.h>
51 #include <X11/extensions/dpms.h>
52
53 #ifdef MODULE_NAME_IS_xvideo
54 #   include <X11/extensions/Xv.h>
55 #   include <X11/extensions/Xvlib.h>
56 #endif
57
58 #include "video.h"
59 #include "video_output.h"
60 #include "xcommon.h"
61
62 #include "interface.h"
63 #include "netutils.h"                                 /* network_ChannelJoin */
64
65 #include "stream_control.h"                 /* needed by input_ext-intf.h... */
66 #include "input_ext-intf.h"
67
68 #ifdef MODULE_NAME_IS_xvideo
69 #   define IMAGE_TYPE     XvImage
70 #   define EXTRA_ARGS     int i_xvport, int i_format
71 #   define EXTRA_ARGS_SHM int i_xvport, int i_format, XShmSegmentInfo *p_shm
72 #   define DATA_SIZE(p)   (p)->data_size
73 #   define IMAGE_FREE     XFree      /* There is nothing like XvDestroyImage */
74 #else
75 #   define IMAGE_TYPE     XImage
76 #   define EXTRA_ARGS     Visual *p_visual, int i_depth, int i_bytes_per_pixel
77 #   define EXTRA_ARGS_SHM Visual *p_visual, int i_depth, XShmSegmentInfo *p_shm
78 #   define DATA_SIZE(p)   ((p)->bytes_per_line * (p)->height)
79 #   define IMAGE_FREE     XDestroyImage
80 #endif
81
82 /*****************************************************************************
83  * Local prototypes
84  *****************************************************************************/
85 static int  vout_Probe     ( probedata_t * );
86 static int  vout_Create    ( vout_thread_t * );
87 static void vout_Destroy   ( vout_thread_t * );
88 static void vout_Display   ( vout_thread_t *, picture_t * );
89 static int  vout_Manage    ( vout_thread_t * );
90 static int  vout_Init      ( vout_thread_t * );
91 static void vout_End       ( vout_thread_t * );
92
93 static int  InitDisplay    ( vout_thread_t * );
94
95 static int  CreateWindow   ( vout_thread_t * );
96 static void DestroyWindow  ( vout_thread_t * );
97
98 static int  NewPicture     ( vout_thread_t *, picture_t * );
99 static void FreePicture    ( vout_thread_t *, picture_t * );
100
101 static IMAGE_TYPE *CreateImage    ( Display *, EXTRA_ARGS, int, int );
102 static IMAGE_TYPE *CreateShmImage ( Display *, EXTRA_ARGS_SHM, int, int );
103
104 static void ToggleFullScreen      ( vout_thread_t * );
105
106 static void EnableXScreenSaver    ( vout_thread_t * );
107 static void DisableXScreenSaver   ( vout_thread_t * );
108
109 static void CreateCursor   ( vout_thread_t * );
110 static void DestroyCursor  ( vout_thread_t * );
111 static void ToggleCursor   ( vout_thread_t * );
112
113 #ifdef MODULE_NAME_IS_xvideo
114 static int  XVideoGetPort         ( Display *, int );
115 static void XVideoReleasePort     ( Display *, int );
116 #endif
117
118 /*****************************************************************************
119  * vout_sys_t: video output method descriptor
120  *****************************************************************************
121  * This structure is part of the video output thread descriptor.
122  * It describes the X11 and XVideo specific properties of an output thread.
123  *****************************************************************************/
124 typedef struct vout_sys_s
125 {
126     /* Internal settings and properties */
127     Display *           p_display;                        /* display pointer */
128
129     Visual *            p_visual;                          /* visual pointer */
130     int                 i_screen;                           /* screen number */
131     Window              window;                               /* root window */
132     GC                  gc;              /* graphic context instance handler */
133
134     boolean_t           b_shm;               /* shared memory extension flag */
135
136 #ifdef MODULE_NAME_IS_xvideo
137     Window              yuv_window;   /* sub-window for displaying yuv video
138                                                                         data */
139     int                 i_xvport;
140 #else
141     Colormap            colormap;               /* colormap used (8bpp only) */
142
143     int                 i_screen_depth;
144     int                 i_bytes_per_pixel;
145     int                 i_bytes_per_line;
146     int                 i_red_mask;
147     int                 i_green_mask;
148     int                 i_blue_mask;
149 #endif
150
151     /* X11 generic properties */
152     Atom                wm_protocols;
153     Atom                wm_delete_window;
154
155     int                 i_width;                     /* width of main window */
156     int                 i_height;                   /* height of main window */
157
158     /* Backup of window position and size before fullscreen switch */
159     int                 i_width_backup;
160     int                 i_height_backup;
161     int                 i_xpos_backup;
162     int                 i_ypos_backup;
163
164     /* Screen saver properties */
165     int                 i_ss_timeout;                             /* timeout */
166     int                 i_ss_interval;           /* interval between changes */
167     int                 i_ss_blanking;                      /* blanking mode */
168     int                 i_ss_exposure;                      /* exposure mode */
169     BOOL                b_ss_dpms;                              /* DPMS mode */
170
171     /* Mouse pointer properties */
172     boolean_t           b_mouse_pointer_visible;
173     mtime_t             i_time_mouse_last_moved; /* used to auto-hide pointer*/
174     Cursor              blank_cursor;                   /* the hidden cursor */
175     Pixmap              cursor_pixmap;
176
177 } vout_sys_t;
178
179 /*****************************************************************************
180  * picture_sys_t: direct buffer method descriptor
181  *****************************************************************************
182  * This structure is part of the picture descriptor, it describes the
183  * XVideo specific properties of a direct buffer.
184  *****************************************************************************/
185 typedef struct picture_sys_s
186 {
187     IMAGE_TYPE *        p_image;
188
189     XShmSegmentInfo     shminfo;       /* shared memory zone information */
190
191 } picture_sys_t;
192
193 /*****************************************************************************
194  * mwmhints_t: window manager hints
195  *****************************************************************************
196  * Fullscreen needs to be able to hide the wm decorations so we provide
197  * this structure to make it easier.
198  *****************************************************************************/
199 #define MWM_HINTS_DECORATIONS   (1L << 1)
200 #define PROP_MWM_HINTS_ELEMENTS 5
201 typedef struct mwmhints_s
202 {
203     u32 flags;
204     u32 functions;
205     u32 decorations;
206     s32 input_mode;
207     u32 status;
208 } mwmhints_t;
209
210 /*****************************************************************************
211  * Chroma defines
212  *****************************************************************************/
213 #ifdef MODULE_NAME_IS_xvideo
214 #   define GUID_YUV12_PLANAR 0x32315659
215 #   define MAX_DIRECTBUFFERS 5
216 #else
217 #   define MAX_DIRECTBUFFERS 2
218 #endif
219
220 /*****************************************************************************
221  * Seeking function TODO: put this in a generic location !
222  *****************************************************************************/
223 static __inline__ void vout_Seek( off_t i_seek )
224 {
225 #define area p_main->p_intf->p_input->stream.p_selected_area
226     off_t i_tell = area->i_tell;
227
228     i_tell += i_seek * (off_t)50 * p_main->p_intf->p_input->stream.i_mux_rate;
229
230     i_tell = ( i_tell <= 0/*area->i_start*/ ) ? 0/*area->i_start*/
231            : ( i_tell >= area->i_size ) ? area->i_size
232            : i_tell;
233
234     input_Seek( p_main->p_intf->p_input, i_tell );
235 #undef area
236 }
237
238 /*****************************************************************************
239  * Functions exported as capabilities. They are declared as static so that
240  * we don't pollute the namespace too much.
241  *****************************************************************************/
242 void _M( vout_getfunctions )( function_list_t * p_function_list )
243 {
244     p_function_list->pf_probe = vout_Probe;
245     p_function_list->functions.vout.pf_create     = vout_Create;
246     p_function_list->functions.vout.pf_init       = vout_Init;
247     p_function_list->functions.vout.pf_end        = vout_End;
248     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
249     p_function_list->functions.vout.pf_manage     = vout_Manage;
250     p_function_list->functions.vout.pf_display    = vout_Display;
251     p_function_list->functions.vout.pf_setpalette = NULL;
252 }
253
254 /*****************************************************************************
255  * vout_Probe: probe the video driver and return a score
256  *****************************************************************************
257  * This function tries to initialize SDL and returns a score to the
258  * plugin manager so that it can select the best plugin.
259  *****************************************************************************/
260 static int vout_Probe( probedata_t *p_data )
261 {
262     Display *p_display;                                   /* display pointer */
263     char    *psz_display;
264 #ifdef MODULE_NAME_IS_xvideo
265     int      i_xvport;
266 #endif
267
268     /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
269     psz_display = XDisplayName( main_GetPszVariable(VOUT_DISPLAY_VAR, NULL) );
270     p_display = XOpenDisplay( psz_display );
271     if( p_display == NULL )                                         /* error */
272     {
273         intf_WarnMsg( 3, "vout: cannot open display %s", psz_display );
274         return( 0 );
275     }
276
277 #ifdef MODULE_NAME_IS_xvideo 
278     /* Check that there is an available XVideo port */
279     i_xvport = XVideoGetPort( p_display, GUID_YUV12_PLANAR );
280     if( i_xvport < 0 )
281     {
282         intf_WarnMsg( 3, "vout: no XVideo port available" );
283         XCloseDisplay( p_display );
284         return( 0 );
285     }
286     XVideoReleasePort( p_display, i_xvport );
287 #endif
288
289     /* Clean-up everyting */
290     XCloseDisplay( p_display );
291
292 #ifdef MODULE_NAME_IS_xvideo 
293     return( 150 );
294 #else
295     return( 50 );
296 #endif
297 }
298
299 /*****************************************************************************
300  * vout_Create: allocate X11 video thread output method
301  *****************************************************************************
302  * This function allocate and initialize a X11 vout method. It uses some of the
303  * vout properties to choose the window size, and change them according to the
304  * actual properties of the display.
305  *****************************************************************************/
306 static int vout_Create( vout_thread_t *p_vout )
307 {
308     char *psz_display;
309
310     /* Allocate structure */
311     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
312     if( p_vout->p_sys == NULL )
313     {
314         intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
315         return( 1 );
316     }
317
318     /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
319     psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
320     p_vout->p_sys->p_display = XOpenDisplay( psz_display );
321
322     if( p_vout->p_sys->p_display == NULL )                          /* error */
323     {
324         intf_ErrMsg( "vout error: cannot open display %s", psz_display );
325         free( p_vout->p_sys );
326         return( 1 );
327     }
328     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
329
330 #ifdef MODULE_NAME_IS_xvideo
331     /* Check that we have access to an XVideo port */
332     p_vout->p_sys->i_xvport = XVideoGetPort( p_vout->p_sys->p_display,
333                                              GUID_YUV12_PLANAR );
334     if( p_vout->p_sys->i_xvport < 0 )
335     {
336         intf_ErrMsg( "vout error: cannot get XVideo port" );
337         XCloseDisplay( p_vout->p_sys->p_display );
338         free( p_vout->p_sys );
339         return 1;
340     }
341 #endif
342
343     /* Create blank cursor (for mouse cursor autohiding) */
344     p_vout->p_sys->b_mouse_pointer_visible = 1;
345     CreateCursor( p_vout );
346
347     /* Spawn base window - this window will include the video output window,
348      * but also command buttons, subtitles and other indicators */
349     if( CreateWindow( p_vout ) )
350     {
351         intf_ErrMsg( "vout error: cannot create X11 window" );
352         DestroyCursor( p_vout );
353         XCloseDisplay( p_vout->p_sys->p_display );
354         free( p_vout->p_sys );
355         return( 1 );
356     }
357
358     /* Open and initialize device. */
359     if( InitDisplay( p_vout ) )
360     {
361         intf_ErrMsg( "vout error: cannot initialize X11 display" );
362         DestroyCursor( p_vout );
363         DestroyWindow( p_vout );
364         XCloseDisplay( p_vout->p_sys->p_display );
365         free( p_vout->p_sys );
366         return( 1 );
367     }
368
369     /* Disable screen saver and return */
370     DisableXScreenSaver( p_vout );
371
372     return( 0 );
373 }
374
375 /*****************************************************************************
376  * vout_Destroy: destroy X11 video thread output method
377  *****************************************************************************
378  * Terminate an output method created by vout_CreateOutputMethod
379  *****************************************************************************/
380 static void vout_Destroy( vout_thread_t *p_vout )
381 {
382     /* Restore cursor if it was blanked */
383     if( !p_vout->p_sys->b_mouse_pointer_visible )
384     {
385         ToggleCursor( p_vout );
386     }
387
388 #ifdef MODULE_NAME_IS_xvideo   
389     XVideoReleasePort( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport );
390 #else
391 #if 0
392     /* Destroy colormap */
393     if( p_vout->p_sys->i_screen_depth == 8 )
394     {
395         XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap );
396     }
397 #endif
398 #endif
399
400     DestroyCursor( p_vout );
401     EnableXScreenSaver( p_vout );
402     DestroyWindow( p_vout );
403
404     XCloseDisplay( p_vout->p_sys->p_display );
405
406     /* Destroy structure */
407     free( p_vout->p_sys );
408 }
409
410 /*****************************************************************************
411  * vout_Init: initialize X11 video thread output method
412  *****************************************************************************
413  * This function create the XImages needed by the output thread. It is called
414  * at the beginning of the thread, but also each time the window is resized.
415  *****************************************************************************/
416 static int vout_Init( vout_thread_t *p_vout )
417 {
418     int i_index;
419     picture_t *p_pic;
420
421     I_OUTPUTPICTURES = 0;
422
423 #ifdef MODULE_NAME_IS_xvideo
424     /* Initialize the output structure */
425     switch( p_vout->render.i_chroma )
426     {
427         case FOURCC_I420:
428         case FOURCC_IYUV:
429         case FOURCC_YV12:
430             p_vout->output.i_chroma = p_vout->render.i_chroma;
431             p_vout->output.i_width  = p_vout->render.i_width;
432             p_vout->output.i_height = p_vout->render.i_height;
433             p_vout->output.i_aspect = p_vout->render.i_aspect;
434             break;
435
436         default:
437             return( 0 );
438     }
439 #else
440     /* Initialize the output structure: RGB with square pixels, whatever
441      * the input format is, since it's the only format we know */
442     switch( p_vout->p_sys->i_screen_depth )
443     {
444         case 8: /* FIXME: set the palette */
445             p_vout->output.i_chroma = FOURCC_BI_RGB | DEPTH_8BPP; break;
446         case 15:
447             p_vout->output.i_chroma = FOURCC_BI_BITFIELDS | DEPTH_15BPP; break;
448         case 16:
449             p_vout->output.i_chroma = FOURCC_BI_BITFIELDS | DEPTH_16BPP; break;
450         case 24:
451             p_vout->output.i_chroma = FOURCC_BI_BITFIELDS | DEPTH_24BPP; break;
452         case 32:
453             p_vout->output.i_chroma = FOURCC_BI_BITFIELDS | DEPTH_32BPP; break;
454         default:
455             intf_ErrMsg( "vout error: unknown screen depth" );
456             return( 0 );
457     }
458
459     p_vout->output.i_width = p_vout->p_sys->i_width;
460     p_vout->output.i_height = p_vout->p_sys->i_height;
461
462     /* Assume we have square pixels */
463     p_vout->output.i_aspect = p_vout->p_sys->i_width
464                                * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
465 #endif
466
467     /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
468     while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
469     {
470         p_pic = NULL;
471
472         /* Find an empty picture slot */
473         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
474         {
475             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
476             {
477                 p_pic = p_vout->p_picture + i_index;
478                 break;
479             }
480         }
481
482         /* Allocate the picture */
483         if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
484         {
485             break;
486         }
487
488         p_pic->i_status        = DESTROYED_PICTURE;
489         p_pic->i_type          = DIRECT_PICTURE;
490
491         p_pic->i_left_margin   =
492         p_pic->i_right_margin  =
493         p_pic->i_top_margin    = 
494         p_pic->i_bottom_margin = 0;
495
496         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
497
498         I_OUTPUTPICTURES++;
499     }
500
501     return( 0 );
502 }
503
504 /*****************************************************************************
505  * vout_Display: displays previously rendered output
506  *****************************************************************************
507  * This function sends the currently rendered image to X11 server.
508  * (The Xv extension takes care of "double-buffering".)
509  *****************************************************************************/
510 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
511 {
512     int i_width, i_height, i_x, i_y;
513
514     vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
515                        &i_x, &i_y, &i_width, &i_height );
516
517     if( p_vout->p_sys->b_shm )
518     {
519         /* Display rendered image using shared memory extension */
520 #ifdef MODULE_NAME_IS_xvideo
521         XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
522                        p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
523                        p_pic->p_sys->p_image, 0 /*src_x*/, 0 /*src_y*/,
524                        p_vout->output.i_width, p_vout->output.i_height,
525                        0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height,
526                        False /* Don't put True here or you'll waste your CPU */ );
527 #else
528         XShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->window,
529                       p_vout->p_sys->gc, p_pic->p_sys->p_image,
530                       0 /*src_x*/, 0 /*src_y*/, 0 /*dest_x*/, 0 /*dest_y*/,
531                       p_vout->output.i_width, p_vout->output.i_height,
532                       False /* Don't put True here ! */ );
533 #endif
534     }
535     else
536     {
537         /* Use standard XPutImage -- this is gonna be slow ! */
538 #ifdef MODULE_NAME_IS_xvideo
539         XvPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
540                     p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
541                     p_pic->p_sys->p_image, 0 /*src_x*/, 0 /*src_y*/,
542                     p_vout->output.i_width, p_vout->output.i_height,
543                     0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height );
544 #else
545         XPutImage( p_vout->p_sys->p_display, p_vout->p_sys->window,
546                    p_vout->p_sys->gc, p_pic->p_sys->p_image,
547                    0 /*src_x*/, 0 /*src_y*/, 0 /*dest_x*/, 0 /*dest_y*/,
548                    p_vout->output.i_width, p_vout->output.i_height );
549 #endif
550     }
551
552     /* Make sure the command is sent now */
553     XFlush( p_vout->p_sys->p_display );
554 }
555
556 /*****************************************************************************
557  * vout_Manage: handle X11 events
558  *****************************************************************************
559  * This function should be called regularly by video output thread. It manages
560  * X11 events and allows window resizing. It returns a non null value on
561  * error.
562  *****************************************************************************/
563 static int vout_Manage( vout_thread_t *p_vout )
564 {
565     XEvent      xevent;                                         /* X11 event */
566     boolean_t   b_resized;                        /* window has been resized */
567     char        i_key;                                    /* ISO Latin-1 key */
568     KeySym      x_key_symbol;
569
570     /* Handle X11 events: ConfigureNotify events are parsed to know if the
571      * output window's size changed, MapNotify and UnmapNotify to know if the
572      * window is mapped (and if the display is useful), and ClientMessages
573      * to intercept window destruction requests */
574
575     b_resized = 0;
576     while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
577                               StructureNotifyMask | KeyPressMask |
578                               ButtonPressMask | ButtonReleaseMask | 
579                               PointerMotionMask | Button1MotionMask , &xevent )
580            == True )
581     {
582         /* ConfigureNotify event: prepare  */
583         if( (xevent.type == ConfigureNotify)
584           && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
585              || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
586         {
587             /* Update dimensions */
588             b_resized = 1;
589             p_vout->i_changes |= VOUT_SIZE_CHANGE;
590             p_vout->p_sys->i_width = xevent.xconfigure.width;
591             p_vout->p_sys->i_height = xevent.xconfigure.height;
592         }
593         /* MapNotify event: change window status and disable screen saver */
594         else if( xevent.type == MapNotify)
595         {
596             if( (p_vout != NULL) && !p_vout->b_active )
597             {
598                 DisableXScreenSaver( p_vout );
599                 p_vout->b_active = 1;
600             }
601         }
602         /* UnmapNotify event: change window status and enable screen saver */
603         else if( xevent.type == UnmapNotify )
604         {
605             if( (p_vout != NULL) && p_vout->b_active )
606             {
607                 EnableXScreenSaver( p_vout );
608                 p_vout->b_active = 0;
609             }
610         }
611         /* Keyboard event */
612         else if( xevent.type == KeyPress )
613         {
614             /* We may have keys like F1 trough F12, ESC ... */
615             x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
616                                              xevent.xkey.keycode, 0 );
617             switch( x_key_symbol )
618             {
619                  case XK_Escape:
620                      p_main->p_intf->b_die = 1;
621                      break;
622                  case XK_Menu:
623                      p_main->p_intf->b_menu_change = 1;
624                      break;
625                  case XK_Left:
626                      vout_Seek( -5 );
627                      break;
628                  case XK_Right:
629                      vout_Seek( 5 );
630                      break;
631                  case XK_Up:
632                      vout_Seek( 60 );
633                      break;
634                  case XK_Down:
635                      vout_Seek( -60 );
636                      break;
637                  case XK_Home:
638                      input_Seek( p_main->p_intf->p_input,
639                      p_main->p_intf->p_input->stream.p_selected_area->i_start );
640                      break;
641                  case XK_End:
642                      input_Seek( p_main->p_intf->p_input,
643                      p_main->p_intf->p_input->stream.p_selected_area->i_size );
644                      break;
645                  case XK_Page_Up:
646                      vout_Seek( 900 );
647                      break;
648                  case XK_Page_Down:
649                      vout_Seek( -900 );
650                      break;
651                  case XK_space:
652                      input_SetStatus( p_main->p_intf->p_input,
653                                       INPUT_STATUS_PAUSE );
654                      break;
655
656                  default:
657                      /* "Normal Keys"
658                       * The reason why I use this instead of XK_0 is that 
659                       * with XLookupString, we don't have to care about
660                       * keymaps. */
661
662                     if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
663                     {
664                         /* FIXME: handle stuff here */
665                         switch( i_key )
666                         {
667                         case 'q':
668                         case 'Q':
669                             p_main->p_intf->b_die = 1;
670                             break;
671                         case 'f':
672                         case 'F':
673                             p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
674                             break;
675
676                         case '0': network_ChannelJoin( 0 ); break;
677                         case '1': network_ChannelJoin( 1 ); break;
678                         case '2': network_ChannelJoin( 2 ); break;
679                         case '3': network_ChannelJoin( 3 ); break;
680                         case '4': network_ChannelJoin( 4 ); break;
681                         case '5': network_ChannelJoin( 5 ); break;
682                         case '6': network_ChannelJoin( 6 ); break;
683                         case '7': network_ChannelJoin( 7 ); break;
684                         case '8': network_ChannelJoin( 8 ); break;
685                         case '9': network_ChannelJoin( 9 ); break;
686
687                         default:
688                             intf_DbgMsg( "vout: unhandled key '%c' (%i)", 
689                                          (char)i_key, i_key );
690                             break;
691                         }
692                     }
693                 break;
694             }
695         }
696         /* Mouse click */
697         else if( xevent.type == ButtonPress )
698         {
699             switch( ((XButtonEvent *)&xevent)->button )
700             {
701                 case Button1:
702                     /* In this part we will eventually manage
703                      * clicks for DVD navigation for instance. For the
704                      * moment just pause the stream. */
705                     input_SetStatus( p_main->p_intf->p_input,
706                                      INPUT_STATUS_PAUSE );
707                     break;
708
709                 case Button4:
710                     vout_Seek( 15 );
711                     break;
712
713                 case Button5:
714                     vout_Seek( -15 );
715                     break;
716             }
717         }
718         /* Mouse release */
719         else if( xevent.type == ButtonRelease )
720         {
721             switch( ((XButtonEvent *)&xevent)->button )
722             {
723                 case Button3:
724                     /* FIXME: need locking ! */
725                     p_main->p_intf->b_menu_change = 1;
726                     break;
727             }
728         }
729         /* Mouse move */
730         else if( xevent.type == MotionNotify )
731         {
732             p_vout->p_sys->i_time_mouse_last_moved = mdate();
733             if( ! p_vout->p_sys->b_mouse_pointer_visible )
734             {
735                 ToggleCursor( p_vout ); 
736             }
737         }
738         /* Other event */
739         else
740         {
741             intf_WarnMsg( 3, "vout: unhandled event %d received", xevent.type );
742         }
743     }
744
745 #ifdef MODULE_NAME_IS_xvideo
746     /* Handle events for YUV video output sub-window */
747     while( XCheckWindowEvent( p_vout->p_sys->p_display,
748                               p_vout->p_sys->yuv_window,
749                               ExposureMask, &xevent ) == True )
750     {
751         /* Window exposed (only handled if stream playback is paused) */
752         if( xevent.type == Expose )
753         {
754             if( ((XExposeEvent *)&xevent)->count == 0 )
755             {
756                 /* (if this is the last a collection of expose events...) */
757                 if( p_main->p_intf->p_input != NULL )
758                 {
759                     if( PAUSE_S ==
760                             p_main->p_intf->p_input->stream.control.i_status )
761                     {
762 /*                        XVideoDisplay( p_vout )*/;
763                     }
764                 }
765             }
766         }
767     }
768 #endif
769
770     /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
771      * are handled - according to the man pages, the format is always 32
772      * in this case */
773     while( XCheckTypedEvent( p_vout->p_sys->p_display,
774                              ClientMessage, &xevent ) )
775     {
776         if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
777             && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
778         {
779             p_main->p_intf->b_die = 1;
780         }
781         else
782         {
783             intf_DbgMsg( "vout: unhandled ClientMessage received" );
784         }
785     }
786
787     /*
788      * Fullscreen Change
789      */
790     if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
791     {
792         ToggleFullScreen( p_vout );
793         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
794
795     }
796
797
798 #ifdef MODULE_NAME_IS_x11
799     /*
800      * Handle vout window resizing
801      */
802 #if 0
803     if( b_resized )
804     {
805         /* If interface window has been resized, change vout size */
806         intf_DbgMsg( "vout: resizing output window" );
807         p_vout->i_width =  p_vout->p_sys->i_width;
808         p_vout->i_height = p_vout->p_sys->i_height;
809         p_vout->i_changes |= VOUT_SIZE_CHANGE;
810     }
811     else if( (p_vout->i_width  != p_vout->p_sys->i_width) ||
812              (p_vout->i_height != p_vout->p_sys->i_height) )
813     {
814         /* If video output size has changed, change interface window size */
815         intf_DbgMsg( "vout: resizing output window" );
816         p_vout->p_sys->i_width =    p_vout->i_width;
817         p_vout->p_sys->i_height =   p_vout->i_height;
818         XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
819                        p_vout->p_sys->i_width, p_vout->p_sys->i_height );
820     }
821     /*
822      * Color/Grayscale or gamma change: in 8bpp, just change the colormap
823      */
824     if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE)
825         && (p_vout->i_screen_depth == 8) )
826     {
827         /* FIXME: clear flags ?? */
828     }
829
830     /*
831      * Size change
832      */
833     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
834     {
835         intf_DbgMsg( "vout info: resizing window" );
836         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
837
838         /* Resize window */
839         XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
840                        p_vout->i_width, p_vout->i_height );
841
842         /* Destroy XImages to change their size */
843         vout_End( p_vout );
844
845         /* Recreate XImages. If SysInit failed, the thread can't go on. */
846         if( vout_Init( p_vout ) )
847         {
848             intf_ErrMsg( "vout error: cannot resize display" );
849             return( 1 );
850        }
851
852         /* Tell the video output thread that it will need to rebuild YUV
853          * tables. This is needed since conversion buffer size may have
854          * changed */
855         p_vout->i_changes |= VOUT_YUV_CHANGE;
856         intf_Msg( "vout: video display resized (%dx%d)",
857                   p_vout->i_width, p_vout->i_height);
858     }
859 #endif /* #if 0 */
860 #else
861     /*
862      * Size change
863      */
864     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
865     {
866         int i_width, i_height, i_x, i_y;
867
868         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
869
870         intf_WarnMsg( 3, "vout: video display resized (%dx%d)",
871                       p_vout->p_sys->i_width,
872                       p_vout->p_sys->i_height );
873  
874         vout_PlacePicture( p_vout, p_vout->p_sys->i_width,
875                            p_vout->p_sys->i_height,
876                            &i_x, &i_y, &i_width, &i_height );
877
878         XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
879                        i_width, i_height );
880         
881         XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
882                      i_x, i_y );
883
884     }
885 #endif
886
887     /* Autohide Cursour */
888     if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
889     {
890         /* Hide the mouse automatically */
891         if( p_vout->p_sys->b_mouse_pointer_visible )
892         {
893             ToggleCursor( p_vout ); 
894         }
895     }
896
897     return 0;
898 }
899
900 /*****************************************************************************
901  * vout_End: terminate X11 video thread output method
902  *****************************************************************************
903  * Destroy the X11 XImages created by vout_Init. It is called at the end of
904  * the thread, but also each time the window is resized.
905  *****************************************************************************/
906 static void vout_End( vout_thread_t *p_vout )
907 {
908     int i_index;
909
910     /* Free the direct buffers we allocated */
911     for( i_index = I_OUTPUTPICTURES ; i_index ; )
912     {
913         i_index--;
914         FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
915     }
916 }
917
918 /* following functions are local */
919
920 /*****************************************************************************
921  * CreateWindow: open and set-up X11 main window
922  *****************************************************************************/
923 static int CreateWindow( vout_thread_t *p_vout )
924 {
925     XSizeHints              xsize_hints;
926     XSetWindowAttributes    xwindow_attributes;
927     XGCValues               xgcvalues;
928     XEvent                  xevent;
929
930     boolean_t               b_expose;
931     boolean_t               b_configure_notify;
932     boolean_t               b_map_notify;
933
934     /* Set main window's size */
935     if( p_vout->render.i_height * p_vout->render.i_aspect
936         >= p_vout->render.i_width * VOUT_ASPECT_FACTOR )
937     {
938         p_vout->p_sys->i_width = p_vout->render.i_height
939           * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
940         p_vout->p_sys->i_height = p_vout->render.i_height;
941     }
942     else
943     {
944         p_vout->p_sys->i_width = p_vout->render.i_width;
945         p_vout->p_sys->i_height = p_vout->render.i_width
946           * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
947     }
948
949 #if 0
950     if( p_vout->p_sys->i_width <= 300 && p_vout->p_sys->i_height <= 300 )
951     {
952         p_vout->p_sys->i_width <<= 1;
953         p_vout->p_sys->i_height <<= 1;
954     }
955     else if( p_vout->p_sys->i_width <= 400
956              && p_vout->p_sys->i_height <= 400 )
957     {
958         p_vout->p_sys->i_width += p_vout->p_sys->i_width >> 1;
959         p_vout->p_sys->i_height += p_vout->p_sys->i_height >> 1;
960     }
961 #endif
962
963     /* Prepare window manager hints and properties */
964     xsize_hints.base_width          = p_vout->p_sys->i_width;
965     xsize_hints.base_height         = p_vout->p_sys->i_height;
966     xsize_hints.flags               = PSize;
967     p_vout->p_sys->wm_protocols     = XInternAtom( p_vout->p_sys->p_display,
968                                                    "WM_PROTOCOLS", True );
969     p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
970                                                    "WM_DELETE_WINDOW", True );
971
972     /* Prepare window attributes */
973     xwindow_attributes.backing_store = Always;       /* save the hidden part */
974     xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
975                                                      p_vout->p_sys->i_screen);
976     xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
977     
978
979     /* Create the window and set hints - the window must receive
980      * ConfigureNotify events, and until it is displayed, Expose and
981      * MapNotify events. */
982
983     p_vout->p_sys->window =
984         XCreateWindow( p_vout->p_sys->p_display,
985                        DefaultRootWindow( p_vout->p_sys->p_display ),
986                        0, 0,
987                        p_vout->p_sys->i_width,
988                        p_vout->p_sys->i_height,
989                        0,
990                        0, InputOutput, 0,
991                        CWBackingStore | CWBackPixel | CWEventMask,
992                        &xwindow_attributes );
993
994     /* Set window manager hints and properties: size hints, command,
995      * window's name, and accepted protocols */
996     XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
997                        &xsize_hints );
998     XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
999                  p_main->ppsz_argv, p_main->i_argc );
1000     XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
1001 #ifdef MODULE_NAME_IS_x11
1002                 VOUT_TITLE " (X11 output)"
1003 #else
1004                 VOUT_TITLE " (XVideo output)"
1005 #endif
1006               );
1007
1008     if( (p_vout->p_sys->wm_protocols == None)        /* use WM_DELETE_WINDOW */
1009         || (p_vout->p_sys->wm_delete_window == None)
1010         || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
1011                              &p_vout->p_sys->wm_delete_window, 1 ) )
1012     {
1013         /* WM_DELETE_WINDOW is not supported by window manager */
1014         intf_Msg( "vout error: missing or bad window manager" );
1015     } 
1016
1017     /* Creation of a graphic context that doesn't generate a GraphicsExpose
1018      * event when using functions like XCopyArea */
1019     xgcvalues.graphics_exposures = False;
1020     p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
1021                                    p_vout->p_sys->window,
1022                                    GCGraphicsExposures, &xgcvalues);
1023
1024     /* Send orders to server, and wait until window is displayed - three
1025      * events must be received: a MapNotify event, an Expose event allowing
1026      * drawing in the window, and a ConfigureNotify to get the window
1027      * dimensions. Once those events have been received, only ConfigureNotify
1028      * events need to be received. */
1029     b_expose = 0;
1030     b_configure_notify = 0;
1031     b_map_notify = 0;
1032     XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
1033     do
1034     {
1035         XNextEvent( p_vout->p_sys->p_display, &xevent);
1036         if( (xevent.type == Expose)
1037             && (xevent.xexpose.window == p_vout->p_sys->window) )
1038         {
1039             b_expose = 1;
1040         }
1041         else if( (xevent.type == MapNotify)
1042                  && (xevent.xmap.window == p_vout->p_sys->window) )
1043         {
1044             b_map_notify = 1;
1045         }
1046         else if( (xevent.type == ConfigureNotify)
1047                  && (xevent.xconfigure.window == p_vout->p_sys->window) )
1048         {
1049             b_configure_notify = 1;
1050             p_vout->p_sys->i_width = xevent.xconfigure.width;
1051             p_vout->p_sys->i_height = xevent.xconfigure.height;
1052         }
1053     } while( !( b_expose && b_configure_notify && b_map_notify ) );
1054
1055     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
1056                   StructureNotifyMask | KeyPressMask |
1057                   ButtonPressMask | ButtonReleaseMask | 
1058                   PointerMotionMask );
1059
1060 #ifdef MODULE_NAME_IS_x11
1061     if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
1062     {
1063         /* Allocate a new palette */
1064         p_vout->p_sys->colormap =
1065             XCreateColormap( p_vout->p_sys->p_display,
1066                              DefaultRootWindow( p_vout->p_sys->p_display ),
1067                              DefaultVisual( p_vout->p_sys->p_display,
1068                                             p_vout->p_sys->i_screen ),
1069                              AllocAll );
1070
1071         xwindow_attributes.colormap = p_vout->p_sys->colormap;
1072         XChangeWindowAttributes( p_vout->p_sys->p_display,
1073                                  p_vout->p_sys->window,
1074                                  CWColormap, &xwindow_attributes );
1075     }
1076
1077 #else
1078     /* Create YUV output sub-window. */
1079     p_vout->p_sys->yuv_window = XCreateSimpleWindow( p_vout->p_sys->p_display,
1080                          p_vout->p_sys->window, 0, 0,
1081                          p_vout->p_sys->i_width,
1082                          p_vout->p_sys->i_height,
1083                          0,
1084                          BlackPixel( p_vout->p_sys->p_display,
1085                                          p_vout->p_sys->i_screen ),
1086                          WhitePixel( p_vout->p_sys->p_display,
1087                                          p_vout->p_sys->i_screen ) );
1088     
1089     XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1090              BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
1091     
1092     XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
1093     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
1094                   ExposureMask );
1095 #endif
1096
1097     /* If the cursor was formerly blank than blank it again */
1098     if( !p_vout->p_sys->b_mouse_pointer_visible )
1099     {
1100         ToggleCursor( p_vout );
1101         ToggleCursor( p_vout );
1102     }
1103
1104     XSync( p_vout->p_sys->p_display, False );
1105
1106     /* At this stage, the window is open, displayed, and ready to
1107      * receive data */
1108
1109     return( 0 );
1110 }
1111
1112 /*****************************************************************************
1113  * DestroyWindow: destroy the window
1114  *****************************************************************************
1115  *
1116  *****************************************************************************/
1117 static void DestroyWindow( vout_thread_t *p_vout )
1118 {
1119     XSync( p_vout->p_sys->p_display, False );
1120
1121 #ifdef MODULE_NAME_IS_xvideo
1122     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
1123 #endif
1124
1125     XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
1126     XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
1127     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
1128 }
1129
1130 /*****************************************************************************
1131  * NewPicture: allocate a picture
1132  *****************************************************************************
1133  * Returns 0 on success, -1 otherwise
1134  *****************************************************************************/
1135 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
1136 {
1137 #define P p_pic->planes
1138     int i_width  = p_vout->output.i_width;
1139     int i_height = p_vout->output.i_height;
1140     
1141     switch( ONLY_FOURCC( p_vout->output.i_chroma ) )
1142     {
1143 #ifdef MODULE_NAME_IS_xvideo
1144         case FOURCC_I420:
1145             /* We know this chroma, allocate a buffer which will be used
1146              * directly by the decoder */
1147             p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
1148
1149             if( p_pic->p_sys == NULL )
1150             {
1151                 return -1;
1152             }
1153
1154             if( p_vout->p_sys->b_shm )
1155             {
1156                 /* Create XvImage using XShm extension */
1157                 p_pic->p_sys->p_image =
1158                     CreateShmImage( p_vout->p_sys->p_display,
1159                                     p_vout->p_sys->i_xvport,
1160                                     GUID_YUV12_PLANAR,
1161                                     &p_pic->p_sys->shminfo,
1162                                     p_vout->output.i_width,
1163                                     p_vout->output.i_height );
1164             }
1165             else
1166             {
1167                 /* Create XvImage using XShm extension */
1168                 p_pic->p_sys->p_image =
1169                     CreateImage( p_vout->p_sys->p_display,
1170                                  p_vout->p_sys->i_xvport,
1171                                  GUID_YUV12_PLANAR,
1172                                  p_vout->output.i_width,
1173                                  p_vout->output.i_height );
1174             }
1175
1176             if( p_pic->p_sys->p_image == NULL )
1177             {
1178                 free( p_pic->p_sys );
1179                 return -1;
1180             }
1181
1182             /* FIXME: try to get the right i_bytes value from p_image */
1183             P[Y_PLANE].p_data = p_pic->p_sys->p_image->data;
1184             P[Y_PLANE].i_bytes = i_width * i_height;
1185             P[Y_PLANE].i_line_bytes = i_width;
1186
1187             P[U_PLANE].p_data = P[Y_PLANE].p_data + i_width * i_height * 5 / 4;
1188             P[U_PLANE].i_bytes = i_width * i_height / 4;
1189             P[U_PLANE].i_line_bytes = i_width / 2;
1190
1191             P[V_PLANE].p_data = P[Y_PLANE].p_data + i_width * i_height;
1192             P[V_PLANE].i_bytes = i_width * i_height / 4;
1193             P[V_PLANE].i_line_bytes = i_width / 2;
1194
1195             p_pic->i_planes = 3;
1196
1197             return 0;
1198 #endif
1199
1200 #ifdef MODULE_NAME_IS_x11
1201         case FOURCC_BI_BITFIELDS:
1202             p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
1203
1204             if( p_pic->p_sys == NULL )
1205             {
1206                 return -1;
1207             }
1208
1209             if( p_vout->p_sys->b_shm )
1210             {
1211                 p_pic->p_sys->p_image =
1212                     CreateShmImage( p_vout->p_sys->p_display,
1213                                     p_vout->p_sys->p_visual,
1214                                     p_vout->p_sys->i_screen_depth,
1215                                     &p_pic->p_sys->shminfo,
1216                                     i_width, i_height );
1217             }
1218             else
1219             {
1220                 p_pic->p_sys->p_image =
1221                     CreateImage( p_vout->p_sys->p_display,
1222                                  p_vout->p_sys->p_visual,
1223                                  p_vout->p_sys->i_screen_depth, 
1224                                  p_vout->p_sys->i_bytes_per_pixel,
1225                                  i_width, i_height );
1226             }
1227
1228             if( p_pic->p_sys->p_image == NULL )
1229             {
1230                 free( p_pic->p_sys );
1231                 return -1;
1232             }
1233
1234             /* FIXME: try to get the right i_bytes value from p_image */
1235             P[ MAIN_PLANE ].p_data = p_pic->p_sys->p_image->data;
1236             P[ MAIN_PLANE ].i_bytes = p_vout->p_sys->i_bytes_per_pixel
1237                                        * i_width * i_height;
1238             P[ MAIN_PLANE ].i_line_bytes = p_vout->p_sys->i_bytes_per_pixel
1239                                             * i_width;
1240
1241             P[ MAIN_PLANE ].i_red_mask = p_vout->p_sys->i_red_mask;
1242             P[ MAIN_PLANE ].i_green_mask = p_vout->p_sys->i_green_mask;
1243             P[ MAIN_PLANE ].i_blue_mask = p_vout->p_sys->i_blue_mask;
1244
1245             p_pic->i_planes = 1;
1246
1247             return 0;
1248 #endif
1249
1250         default:
1251             /* Unknown chroma, tell the guy to get lost */
1252             p_pic->i_planes = 0;
1253
1254             return -1;
1255     }
1256 #undef P
1257 }
1258
1259 /*****************************************************************************
1260  * FreePicture: destroy a picture allocated with NewPicture
1261  *****************************************************************************
1262  * Destroy XImage AND associated data. If using Shm, detach shared memory
1263  * segment from server and process, then free it. The XDestroyImage manpage
1264  * says that both the image structure _and_ the data pointed to by the
1265  * image structure are freed, so no need to free p_image->data.
1266  *****************************************************************************/
1267 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1268 {
1269     /* The order of operations is correct */
1270     if( p_vout->p_sys->b_shm )
1271     {
1272         XShmDetach( p_vout->p_sys->p_display, &p_pic->p_sys->shminfo );
1273         IMAGE_FREE( p_pic->p_sys->p_image );
1274
1275         shmctl( p_pic->p_sys->shminfo.shmid, IPC_RMID, 0 );
1276         if( shmdt( p_pic->p_sys->shminfo.shmaddr ) )
1277         {
1278             intf_ErrMsg( "vout error: cannot detach shared memory (%s)",
1279                          strerror(errno) );
1280         }
1281     }
1282     else
1283     {
1284         IMAGE_FREE( p_pic->p_sys->p_image );
1285     }
1286
1287     XSync( p_vout->p_sys->p_display, False );
1288
1289     free( p_pic->p_sys );
1290 }
1291
1292 /*****************************************************************************
1293  * ToggleFullScreen: Enable or disable full screen mode
1294  *****************************************************************************
1295  * This function will switch between fullscreen and window mode.
1296  *
1297  *****************************************************************************/
1298 static void ToggleFullScreen ( vout_thread_t *p_vout )
1299 {
1300   Atom prop;
1301   mwmhints_t mwmhints;
1302   int i_xpos, i_ypos, i_width, i_height;
1303
1304   p_vout->b_fullscreen = !p_vout->b_fullscreen;
1305
1306   if( p_vout->b_fullscreen )
1307   {
1308       Window next_parent, parent, *p_dummy, dummy1;
1309       unsigned int dummy2, dummy3;
1310      
1311       intf_WarnMsg( 3, "vout: entering fullscreen mode" );
1312
1313       /* Save current window coordinates so they can be restored when
1314        * we exit from fullscreen mode */
1315
1316       /* find the real parent, which means the which is a direct child of
1317        * the root window */
1318       next_parent = parent = p_vout->p_sys->window;
1319       while( next_parent != DefaultRootWindow( p_vout->p_sys->p_display ) )
1320       {
1321           parent = next_parent;
1322           XQueryTree( p_vout->p_sys->p_display,
1323                       parent,
1324                       &dummy1,
1325                       &next_parent,
1326                       &p_dummy,
1327                       &dummy2 );
1328           XFree((void *)p_dummy);
1329       }
1330
1331       XGetGeometry( p_vout->p_sys->p_display,
1332                     p_vout->p_sys->window,
1333                     &dummy1,
1334                     &dummy2,
1335                     &dummy3,
1336                     &p_vout->p_sys->i_width_backup,
1337                     &p_vout->p_sys->i_height_backup,
1338                     &dummy2, &dummy3 );
1339
1340       XTranslateCoordinates( p_vout->p_sys->p_display,
1341                              parent,
1342                              DefaultRootWindow( p_vout->p_sys->p_display ),
1343                              0,
1344                              0,
1345                              &p_vout->p_sys->i_xpos_backup,
1346                              &p_vout->p_sys->i_ypos_backup,
1347                              &dummy1 );
1348
1349       mwmhints.flags = MWM_HINTS_DECORATIONS;
1350       mwmhints.decorations = 0;
1351
1352       i_xpos = 0;
1353       i_ypos = 0;
1354       i_width = DisplayWidth( p_vout->p_sys->p_display,
1355                               p_vout->p_sys->i_screen );
1356       i_height = DisplayHeight( p_vout->p_sys->p_display,
1357                                 p_vout->p_sys->i_screen );
1358
1359 #if 0
1360       /* Being a transient window allows us to really be fullscreen (display
1361        * over the taskbar for instance) but then we end-up with the same
1362        * result as with the brute force method */
1363       XSetTransientForHint( p_vout->p_sys->p_display,
1364                             p_vout->p_sys->window, None );
1365 #endif
1366   }
1367   else
1368   {
1369       intf_WarnMsg( 3, "vout: leaving fullscreen mode" );
1370       
1371       mwmhints.flags = MWM_HINTS_DECORATIONS;
1372       mwmhints.decorations = 1;
1373
1374       i_xpos = p_vout->p_sys->i_xpos_backup;
1375       i_ypos = p_vout->p_sys->i_ypos_backup;
1376       i_width = p_vout->p_sys->i_width_backup;
1377       i_height = p_vout->p_sys->i_height_backup;
1378   }
1379
1380   /* To my knowledge there are two ways to create a borderless window.
1381    * There's the generic way which is to tell x to bypass the window manager,
1382    * but this creates problems with the focus of other applications.
1383    * The other way is to use the motif property "_MOTIF_WM_HINTS" which
1384    * luckily seems to be supported by most window managers.
1385    */
1386   prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS",
1387                       False );
1388   XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
1389                    prop, prop, 32, PropModeReplace,
1390                    (unsigned char *)&mwmhints,
1391                    PROP_MWM_HINTS_ELEMENTS );
1392 #if 0 /* brute force way to remove decorations */
1393   XSetWindowAttributes attributes;
1394   attributes.override_redirect = True;
1395   XChangeWindowAttributes( p_vout->p_sys->p_display,
1396                            p_vout->p_sys->window,
1397                            CWOverrideRedirect,
1398                            &attributes);
1399 #endif
1400
1401   /* We need to unmap and remap the window if we want the window 
1402    * manager to take our changes into effect */
1403   XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
1404   XMapRaised( p_vout->p_sys->p_display, p_vout->p_sys->window);
1405   XMoveResizeWindow( p_vout->p_sys->p_display,
1406                      p_vout->p_sys->window,
1407                      i_xpos,
1408                      i_ypos,
1409                      i_width,
1410                      i_height );
1411   XFlush( p_vout->p_sys->p_display );
1412 }
1413
1414 /*****************************************************************************
1415  * EnableXScreenSaver: enable screen saver
1416  *****************************************************************************
1417  * This function enables the screen saver on a display after it has been
1418  * disabled by XDisableScreenSaver.
1419  * FIXME: what happens if multiple vlc sessions are running at the same
1420  *        time ???
1421  *****************************************************************************/
1422 static void EnableXScreenSaver( vout_thread_t *p_vout )
1423 {
1424     int dummy;
1425
1426     intf_DbgMsg( "vout: enabling screen saver" );
1427     XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1428                      p_vout->p_sys->i_ss_interval,
1429                      p_vout->p_sys->i_ss_blanking,
1430                      p_vout->p_sys->i_ss_exposure );
1431
1432     /* Restore DPMS settings */
1433     if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1434     {
1435         if( p_vout->p_sys->b_ss_dpms )
1436             DPMSEnable( p_vout->p_sys->p_display );
1437     }
1438 }
1439
1440 /*****************************************************************************
1441  * DisableXScreenSaver: disable screen saver
1442  *****************************************************************************
1443  * See XEnableXScreenSaver
1444  *****************************************************************************/
1445 static void DisableXScreenSaver( vout_thread_t *p_vout )
1446 {
1447     int dummy;
1448
1449     /* Save screen saver informations */
1450     XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1451                      &p_vout->p_sys->i_ss_interval,
1452                      &p_vout->p_sys->i_ss_blanking,
1453                      &p_vout->p_sys->i_ss_exposure );
1454
1455     /* Disable screen saver */
1456     intf_DbgMsg( "vout: disabling screen saver" );
1457     XSetScreenSaver( p_vout->p_sys->p_display, 0,
1458                      p_vout->p_sys->i_ss_interval,
1459                      p_vout->p_sys->i_ss_blanking,
1460                      p_vout->p_sys->i_ss_exposure );
1461
1462     /* Disable DPMS */
1463     if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1464     {
1465         CARD16 dummy;
1466         /* Save DPMS current state */
1467         DPMSInfo( p_vout->p_sys->p_display, &dummy,
1468                   &p_vout->p_sys->b_ss_dpms );
1469         intf_DbgMsg( "vout: disabling DPMS" );
1470         DPMSDisable( p_vout->p_sys->p_display );
1471    }
1472 }
1473
1474 /*****************************************************************************
1475  * CreateCursor: create a blank mouse pointer
1476  *****************************************************************************/
1477 static void CreateCursor( vout_thread_t *p_vout )
1478 {
1479     XColor cursor_color;
1480
1481     p_vout->p_sys->cursor_pixmap =
1482         XCreatePixmap( p_vout->p_sys->p_display,
1483                        DefaultRootWindow( p_vout->p_sys->p_display ),
1484                        1, 1, 1 );
1485
1486     XParseColor( p_vout->p_sys->p_display,
1487                  XCreateColormap( p_vout->p_sys->p_display,
1488                                   DefaultRootWindow(
1489                                                     p_vout->p_sys->p_display ),
1490                                   DefaultVisual(
1491                                                 p_vout->p_sys->p_display,
1492                                                 p_vout->p_sys->i_screen ),
1493                                   AllocNone ),
1494                  "black", &cursor_color );
1495
1496     p_vout->p_sys->blank_cursor =
1497         XCreatePixmapCursor( p_vout->p_sys->p_display,
1498                              p_vout->p_sys->cursor_pixmap,
1499                              p_vout->p_sys->cursor_pixmap,
1500                              &cursor_color, &cursor_color, 1, 1 );
1501 }
1502
1503 /*****************************************************************************
1504  * DestroyCursor: destroy the blank mouse pointer
1505  *****************************************************************************/
1506 static void DestroyCursor( vout_thread_t *p_vout )
1507 {
1508     XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
1509 }
1510
1511 /*****************************************************************************
1512  * ToggleCursor: hide or show the mouse pointer
1513  *****************************************************************************
1514  * This function hides the X pointer if it is visible by setting the pointer
1515  * sprite to a blank one. To show it again, we disable the sprite.
1516  *****************************************************************************/
1517 static void ToggleCursor( vout_thread_t *p_vout )
1518 {
1519     if( p_vout->p_sys->b_mouse_pointer_visible )
1520     {
1521         XDefineCursor( p_vout->p_sys->p_display,
1522                        p_vout->p_sys->window,
1523                        p_vout->p_sys->blank_cursor );
1524         p_vout->p_sys->b_mouse_pointer_visible = 0;
1525     }
1526     else
1527     {
1528         XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
1529         p_vout->p_sys->b_mouse_pointer_visible = 1;
1530     }
1531 }
1532
1533 #ifdef MODULE_NAME_IS_xvideo
1534 /*****************************************************************************
1535  * XVideoGetPort: get YUV12 port
1536  *****************************************************************************/
1537 static int XVideoGetPort( Display *dpy, int i_id )
1538 {
1539     XvAdaptorInfo *p_adaptor;
1540     unsigned int i;
1541     int i_adaptor, i_num_adaptors, i_requested_adaptor;
1542     int i_selected_port;
1543
1544     switch( XvQueryExtension( dpy, &i, &i, &i, &i, &i ) )
1545     {
1546         case Success:
1547             break;
1548
1549         case XvBadExtension:
1550             intf_WarnMsg( 3, "vout error: XvBadExtension" );
1551             return( -1 );
1552
1553         case XvBadAlloc:
1554             intf_WarnMsg( 3, "vout error: XvBadAlloc" );
1555             return( -1 );
1556
1557         default:
1558             intf_WarnMsg( 3, "vout error: XvQueryExtension failed" );
1559             return( -1 );
1560     }
1561
1562     switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
1563                              &i_num_adaptors, &p_adaptor ) )
1564     {
1565         case Success:
1566             break;
1567
1568         case XvBadExtension:
1569             intf_WarnMsg( 3, "vout error: XvBadExtension for XvQueryAdaptors" );
1570             return( -1 );
1571
1572         case XvBadAlloc:
1573             intf_WarnMsg( 3, "vout error: XvBadAlloc for XvQueryAdaptors" );
1574             return( -1 );
1575
1576         default:
1577             intf_WarnMsg( 3, "vout error: XvQueryAdaptors failed" );
1578             return( -1 );
1579     }
1580
1581     i_selected_port = -1;
1582     i_requested_adaptor = main_GetIntVariable( VOUT_XVADAPTOR_VAR, -1 );
1583
1584     /* No special xv port has been requested so try all of them */
1585     for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
1586     {
1587         XvImageFormatValues *p_formats;
1588         int i_format, i_num_formats;
1589         int i_port;
1590
1591         /* If we requested an adaptor and it's not this one, we aren't
1592          * interested */
1593         if( i_requested_adaptor != -1 && i_adaptor != i_requested_adaptor )
1594         {
1595             continue;
1596         }
1597
1598         /* If the adaptor doesn't have the required properties, skip it */
1599         if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
1600             !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
1601         {
1602             continue;
1603         }
1604
1605         /* Check that port supports YUV12 planar format... */
1606         p_formats = XvListImageFormats( dpy, p_adaptor[i_adaptor].base_id,
1607                                         &i_num_formats );
1608
1609         for( i_format = 0; i_format < i_num_formats; i_format++ )
1610         {
1611             XvEncodingInfo  *p_enc;
1612             int             i_enc, i_num_encodings;
1613             XvAttribute     *p_attr;
1614             int             i_attr, i_num_attributes;
1615
1616             /* If this is not the format we want, forget it */
1617             if( p_formats[ i_format ].id != i_id )
1618             {
1619                 continue;
1620             }
1621
1622             /* Look for the first available port supporting this format */
1623             for( i_port = p_adaptor[i_adaptor].base_id;
1624                  ( i_port < p_adaptor[i_adaptor].base_id
1625                              + p_adaptor[i_adaptor].num_ports )
1626                    && ( i_selected_port == -1 );
1627                  i_port++ )
1628             {
1629                 if( XvGrabPort( dpy, i_port, CurrentTime ) == Success )
1630                 {
1631                     i_selected_port = i_port;
1632                 }
1633             }
1634
1635             /* If no free port was found, forget it */
1636             if( i_selected_port == -1 )
1637             {
1638                 continue;
1639             }
1640
1641             /* If we found a port, print information about it */
1642             intf_WarnMsg( 3, "vout: found adaptor %i, port %i, "
1643                              "image format 0x%x (%4.4s) %s",
1644                              i_adaptor, i_selected_port,
1645                              p_formats[ i_format ].id,
1646                              (char *)&p_formats[ i_format ].id,
1647                              ( p_formats[ i_format ].format
1648                                 == XvPacked ) ? "packed" : "planar" );
1649
1650             intf_WarnMsg( 10, " encoding list:" );
1651
1652             if( XvQueryEncodings( dpy, i_selected_port,
1653                                   &i_num_encodings, &p_enc )
1654                  != Success )
1655             {
1656                 intf_WarnMsg( 10, "  XvQueryEncodings failed" );
1657                 continue;
1658             }
1659
1660             for( i_enc = 0; i_enc < i_num_encodings; i_enc++ )
1661             {
1662                 intf_WarnMsg( 10, "  id=%ld, name=%s, size=%ldx%ld,"
1663                                   " numerator=%d, denominator=%d",
1664                               p_enc[i_enc].encoding_id, p_enc[i_enc].name,
1665                               p_enc[i_enc].width, p_enc[i_enc].height,
1666                               p_enc[i_enc].rate.numerator,
1667                               p_enc[i_enc].rate.denominator );
1668             }
1669
1670             if( p_enc != NULL )
1671             {
1672                 XvFreeEncodingInfo( p_enc );
1673             }
1674
1675             intf_WarnMsg( 10, " attribute list:" );
1676             p_attr = XvQueryPortAttributes( dpy, i_selected_port,
1677                                             &i_num_attributes );
1678             for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
1679             {
1680                 intf_WarnMsg( 10,
1681                       "  name=%s, flags=[%s%s ], min=%i, max=%i",
1682                       p_attr[i_attr].name,
1683                       (p_attr[i_attr].flags & XvGettable) ? " get" : "",
1684                       (p_attr[i_attr].flags & XvSettable) ? " set" : "",
1685                       p_attr[i_attr].min_value, p_attr[i_attr].max_value );
1686             }
1687
1688             if( p_attr != NULL )
1689             {
1690                 XFree( p_attr );
1691             }
1692         }
1693
1694         if( p_formats != NULL )
1695         {
1696             XFree( p_formats );
1697         }
1698
1699     }
1700
1701     if( i_num_adaptors > 0 )
1702     {
1703         XvFreeAdaptorInfo( p_adaptor );
1704     }
1705
1706     if( i_selected_port == -1 )
1707     {
1708         if( i_requested_adaptor == -1 )
1709         {
1710             intf_WarnMsg( 3, "vout: no free XVideo port found for %i", i_id );
1711         }
1712         else
1713         {
1714             intf_WarnMsg( 3, "vout: XVideo adaptor %i does not have a free "
1715                              "XVideo port for %i", i_requested_adaptor, i_id );
1716         }
1717     }
1718
1719     return( i_selected_port );
1720 }
1721
1722 /*****************************************************************************
1723  * XVideoReleasePort: release YUV12 port
1724  *****************************************************************************/
1725 static void XVideoReleasePort( Display *dpy, int i_port )
1726 {
1727     XvUngrabPort( dpy, i_port, CurrentTime );
1728 }
1729 #endif
1730
1731 /*****************************************************************************
1732  * InitDisplay: open and initialize X11 device
1733  *****************************************************************************
1734  * Create a window according to video output given size, and set other
1735  * properties according to the display properties.
1736  *****************************************************************************/
1737 static int InitDisplay( vout_thread_t *p_vout )
1738 {
1739 #ifdef MODULE_NAME_IS_x11
1740     XPixmapFormatValues *       p_formats;                 /* pixmap formats */
1741     XVisualInfo *               p_xvisual;           /* visuals informations */
1742     XVisualInfo                 xvisual_template;         /* visual template */
1743     int                         i_count;                       /* array size */
1744 #endif
1745
1746 #ifdef SYS_DARWIN
1747     /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
1748     p_vout->p_sys->b_shm = 0;
1749 #else
1750     p_vout->p_sys->b_shm = ( XShmQueryExtension( p_vout->p_sys->p_display )
1751                               == True );
1752 #endif
1753     if( !p_vout->p_sys->b_shm )
1754     {
1755         intf_WarnMsg( 1, "vout warning: XShm video extension is unavailable" );
1756     }
1757
1758 #ifdef MODULE_NAME_IS_xvideo
1759     /* XXX The brightness and contrast values should be read from environment
1760      * XXX variables... */
1761 #if 0
1762     XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
1763     XVideoSetAttribute( p_vout, "XV_CONTRAST",   0.5 );
1764 #endif
1765 #endif
1766
1767 #ifdef MODULE_NAME_IS_x11
1768     /* Initialize structure */
1769     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
1770
1771     /* Get screen depth */
1772     p_vout->p_sys->i_screen_depth = XDefaultDepth( p_vout->p_sys->p_display,
1773                                                    p_vout->p_sys->i_screen );
1774     switch( p_vout->p_sys->i_screen_depth )
1775     {
1776     case 8:
1777         /*
1778          * Screen depth is 8bpp. Use PseudoColor visual with private colormap.
1779          */
1780         xvisual_template.screen =   p_vout->p_sys->i_screen;
1781         xvisual_template.class =    DirectColor;
1782         p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
1783                                     VisualScreenMask | VisualClassMask,
1784                                     &xvisual_template, &i_count );
1785         if( p_xvisual == NULL )
1786         {
1787             intf_ErrMsg( "vout error: no PseudoColor visual available" );
1788             return( 1 );
1789         }
1790         p_vout->p_sys->i_bytes_per_pixel = 1;
1791         break;
1792     case 15:
1793     case 16:
1794     case 24:
1795     default:
1796         /*
1797          * Screen depth is higher than 8bpp. TrueColor visual is used.
1798          */
1799         xvisual_template.screen =   p_vout->p_sys->i_screen;
1800         xvisual_template.class =    TrueColor;
1801         p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
1802                                     VisualScreenMask | VisualClassMask,
1803                                     &xvisual_template, &i_count );
1804         if( p_xvisual == NULL )
1805         {
1806             intf_ErrMsg( "vout error: no TrueColor visual available" );
1807             return( 1 );
1808         }
1809         p_vout->p_sys->i_red_mask =        p_xvisual->red_mask;
1810         p_vout->p_sys->i_green_mask =      p_xvisual->green_mask;
1811         p_vout->p_sys->i_blue_mask =       p_xvisual->blue_mask;
1812
1813         /* There is no difference yet between 3 and 4 Bpp. The only way
1814          * to find the actual number of bytes per pixel is to list supported
1815          * pixmap formats. */
1816         p_formats = XListPixmapFormats( p_vout->p_sys->p_display, &i_count );
1817         p_vout->p_sys->i_bytes_per_pixel = 0;
1818
1819         for( ; i_count-- ; p_formats++ )
1820         {
1821             /* Under XFree4.0, the list contains pixmap formats available
1822              * through all video depths ; so we have to check against current
1823              * depth. */
1824             if( p_formats->depth == p_vout->p_sys->i_screen_depth )
1825             {
1826                 if( p_formats->bits_per_pixel / 8
1827                         > p_vout->p_sys->i_bytes_per_pixel )
1828                 {
1829                     p_vout->p_sys->i_bytes_per_pixel = p_formats->bits_per_pixel / 8;
1830                 }
1831             }
1832         }
1833         break;
1834     }
1835     p_vout->p_sys->p_visual = p_xvisual->visual;
1836     XFree( p_xvisual );
1837 #endif
1838
1839     return( 0 );
1840 }
1841
1842 /*****************************************************************************
1843  * CreateShmImage: create an XImage or XvImage using shared memory extension
1844  *****************************************************************************
1845  * Prepare an XImage or XvImage for display function.
1846  * The order of the operations respects the recommandations of the mit-shm
1847  * document by J.Corbet and K.Packard. Most of the parameters were copied from
1848  * there. See http://ftp.xfree86.org/pub/XFree86/4.0/doc/mit-shm.TXT
1849  *****************************************************************************/
1850 static IMAGE_TYPE * CreateShmImage( Display* p_display, EXTRA_ARGS_SHM,
1851                                     int i_width, int i_height )
1852 {
1853     IMAGE_TYPE *p_image;
1854
1855     /* Create XImage / XvImage */
1856 #ifdef MODULE_NAME_IS_xvideo
1857     p_image = XvShmCreateImage( p_display, i_xvport, i_format, 0,
1858                                 i_width, i_height, p_shm );
1859 #else
1860     p_image = XShmCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
1861                                p_shm, i_width, i_height );
1862 #endif
1863     if( p_image == NULL )
1864     {
1865         intf_ErrMsg( "vout error: image creation failed." );
1866         return( NULL );
1867     }
1868
1869     /* Allocate shared memory segment - 0776 set the access permission
1870      * rights (like umask), they are not yet supported by all X servers */
1871     p_shm->shmid = shmget( IPC_PRIVATE, DATA_SIZE(p_image), IPC_CREAT | 0776 );
1872     if( p_shm->shmid < 0 )
1873     {
1874         intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
1875                      strerror( errno ) );
1876         IMAGE_FREE( p_image );
1877         return( NULL );
1878     }
1879
1880     /* Attach shared memory segment to process (read/write) */
1881     p_shm->shmaddr = p_image->data = shmat( p_shm->shmid, 0, 0 );
1882     if(! p_shm->shmaddr )
1883     {
1884         intf_ErrMsg( "vout error: cannot attach shared memory (%s)",
1885                     strerror(errno));
1886         IMAGE_FREE( p_image );
1887         shmctl( p_shm->shmid, IPC_RMID, 0 );
1888         return( NULL );
1889     }
1890
1891     /* Read-only data. We won't be using XShmGetImage */
1892     p_shm->readOnly = True;
1893
1894     /* Attach shared memory segment to X server */
1895     if( XShmAttach( p_display, p_shm ) == False )
1896     {
1897         intf_ErrMsg( "vout error: cannot attach shared memory to X server" );
1898         IMAGE_FREE( p_image );
1899         shmctl( p_shm->shmid, IPC_RMID, 0 );
1900         shmdt( p_shm->shmaddr );
1901         return( NULL );
1902     }
1903
1904     /* Send image to X server. This instruction is required, since having
1905      * built a Shm XImage and not using it causes an error on XCloseDisplay */
1906     XSync( p_display, False );
1907
1908 #if 0
1909     /* Mark the shm segment to be removed when there are no more
1910      * attachements, so it is automatic on process exit or after shmdt */
1911     shmctl( p_shm->shmid, IPC_RMID, 0 );
1912 #endif
1913
1914     return( p_image );
1915 }
1916
1917 /*****************************************************************************
1918  * CreateImage: create an XImage or XvImage
1919  *****************************************************************************
1920  * Create a simple image used as a buffer.
1921  *****************************************************************************/
1922 static IMAGE_TYPE * CreateImage( Display *p_display, EXTRA_ARGS,
1923                                  int i_width, int i_height )
1924 {
1925     byte_t *    p_data;                           /* image data storage zone */
1926     IMAGE_TYPE *p_image;
1927 #ifdef MODULE_NAME_IS_x11
1928     int         i_quantum;                     /* XImage quantum (see below) */
1929     int         i_bytes_per_line;
1930 #endif
1931
1932     /* Allocate memory for image */
1933 #ifdef MODULE_NAME_IS_xvideo
1934     p_data = (byte_t *) malloc( i_width * i_height * 2 ); /* XXX */
1935 #else
1936     i_bytes_per_line = i_width * i_bytes_per_pixel;
1937     p_data = (byte_t *) malloc( i_bytes_per_line * i_height );
1938 #endif
1939     if( !p_data )
1940     {
1941         intf_ErrMsg( "vout error: %s", strerror(ENOMEM));
1942         return( NULL );
1943     }
1944
1945 #ifdef MODULE_NAME_IS_x11
1946     /* Optimize the quantum of a scanline regarding its size - the quantum is
1947        a diviser of the number of bits between the start of two scanlines. */
1948     if( i_bytes_per_line & 0xf )
1949     {
1950         i_quantum = 0x8;
1951     }
1952     else if( i_bytes_per_line & 0x10 )
1953     {
1954         i_quantum = 0x10;
1955     }
1956     else
1957     {
1958         i_quantum = 0x20;
1959     }
1960 #endif
1961
1962     /* Create XImage. p_data will be automatically freed */
1963 #ifdef MODULE_NAME_IS_xvideo
1964     p_image = XvCreateImage( p_display, i_xvport, i_format,
1965                              p_data, i_width, i_height );
1966 #else
1967     p_image = XCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
1968                             p_data, i_width, i_height, i_quantum, 0 );
1969 #endif
1970     if( p_image == NULL )
1971     {
1972         intf_ErrMsg( "vout error: XCreateImage() failed" );
1973         free( p_data );
1974         return( NULL );
1975     }
1976
1977     return p_image;
1978 }
1979