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