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