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