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