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