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