Remove unused property
[vlc.git] / modules / video_output / x11 / xcommon.c
1 /*****************************************************************************
2  * xcommon.c: Functions common to the X11 and XVideo plugins
3  *****************************************************************************
4  * Copyright (C) 1998-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Vincent Seguin <seguin@via.ecp.fr>
8  *          Sam Hocevar <sam@zoy.org>
9  *          David Kennedy <dkennedy@tinytoad.com>
10  *          Gildas Bazin <gbazin@videolan.org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc_common.h>
35 #include <vlc_interface.h>
36 #include <vlc_playlist.h>
37 #include <vlc_vout.h>
38 #include <vlc_vout_window.h>
39 #include <vlc_keys.h>
40
41 #ifdef HAVE_MACHINE_PARAM_H
42     /* BSD */
43 #   include <machine/param.h>
44 #   include <sys/types.h>                                  /* typedef ushort */
45 #   include <sys/ipc.h>
46 #endif
47
48 #ifdef HAVE_XSP
49 #include <X11/extensions/Xsp.h>
50 #endif
51
52 #ifdef HAVE_SYS_SHM_H
53 #   include <sys/shm.h>                                /* shmget(), shmctl() */
54 #endif
55
56 #include <X11/Xlib.h>
57 #include <X11/Xproto.h>
58 #include <X11/Xmd.h>
59 #include <X11/Xutil.h>
60 #include <X11/keysym.h>
61 #include <X11/XF86keysym.h>
62 #ifdef HAVE_SYS_SHM_H
63 #   include <X11/extensions/XShm.h>
64 #endif
65 #ifdef DPMSINFO_IN_DPMS_H
66 #   include <X11/extensions/dpms.h>
67 #endif
68
69 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
70 #   include <X11/extensions/Xv.h>
71 #   include <X11/extensions/Xvlib.h>
72 #endif
73
74 #ifdef MODULE_NAME_IS_glx
75 #   include <GL/glx.h>
76 #endif
77
78 #ifdef MODULE_NAME_IS_xvmc
79 #   include <X11/extensions/vldXvMC.h>
80 #   include "../../codec/xvmc/accel_xvmc.h"
81 #endif
82
83 #include "xcommon.h"
84
85 /*****************************************************************************
86  * Local prototypes
87  *****************************************************************************/
88 int  Activate   ( vlc_object_t * );
89 void Deactivate ( vlc_object_t * );
90
91 static int  InitVideo      ( vout_thread_t * );
92 static void EndVideo       ( vout_thread_t * );
93 static void DisplayVideo   ( vout_thread_t *, picture_t * );
94 static int  ManageVideo    ( vout_thread_t * );
95 static int  Control        ( vout_thread_t *, int, va_list );
96
97 static int  InitDisplay    ( vout_thread_t * );
98
99 static int  CreateWindow   ( vout_thread_t *, x11_window_t * );
100 static void DestroyWindow  ( vout_thread_t *, x11_window_t * );
101
102 static int  NewPicture     ( vout_thread_t *, picture_t * );
103 static void FreePicture    ( vout_thread_t *, picture_t * );
104
105 #ifdef HAVE_SYS_SHM_H
106 static int i_shm_major = 0;
107 #endif
108
109 static void ToggleFullScreen      ( vout_thread_t * );
110
111 static void EnableXScreenSaver    ( vout_thread_t * );
112 static void DisableXScreenSaver   ( vout_thread_t * );
113
114 static void CreateCursor   ( vout_thread_t * );
115 static void DestroyCursor  ( vout_thread_t * );
116 static void ToggleCursor   ( vout_thread_t * );
117
118 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
119 static int  XVideoGetPort    ( vout_thread_t *, vlc_fourcc_t, picture_heap_t * );
120 static void XVideoReleasePort( vout_thread_t *, int );
121 #endif
122
123 #ifdef MODULE_NAME_IS_x11
124 static void SetPalette     ( vout_thread_t *,
125                              uint16_t *, uint16_t *, uint16_t * );
126 #endif
127
128 #ifdef MODULE_NAME_IS_xvmc
129 static void RenderVideo    ( vout_thread_t *, picture_t * );
130 static int  xvmc_check_yv12( Display *display, XvPortID port );
131 static void xvmc_update_XV_DOUBLE_BUFFER( vout_thread_t *p_vout );
132 #endif
133
134 static int X11ErrorHandler( Display *, XErrorEvent * );
135
136 #ifdef HAVE_XSP
137 static void EnablePixelDoubling( vout_thread_t *p_vout );
138 static void DisablePixelDoubling( vout_thread_t *p_vout );
139 #endif
140
141 #ifdef HAVE_OSSO
142 static const int i_backlight_on_interval = 300;
143 #endif
144
145
146
147 /*****************************************************************************
148  * Activate: allocate X11 video thread output method
149  *****************************************************************************
150  * This function allocate and initialize a X11 vout method. It uses some of the
151  * vout properties to choose the window size, and change them according to the
152  * actual properties of the display.
153  *****************************************************************************/
154 int Activate ( vlc_object_t *p_this )
155 {
156     vout_thread_t *p_vout = (vout_thread_t *)p_this;
157     char *        psz_display;
158 #if defined(MODULE_NAME_IS_xvmc)
159     char *psz_value;
160 #endif
161 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
162     char *       psz_chroma;
163     vlc_fourcc_t i_chroma = 0;
164     bool   b_chroma = 0;
165 #endif
166
167     p_vout->pf_init = InitVideo;
168     p_vout->pf_end = EndVideo;
169     p_vout->pf_manage = ManageVideo;
170 #ifdef MODULE_NAME_IS_xvmc
171     p_vout->pf_render = RenderVideo;
172 #else
173     p_vout->pf_render = NULL;
174 #endif
175     p_vout->pf_display = DisplayVideo;
176     p_vout->pf_control = Control;
177
178     /* Allocate structure */
179     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
180     if( p_vout->p_sys == NULL )
181         return VLC_ENOMEM;
182
183     /* key and mouse event handling */
184     p_vout->p_sys->i_vout_event = var_CreateGetInteger( p_vout, "vout-event" );
185
186     /* Open display, using the "display" config variable or the DISPLAY
187      * environment variable */
188     psz_display = config_GetPsz( p_vout, MODULE_STRING "-display" );
189
190     p_vout->p_sys->p_display = XOpenDisplay( psz_display );
191
192     if( p_vout->p_sys->p_display == NULL )                         /* error */
193     {
194         msg_Err( p_vout, "cannot open display %s",
195                          XDisplayName( psz_display ) );
196         free( p_vout->p_sys );
197         free( psz_display );
198         return VLC_EGENERIC;
199     }
200     free( psz_display );
201
202     /* Replace error handler so we can intercept some non-fatal errors */
203     XSetErrorHandler( X11ErrorHandler );
204
205     /* Get a screen ID matching the XOpenDisplay return value */
206     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
207
208 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
209     psz_chroma = config_GetPsz( p_vout, "xvideo-chroma" );
210     if( psz_chroma )
211     {
212         if( strlen( psz_chroma ) >= 4 )
213         {
214             /* Do not use direct assignment because we are not sure of the
215              * alignment. */
216             memcpy(&i_chroma, psz_chroma, 4);
217             b_chroma = 1;
218         }
219
220         free( psz_chroma );
221     }
222
223     if( b_chroma )
224     {
225         msg_Dbg( p_vout, "forcing chroma 0x%.8x (%4.4s)",
226                  i_chroma, (char*)&i_chroma );
227     }
228     else
229     {
230         i_chroma = p_vout->render.i_chroma;
231     }
232
233     /* Check that we have access to an XVideo port providing this chroma */
234     p_vout->p_sys->i_xvport = XVideoGetPort( p_vout, VLC2X11_FOURCC(i_chroma),
235                                              &p_vout->output );
236     if( p_vout->p_sys->i_xvport < 0 )
237     {
238         /* If a specific chroma format was requested, then we don't try to
239          * be cleverer than the user. He knew pretty well what he wanted. */
240         if( b_chroma )
241         {
242             XCloseDisplay( p_vout->p_sys->p_display );
243             free( p_vout->p_sys );
244             return VLC_EGENERIC;
245         }
246
247         /* It failed, but it's not completely lost ! We try to open an
248          * XVideo port for an YUY2 picture. We'll need to do an YUV
249          * conversion, but at least it has got scaling. */
250         p_vout->p_sys->i_xvport =
251                         XVideoGetPort( p_vout, X11_FOURCC('Y','U','Y','2'),
252                                                &p_vout->output );
253         if( p_vout->p_sys->i_xvport < 0 )
254         {
255             /* It failed, but it's not completely lost ! We try to open an
256              * XVideo port for a simple 16bpp RGB picture. We'll need to do
257              * an YUV conversion, but at least it has got scaling. */
258             p_vout->p_sys->i_xvport =
259                             XVideoGetPort( p_vout, X11_FOURCC('R','V','1','6'),
260                                                    &p_vout->output );
261             if( p_vout->p_sys->i_xvport < 0 )
262             {
263                 XCloseDisplay( p_vout->p_sys->p_display );
264                 free( p_vout->p_sys );
265                 return VLC_EGENERIC;
266             }
267         }
268     }
269     p_vout->output.i_chroma = vlc_fourcc_GetCodec( VIDEO_ES, X112VLC_FOURCC(p_vout->output.i_chroma) );
270 #elif defined(MODULE_NAME_IS_glx)
271     {
272         int i_opcode, i_evt, i_err = 0;
273         int i_maj, i_min = 0;
274
275         /* Check for GLX extension */
276         if( !XQueryExtension( p_vout->p_sys->p_display, "GLX",
277                               &i_opcode, &i_evt, &i_err ) )
278         {
279             msg_Err( p_this, "GLX extension not supported" );
280             XCloseDisplay( p_vout->p_sys->p_display );
281             free( p_vout->p_sys );
282             return VLC_EGENERIC;
283         }
284         if( !glXQueryExtension( p_vout->p_sys->p_display, &i_err, &i_evt ) )
285         {
286             msg_Err( p_this, "glXQueryExtension failed" );
287             XCloseDisplay( p_vout->p_sys->p_display );
288             free( p_vout->p_sys );
289             return VLC_EGENERIC;
290         }
291
292         /* Check GLX version */
293         if (!glXQueryVersion( p_vout->p_sys->p_display, &i_maj, &i_min ) )
294         {
295             msg_Err( p_this, "glXQueryVersion failed" );
296             XCloseDisplay( p_vout->p_sys->p_display );
297             free( p_vout->p_sys );
298             return VLC_EGENERIC;
299         }
300         if( i_maj <= 0 || ((i_maj == 1) && (i_min < 3)) )
301         {
302             p_vout->p_sys->b_glx13 = false;
303             msg_Dbg( p_this, "using GLX 1.2 API" );
304         }
305         else
306         {
307             p_vout->p_sys->b_glx13 = true;
308             msg_Dbg( p_this, "using GLX 1.3 API" );
309         }
310     }
311 #endif
312
313     /* Create blank cursor (for mouse cursor autohiding) */
314     p_vout->p_sys->i_time_mouse_last_moved = mdate();
315     p_vout->p_sys->i_mouse_hide_timeout =
316         var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
317     p_vout->p_sys->b_mouse_pointer_visible = 1;
318     CreateCursor( p_vout );
319
320     /* Set main window's size */
321     p_vout->p_sys->window.i_x      = 0;
322     p_vout->p_sys->window.i_y      = 0;
323     p_vout->p_sys->window.i_width  = p_vout->i_window_width;
324     p_vout->p_sys->window.i_height = p_vout->i_window_height;
325     var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
326     /* Spawn base window - this window will include the video output window,
327      * but also command buttons, subtitles and other indicators */
328     if( CreateWindow( p_vout, &p_vout->p_sys->window ) )
329     {
330         msg_Err( p_vout, "cannot create X11 window" );
331         DestroyCursor( p_vout );
332         XCloseDisplay( p_vout->p_sys->p_display );
333         free( p_vout->p_sys );
334         return VLC_EGENERIC;
335     }
336
337     /* Open and initialize device. */
338     if( InitDisplay( p_vout ) )
339     {
340         msg_Err( p_vout, "cannot initialize X11 display" );
341         DestroyCursor( p_vout );
342         DestroyWindow( p_vout, &p_vout->p_sys->window );
343         XCloseDisplay( p_vout->p_sys->p_display );
344         free( p_vout->p_sys );
345         return VLC_EGENERIC;
346     }
347
348     /* Disable screen saver */
349     DisableXScreenSaver( p_vout );
350
351     /* Misc init */
352     p_vout->p_sys->i_time_button_last_pressed = 0;
353
354 #ifdef MODULE_NAME_IS_xvmc
355     p_vout->p_sys->p_last_subtitle_save = NULL;
356     psz_value = config_GetPsz( p_vout, "xvmc-deinterlace-mode" );
357
358     /* Look what method was requested */
359     //var_Create( p_vout, "xvmc-deinterlace-mode", VLC_VAR_STRING );
360     //var_Change( p_vout, "xvmc-deinterlace-mode", VLC_VAR_INHERITVALUE, &val, NULL );
361     if( psz_value )
362     {
363         if( (strcmp(psz_value, "bob") == 0) ||
364             (strcmp(psz_value, "blend") == 0) )
365            p_vout->p_sys->xvmc_deinterlace_method = 2;
366         else if (strcmp(psz_value, "discard") == 0)
367            p_vout->p_sys->xvmc_deinterlace_method = 1;
368         else
369            p_vout->p_sys->xvmc_deinterlace_method = 0;
370         free(psz_value );
371     }
372     else
373         p_vout->p_sys->xvmc_deinterlace_method = 0;
374
375     /* Look what method was requested */
376     //var_Create( p_vout, "xvmc-crop-style", VLC_VAR_STRING );
377     //var_Change( p_vout, "xvmc-crop-style", VLC_VAR_INHERITVALUE, &val, NULL );
378     psz_value = config_GetPsz( p_vout, "xvmc-crop-style" );
379
380     if( psz_value )
381     {
382         if( strncmp( psz_value, "eq", 2 ) == 0 )
383            p_vout->p_sys->xvmc_crop_style = 1;
384         else if( strncmp( psz_value, "4-16", 4 ) == 0)
385            p_vout->p_sys->xvmc_crop_style = 2;
386         else if( strncmp( psz_value, "16-4", 4 ) == 0)
387            p_vout->p_sys->xvmc_crop_style = 3;
388         else
389            p_vout->p_sys->xvmc_crop_style = 0;
390         free( psz_value );
391     }
392     else
393         p_vout->p_sys->xvmc_crop_style = 0;
394
395     msg_Dbg(p_vout, "Deinterlace = %d", p_vout->p_sys->xvmc_deinterlace_method);
396     msg_Dbg(p_vout, "Crop = %d", p_vout->p_sys->xvmc_crop_style);
397
398     if( checkXvMCCap( p_vout ) == VLC_EGENERIC )
399     {
400         msg_Err( p_vout, "no XVMC capability found" );
401         Deactivate( p_this );
402         return VLC_EGENERIC;
403     }
404     subpicture_t sub_pic;
405     sub_pic.p_sys = NULL;
406     p_vout->p_sys->last_date = 0;
407 #endif
408
409 #ifdef HAVE_XSP
410     p_vout->p_sys->i_hw_scale = 1;
411 #endif
412
413 #ifdef HAVE_OSSO
414     p_vout->p_sys->i_backlight_on_counter = i_backlight_on_interval;
415     p_vout->p_sys->p_octx = osso_initialize( "vlc", VERSION, 0, NULL );
416     if ( p_vout->p_sys->p_octx == NULL ) {
417         msg_Err( p_vout, "Could not get osso context" );
418     } else {
419         msg_Dbg( p_vout, "Initialized osso context" );
420     }
421 #endif
422
423     /* Variable to indicate if the window should be on top of others */
424     /* Trigger a callback right now */
425     var_TriggerCallback( p_vout, "video-on-top" );
426
427     return VLC_SUCCESS;
428 }
429
430 /*****************************************************************************
431  * Deactivate: destroy X11 video thread output method
432  *****************************************************************************
433  * Terminate an output method created by Open
434  *****************************************************************************/
435 void Deactivate ( vlc_object_t *p_this )
436 {
437     vout_thread_t *p_vout = (vout_thread_t *)p_this;
438
439     /* Restore cursor if it was blanked */
440     if( !p_vout->p_sys->b_mouse_pointer_visible )
441     {
442         ToggleCursor( p_vout );
443     }
444
445 #ifdef MODULE_NAME_IS_x11
446     /* Destroy colormap */
447     if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
448     {
449         XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap );
450     }
451 #elif defined(MODULE_NAME_IS_xvideo)
452     XVideoReleasePort( p_vout, p_vout->p_sys->i_xvport );
453 #elif defined(MODULE_NAME_IS_xvmc)
454     if( p_vout->p_sys->xvmc_cap )
455     {
456         xvmc_context_writer_lock( &p_vout->p_sys->xvmc_lock );
457         xxmc_dispose_context( p_vout );
458         if( p_vout->p_sys->old_subpic )
459         {
460             xxmc_xvmc_free_subpicture( p_vout, p_vout->p_sys->old_subpic );
461             p_vout->p_sys->old_subpic = NULL;
462         }
463         if( p_vout->p_sys->new_subpic )
464         {
465             xxmc_xvmc_free_subpicture( p_vout, p_vout->p_sys->new_subpic );
466             p_vout->p_sys->new_subpic = NULL;
467         }
468         free( p_vout->p_sys->xvmc_cap );
469         xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
470     }
471 #endif
472
473 #ifdef HAVE_XSP
474     DisablePixelDoubling(p_vout);
475 #endif
476
477     DestroyCursor( p_vout );
478     EnableXScreenSaver( p_vout );
479     DestroyWindow( p_vout, &p_vout->p_sys->window );
480     XCloseDisplay( p_vout->p_sys->p_display );
481
482     /* Destroy structure */
483 #ifdef MODULE_NAME_IS_xvmc
484     free_context_lock( &p_vout->p_sys->xvmc_lock );
485 #endif
486
487 #ifdef HAVE_OSSO
488     if ( p_vout->p_sys->p_octx != NULL ) {
489         msg_Dbg( p_vout, "Deinitializing osso context" );
490         osso_deinitialize( p_vout->p_sys->p_octx );
491     }
492 #endif
493
494     free( p_vout->p_sys );
495 }
496
497 #ifdef MODULE_NAME_IS_xvmc
498
499 #define XINE_IMGFMT_YV12 (('2'<<24)|('1'<<16)|('V'<<8)|'Y')
500
501 /* called xlocked */
502 static int xvmc_check_yv12( Display *display, XvPortID port )
503 {
504     XvImageFormatValues *formatValues;
505     int                  formats;
506     int                  i;
507
508     formatValues = XvListImageFormats( display, port, &formats );
509
510     for( i = 0; i < formats; i++ )
511     {
512         if( ( formatValues[i].id == XINE_IMGFMT_YV12 ) &&
513             ( !( strncmp( formatValues[i].guid, "YV12", 4 ) ) ) )
514         {
515             XFree (formatValues);
516             return 0;
517         }
518     }
519
520     XFree (formatValues);
521     return 1;
522 }
523
524 static void xvmc_sync_surface( vout_thread_t *p_vout, XvMCSurface * srf )
525 {
526     XvMCSyncSurface( p_vout->p_sys->p_display, srf );
527 }
528
529 static void xvmc_update_XV_DOUBLE_BUFFER( vout_thread_t *p_vout )
530 {
531     Atom         atom;
532     int          xv_double_buffer;
533
534     xv_double_buffer = 1;
535
536     XLockDisplay( p_vout->p_sys->p_display );
537     atom = XInternAtom( p_vout->p_sys->p_display, "XV_DOUBLE_BUFFER", False );
538 #if 0
539     XvSetPortAttribute (p_vout->p_sys->p_display, p_vout->p_sys->i_xvport, atom, xv_double_buffer);
540 #endif
541     XvMCSetAttribute( p_vout->p_sys->p_display, &p_vout->p_sys->context, atom, xv_double_buffer );
542     XUnlockDisplay( p_vout->p_sys->p_display );
543
544     //xprintf(this->xine, XINE_VERBOSITY_DEBUG,
545     //    "video_out_xxmc: double buffering mode = %d\n", xv_double_buffer);
546 }
547
548 static void RenderVideo( vout_thread_t *p_vout, picture_t *p_pic )
549 {
550     vlc_xxmc_t *xxmc = NULL;
551
552     xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
553
554     xxmc = &p_pic->p_sys->xxmc_data;
555     if( (!xxmc->decoded ||
556         !xxmc_xvmc_surface_valid( p_vout, p_pic->p_sys->xvmc_surf )) )
557     {
558         xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
559         return;
560     }
561
562 #if 0
563     vlc_mutex_lock( &p_vout->lastsubtitle_lock );
564     if (p_vout->p_sys->p_last_subtitle != NULL)
565     {
566         if( p_vout->p_sys->p_last_subtitle_save != p_vout->p_sys->p_last_subtitle )
567         {
568             p_vout->p_sys->new_subpic =
569                 xxmc_xvmc_alloc_subpicture( p_vout, &p_vout->p_sys->context,
570                     p_vout->p_sys->xvmc_width,
571                     p_vout->p_sys->xvmc_height,
572                     p_vout->p_sys->xvmc_cap[p_vout->p_sys->xvmc_cur_cap].subPicType.id );
573
574             if (p_vout->p_sys->new_subpic)
575             {
576                 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
577                 XvMCClearSubpicture( p_vout->p_sys->p_display,
578                         p_vout->p_sys->new_subpic,
579                         0,
580                         0,
581                         p_vout->p_sys->xvmc_width,
582                         p_vout->p_sys->xvmc_height,
583                         0x00 );
584                 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
585                 clear_xx44_palette( &p_vout->p_sys->palette );
586
587                 if( sub_pic.p_sys == NULL )
588                 {
589                     sub_pic.p_sys = malloc( sizeof( picture_sys_t ) );
590                     if( sub_pic.p_sys != NULL )
591                     {
592                         sub_pic.p_sys->p_vout = p_vout;
593                         sub_pic.p_sys->xvmc_surf = NULL;
594                         sub_pic.p_sys->p_image = p_vout->p_sys->subImage;
595                     }
596                 }
597                 sub_pic.p_sys->p_image = p_vout->p_sys->subImage;
598                 sub_pic.p->p_pixels = sub_pic.p_sys->p_image->data;
599                 sub_pic.p->i_pitch = p_vout->output.i_width;
600
601                 memset( p_vout->p_sys->subImage->data, 0,
602                         (p_vout->p_sys->subImage->width * p_vout->p_sys->subImage->height) );
603
604                 if (p_vout->p_last_subtitle != NULL)
605                 {
606                     blend_xx44( p_vout->p_sys->subImage->data,
607                                 p_vout->p_last_subtitle,
608                                 p_vout->p_sys->subImage->width,
609                                 p_vout->p_sys->subImage->height,
610                                 p_vout->p_sys->subImage->width,
611                                 &p_vout->p_sys->palette,
612                                 (p_vout->p_sys->subImage->id == FOURCC_IA44) );
613                 }
614
615                 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
616                 XvMCCompositeSubpicture( p_vout->p_sys->p_display,
617                                          p_vout->p_sys->new_subpic,
618                                          p_vout->p_sys->subImage,
619                                          0, /* overlay->x */
620                                          0, /* overlay->y */
621                                          p_vout->output.i_width, /* overlay->width, */
622                                          p_vout->output.i_height, /* overlay->height */
623                                          0, /* overlay->x */
624                                          0 ); /*overlay->y */
625                 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
626                 if (p_vout->p_sys->old_subpic)
627                 {
628                     xxmc_xvmc_free_subpicture( p_vout,
629                                                p_vout->p_sys->old_subpic);
630                     p_vout->p_sys->old_subpic = NULL;
631                 }
632                 if (p_vout->p_sys->new_subpic)
633                 {
634                     p_vout->p_sys->old_subpic = p_vout->p_sys->new_subpic;
635                     p_vout->p_sys->new_subpic = NULL;
636                     xx44_to_xvmc_palette( &p_vout->p_sys->palette,
637                             p_vout->p_sys->xvmc_palette,
638                             0,
639                             p_vout->p_sys->old_subpic->num_palette_entries,
640                             p_vout->p_sys->old_subpic->entry_bytes,
641                             p_vout->p_sys->old_subpic->component_order );
642                     XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
643                     XvMCSetSubpicturePalette( p_vout->p_sys->p_display,
644                                               p_vout->p_sys->old_subpic,
645                                               p_vout->p_sys->xvmc_palette );
646                     XvMCFlushSubpicture( p_vout->p_sys->p_display,
647                                          p_vout->p_sys->old_subpic);
648                     XvMCSyncSubpicture( p_vout->p_sys->p_display,
649                                         p_vout->p_sys->old_subpic );
650                     XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
651                 }
652
653                 XVMCLOCKDISPLAY( p_vout->p_sys->p_display);
654                 if (p_vout->p_sys->xvmc_backend_subpic )
655                 {
656                     XvMCBlendSubpicture( p_vout->p_sys->p_display,
657                                          p_pic->p_sys->xvmc_surf,
658                                          p_vout->p_sys->old_subpic,
659                                          0,
660                                          0,
661                                          p_vout->p_sys->xvmc_width,
662                                          p_vout->p_sys->xvmc_height,
663                                          0,
664                                          0,
665                                          p_vout->p_sys->xvmc_width,
666                                          p_vout->p_sys->xvmc_height );
667                 }
668                 else
669                 {
670                     XvMCBlendSubpicture2( p_vout->p_sys->p_display,
671                                           p_pic->p_sys->xvmc_surf,
672                                           p_pic->p_sys->xvmc_surf,
673                                           p_vout->p_sys->old_subpic,
674                                           0,
675                                           0,
676                                           p_vout->p_sys->xvmc_width,
677                                           p_vout->p_sys->xvmc_height,
678                                           0,
679                                           0,
680                                           p_vout->p_sys->xvmc_width,
681                                           p_vout->p_sys->xvmc_height );
682                }
683                XVMCUNLOCKDISPLAY(p_vout->p_sys->p_display);
684             }
685         }
686         else
687         {
688             XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
689             if( p_vout->p_sys->xvmc_backend_subpic )
690             {
691                 XvMCBlendSubpicture( p_vout->p_sys->p_display,
692                                      p_pic->p_sys->xvmc_surf,
693                                      p_vout->p_sys->old_subpic,
694                                      0, 0,
695                                      p_vout->p_sys->xvmc_width,
696                                      p_vout->p_sys->xvmc_height,
697                                      0, 0,
698                                      p_vout->p_sys->xvmc_width,
699                                      p_vout->p_sys->xvmc_height );
700             }
701             else
702             {
703                 XvMCBlendSubpicture2( p_vout->p_sys->p_display,
704                                       p_pic->p_sys->xvmc_surf,
705                                       p_pic->p_sys->xvmc_surf,
706                                       p_vout->p_sys->old_subpic,
707                                       0, 0,
708                                       p_vout->p_sys->xvmc_width,
709                                       p_vout->p_sys->xvmc_height,
710                                       0, 0,
711                                       p_vout->p_sys->xvmc_width,
712                                       p_vout->p_sys->xvmc_height );
713             }
714             XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
715         }
716     }
717     p_vout->p_sys->p_last_subtitle_save = p_vout->p_last_subtitle;
718
719     vlc_mutex_unlock( &p_vout->lastsubtitle_lock );
720 #endif
721     xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
722 }
723 #endif
724
725 #ifdef HAVE_XSP
726 /*****************************************************************************
727  * EnablePixelDoubling: Enables pixel doubling
728  *****************************************************************************
729  * Checks if the double size image fits in current window, and enables pixel
730  * doubling accordingly. The i_hw_scale is the integer scaling factor.
731  *****************************************************************************/
732 static void EnablePixelDoubling( vout_thread_t *p_vout )
733 {
734     int i_hor_scale = ( p_vout->p_sys->window.i_width ) / p_vout->render.i_width;
735     int i_vert_scale =  ( p_vout->p_sys->window.i_height ) / p_vout->render.i_height;
736     if ( ( i_hor_scale > 1 ) && ( i_vert_scale > 1 ) ) {
737         p_vout->p_sys->i_hw_scale = 2;
738         msg_Dbg( p_vout, "Enabling pixel doubling, scaling factor %d", p_vout->p_sys->i_hw_scale );
739         XSPSetPixelDoubling( p_vout->p_sys->p_display, 0, 1 );
740     }
741 }
742
743 /*****************************************************************************
744  * DisablePixelDoubling: Disables pixel doubling
745  *****************************************************************************
746  * The scaling factor i_hw_scale is reset to the no-scaling value 1.
747  *****************************************************************************/
748 static void DisablePixelDoubling( vout_thread_t *p_vout )
749 {
750     if ( p_vout->p_sys->i_hw_scale > 1 ) {
751         msg_Dbg( p_vout, "Disabling pixel doubling" );
752         XSPSetPixelDoubling( p_vout->p_sys->p_display, 0, 0 );
753         p_vout->p_sys->i_hw_scale = 1;
754     }
755 }
756 #endif
757
758
759
760 /*****************************************************************************
761  * InitVideo: initialize X11 video thread output method
762  *****************************************************************************
763  * This function create the XImages needed by the output thread. It is called
764  * at the beginning of the thread, but also each time the window is resized.
765  *****************************************************************************/
766 static int InitVideo( vout_thread_t *p_vout )
767 {
768     unsigned int i_index = 0;
769     picture_t *p_pic;
770
771     I_OUTPUTPICTURES = 0;
772
773 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
774     /* Initialize the output structure; we already found an XVideo port,
775      * and the corresponding chroma we will be using. Since we can
776      * arbitrary scale, stick to the coordinates and aspect. */
777     p_vout->output.i_width  = p_vout->render.i_width;
778     p_vout->output.i_height = p_vout->render.i_height;
779     p_vout->output.i_aspect = p_vout->render.i_aspect;
780
781     p_vout->fmt_out = p_vout->fmt_in;
782     p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
783
784 #if XvVersion < 2 || ( XvVersion == 2 && XvRevision < 2 )
785     switch( p_vout->output.i_chroma )
786     {
787         case VLC_CODEC_RGB16:
788 #if defined( WORDS_BIGENDIAN )
789             p_vout->output.i_rmask = 0xf800;
790             p_vout->output.i_gmask = 0x07e0;
791             p_vout->output.i_bmask = 0x001f;
792 #else
793             p_vout->output.i_rmask = 0x001f;
794             p_vout->output.i_gmask = 0x07e0;
795             p_vout->output.i_bmask = 0xf800;
796 #endif
797             break;
798         case VLC_CODEC_RGB15:
799 #if defined( WORDS_BIGENDIAN )
800             p_vout->output.i_rmask = 0x7c00;
801             p_vout->output.i_gmask = 0x03e0;
802             p_vout->output.i_bmask = 0x001f;
803 #else
804             p_vout->output.i_rmask = 0x001f;
805             p_vout->output.i_gmask = 0x03e0;
806             p_vout->output.i_bmask = 0x7c00;
807 #endif
808             break;
809     }
810 #endif
811
812 #elif defined(MODULE_NAME_IS_x11)
813     /* Initialize the output structure: RGB with square pixels, whatever
814      * the input format is, since it's the only format we know */
815     switch( p_vout->p_sys->i_screen_depth )
816     {
817         case 8: /* FIXME: set the palette */
818             p_vout->output.i_chroma = VLC_CODEC_RGB8; break;
819         case 15:
820             p_vout->output.i_chroma = VLC_CODEC_RGB15; break;
821         case 16:
822             p_vout->output.i_chroma = VLC_CODEC_RGB16; break;
823         case 24:
824         case 32:
825             p_vout->output.i_chroma = VLC_CODEC_RGB32; break;
826         default:
827             msg_Err( p_vout, "unknown screen depth %i",
828                      p_vout->p_sys->i_screen_depth );
829             return VLC_SUCCESS;
830     }
831
832 #ifdef HAVE_XSP
833     vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width  / p_vout->p_sys->i_hw_scale,
834                        p_vout->p_sys->window.i_height  / p_vout->p_sys->i_hw_scale,
835                        &i_index, &i_index,
836                        &p_vout->fmt_out.i_visible_width,
837                        &p_vout->fmt_out.i_visible_height );
838 #else
839     vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
840                        p_vout->p_sys->window.i_height,
841                        &i_index, &i_index,
842                        &p_vout->fmt_out.i_visible_width,
843                        &p_vout->fmt_out.i_visible_height );
844 #endif
845
846     p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
847
848     p_vout->output.i_width = p_vout->fmt_out.i_width =
849         p_vout->fmt_out.i_visible_width * p_vout->fmt_in.i_width /
850         p_vout->fmt_in.i_visible_width;
851     p_vout->output.i_height = p_vout->fmt_out.i_height =
852         p_vout->fmt_out.i_visible_height * p_vout->fmt_in.i_height /
853         p_vout->fmt_in.i_visible_height;
854     p_vout->fmt_out.i_x_offset =
855         p_vout->fmt_out.i_visible_width * p_vout->fmt_in.i_x_offset /
856         p_vout->fmt_in.i_visible_width;
857     p_vout->fmt_out.i_y_offset =
858         p_vout->fmt_out.i_visible_height * p_vout->fmt_in.i_y_offset /
859         p_vout->fmt_in.i_visible_height;
860
861     p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_sar_den = 1;
862     p_vout->output.i_aspect = p_vout->fmt_out.i_aspect =
863         p_vout->fmt_out.i_width * VOUT_ASPECT_FACTOR /p_vout->fmt_out.i_height;
864
865     msg_Dbg( p_vout, "x11 image size %ix%i (%i,%i,%ix%i)",
866              p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
867              p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
868              p_vout->fmt_out.i_visible_width,
869              p_vout->fmt_out.i_visible_height );
870 #endif
871
872     /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
873     while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
874     {
875         p_pic = NULL;
876
877         /* Find an empty picture slot */
878         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
879         {
880           if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
881             {
882                 p_pic = p_vout->p_picture + i_index;
883                 break;
884             }
885         }
886
887         /* Allocate the picture */
888         if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
889         {
890             break;
891         }
892
893         p_pic->i_status = DESTROYED_PICTURE;
894         p_pic->i_type   = DIRECT_PICTURE;
895
896         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
897
898         I_OUTPUTPICTURES++;
899     }
900
901     if( p_vout->output.i_chroma == VLC_CODEC_YV12 )
902     {
903         /* U and V inverted compared to I420
904          * Fixme: this should be handled by the vout core */
905         p_vout->output.i_chroma = VLC_CODEC_I420;
906         p_vout->fmt_out.i_chroma = VLC_CODEC_I420;
907     }
908
909     return VLC_SUCCESS;
910 }
911
912 /*****************************************************************************
913  * DisplayVideo: displays previously rendered output
914  *****************************************************************************
915  * This function sends the currently rendered image to X11 server.
916  * (The Xv extension takes care of "double-buffering".)
917  *****************************************************************************/
918 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
919 {
920     unsigned int i_width, i_height, i_x, i_y;
921
922     vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
923                        p_vout->p_sys->window.i_height,
924                        &i_x, &i_y, &i_width, &i_height );
925
926 #ifdef MODULE_NAME_IS_xvmc
927     xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
928
929     vlc_xxmc_t *xxmc = &p_pic->p_sys->xxmc_data;
930     if( !xxmc->decoded ||
931         !xxmc_xvmc_surface_valid( p_vout, p_pic->p_sys->xvmc_surf ) )
932     {
933       msg_Dbg( p_vout, "DisplayVideo decoded=%d\tsurfacevalid=%d",
934                xxmc->decoded,
935                xxmc_xvmc_surface_valid( p_vout, p_pic->p_sys->xvmc_surf ) );
936       xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
937       return;
938     }
939
940     int src_width = p_vout->output.i_width;
941     int src_height = p_vout->output.i_height;
942     int src_x, src_y;
943
944     if( p_vout->p_sys->xvmc_crop_style == 1 )
945     {
946         src_x = 20;
947         src_y = 20;
948         src_width -= 40;
949         src_height -= 40;
950     }
951     else if( p_vout->p_sys->xvmc_crop_style == 2 )
952     {
953         src_x = 20;
954         src_y = 40;
955         src_width -= 40;
956         src_height -= 80;
957     }
958     else if( p_vout->p_sys->xvmc_crop_style == 3 )
959     {
960         src_x = 40;
961         src_y = 20;
962         src_width -= 80;
963         src_height -= 40;
964     }
965     else
966     {
967         src_x = 0;
968         src_y = 0;
969     }
970
971     int first_field;
972     if( p_vout->p_sys->xvmc_deinterlace_method > 0 )
973     {   /* BOB DEINTERLACE */
974         if( (p_pic->p_sys->nb_display == 0) ||
975             (p_vout->p_sys->xvmc_deinterlace_method == 1) )
976         {
977             first_field = (p_pic->b_top_field_first) ?
978                                 XVMC_BOTTOM_FIELD : XVMC_TOP_FIELD;
979         }
980         else
981         {
982             first_field = (p_pic->b_top_field_first) ?
983                                 XVMC_TOP_FIELD : XVMC_BOTTOM_FIELD;
984         }
985     }
986     else
987     {
988         first_field = XVMC_FRAME_PICTURE;
989      }
990
991     XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
992     XvMCFlushSurface( p_vout->p_sys->p_display, p_pic->p_sys->xvmc_surf );
993     /* XvMCSyncSurface(p_vout->p_sys->p_display, p_picture->p_sys->xvmc_surf); */
994     XvMCPutSurface( p_vout->p_sys->p_display,
995                     p_pic->p_sys->xvmc_surf,
996                     p_vout->p_sys->window.video_window,
997                     src_x,
998                     src_y,
999                     src_width,
1000                     src_height,
1001                     0 /*dest_x*/,
1002                     0 /*dest_y*/,
1003                     i_width,
1004                     i_height,
1005                     first_field);
1006
1007     XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1008     if( p_vout->p_sys->xvmc_deinterlace_method == 2 )
1009     {   /* BOB DEINTERLACE */
1010         if( p_pic->p_sys->nb_display == 0 )/* && ((t2-t1) < 15000)) */
1011         {
1012             mtime_t last_date = p_pic->date;
1013
1014             vlc_mutex_lock( &p_vout->picture_lock );
1015             if( !p_vout->p_sys->last_date )
1016             {
1017                 p_pic->date += 20000;
1018             }
1019             else
1020             {
1021                 p_pic->date = ((3 * p_pic->date -
1022                                     p_vout->p_sys->last_date) / 2 );
1023             }
1024             p_vout->p_sys->last_date = last_date;
1025             p_pic->b_force = 1;
1026             p_pic->p_sys->nb_display = 1;
1027             vlc_mutex_unlock( &p_vout->picture_lock );
1028         }
1029         else
1030         {
1031             p_pic->p_sys->nb_display = 0;
1032             p_pic->b_force = 0;
1033         }
1034     }
1035     xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1036 #endif
1037
1038 #ifdef HAVE_SYS_SHM_H
1039     if( p_vout->p_sys->i_shm_opcode )
1040     {
1041         /* Display rendered image using shared memory extension */
1042 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1043         XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
1044                        p_vout->p_sys->window.video_window,
1045                        p_vout->p_sys->window.gc, p_pic->p_sys->p_image,
1046                        p_vout->fmt_out.i_x_offset,
1047                        p_vout->fmt_out.i_y_offset,
1048                        p_vout->fmt_out.i_visible_width,
1049                        p_vout->fmt_out.i_visible_height,
1050                        0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height,
1051                        False /* Don't put True here or you'll waste your CPU */ );
1052 #else
1053         XShmPutImage( p_vout->p_sys->p_display,
1054                       p_vout->p_sys->window.video_window,
1055                       p_vout->p_sys->window.gc, p_pic->p_sys->p_image,
1056                       p_vout->fmt_out.i_x_offset,
1057                       p_vout->fmt_out.i_y_offset,
1058                       0 /*dest_x*/, 0 /*dest_y*/,
1059                       p_vout->fmt_out.i_visible_width,
1060                       p_vout->fmt_out.i_visible_height,
1061                       False /* Don't put True here ! */ );
1062 #endif
1063     }
1064     else
1065 #endif /* HAVE_SYS_SHM_H */
1066     {
1067         /* Use standard XPutImage -- this is gonna be slow ! */
1068 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1069         XvPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
1070                     p_vout->p_sys->window.video_window,
1071                     p_vout->p_sys->window.gc, p_pic->p_sys->p_image,
1072                     p_vout->fmt_out.i_x_offset,
1073                     p_vout->fmt_out.i_y_offset,
1074                     p_vout->fmt_out.i_visible_width,
1075                     p_vout->fmt_out.i_visible_height,
1076                     0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height );
1077 #else
1078         XPutImage( p_vout->p_sys->p_display,
1079                    p_vout->p_sys->window.video_window,
1080                    p_vout->p_sys->window.gc, p_pic->p_sys->p_image,
1081                    p_vout->fmt_out.i_x_offset,
1082                    p_vout->fmt_out.i_y_offset,
1083                    0 /*dest_x*/, 0 /*dest_y*/,
1084                    p_vout->fmt_out.i_visible_width,
1085                    p_vout->fmt_out.i_visible_height );
1086 #endif
1087     }
1088
1089     /* Make sure the command is sent now - do NOT use XFlush !*/
1090     XSync( p_vout->p_sys->p_display, False );
1091 }
1092
1093 /*****************************************************************************
1094  * ManageVideo: handle X11 events
1095  *****************************************************************************
1096  * This function should be called regularly by video output thread. It manages
1097  * X11 events and allows window resizing. It returns a non null value on
1098  * error.
1099  *****************************************************************************/
1100 static int ManageVideo( vout_thread_t *p_vout )
1101 {
1102     XEvent      xevent;                                         /* X11 event */
1103     vlc_value_t val;
1104
1105 #ifdef MODULE_NAME_IS_xvmc
1106     xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1107 #endif
1108
1109     /* Handle events from the owner window */
1110     while( XCheckWindowEvent( p_vout->p_sys->p_display,
1111                               p_vout->p_sys->window.owner_window->handle.xid,
1112                               StructureNotifyMask, &xevent ) == True )
1113     {
1114         /* ConfigureNotify event: prepare  */
1115         if( xevent.type == ConfigureNotify )
1116             /* Update dimensions */
1117             XResizeWindow( p_vout->p_sys->p_display,
1118                            p_vout->p_sys->window.base_window,
1119                            xevent.xconfigure.width,
1120                            xevent.xconfigure.height );
1121     }
1122
1123     /* Handle X11 events: ConfigureNotify events are parsed to know if the
1124      * output window's size changed, MapNotify and UnmapNotify to know if the
1125      * window is mapped (and if the display is useful), and ClientMessages
1126      * to intercept window destruction requests */
1127
1128     while( XCheckWindowEvent( p_vout->p_sys->p_display,
1129                               p_vout->p_sys->window.base_window,
1130                               StructureNotifyMask |
1131                               ButtonPressMask | ButtonReleaseMask |
1132                               PointerMotionMask | Button1MotionMask , &xevent )
1133            == True )
1134     {
1135         /* ConfigureNotify event: prepare  */
1136         if( xevent.type == ConfigureNotify )
1137         {
1138             if( (unsigned int)xevent.xconfigure.width
1139                    != p_vout->p_sys->window.i_width
1140               || (unsigned int)xevent.xconfigure.height
1141                     != p_vout->p_sys->window.i_height )
1142             {
1143                 /* Update dimensions */
1144                 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1145                 p_vout->p_sys->window.i_width = xevent.xconfigure.width;
1146                 p_vout->p_sys->window.i_height = xevent.xconfigure.height;
1147             }
1148         }
1149         /* Mouse click */
1150         else if( xevent.type == ButtonPress )
1151         {
1152             switch( ((XButtonEvent *)&xevent)->button )
1153             {
1154                 case Button1:
1155                     var_Get( p_vout, "mouse-button-down", &val );
1156                     val.i_int |= 1;
1157                     var_Set( p_vout, "mouse-button-down", val );
1158
1159                     var_SetBool( p_vout->p_libvlc, "intf-popupmenu", false );
1160
1161                     /* detect double-clicks */
1162                     if( ( ((XButtonEvent *)&xevent)->time -
1163                           p_vout->p_sys->i_time_button_last_pressed ) < 300 )
1164                     {
1165                         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
1166                     }
1167
1168                     p_vout->p_sys->i_time_button_last_pressed =
1169                         ((XButtonEvent *)&xevent)->time;
1170                     break;
1171                 case Button2:
1172                     var_Get( p_vout, "mouse-button-down", &val );
1173                     val.i_int |= 2;
1174                     var_Set( p_vout, "mouse-button-down", val );
1175                     break;
1176
1177                 case Button3:
1178                     var_Get( p_vout, "mouse-button-down", &val );
1179                     val.i_int |= 4;
1180                     var_Set( p_vout, "mouse-button-down", val );
1181                     var_SetBool( p_vout->p_libvlc, "intf-popupmenu", true );
1182                     break;
1183
1184                 case Button4:
1185                     var_Get( p_vout, "mouse-button-down", &val );
1186                     val.i_int |= 8;
1187                     var_Set( p_vout, "mouse-button-down", val );
1188                     break;
1189
1190                 case Button5:
1191                     var_Get( p_vout, "mouse-button-down", &val );
1192                     val.i_int |= 16;
1193                     var_Set( p_vout, "mouse-button-down", val );
1194                     break;
1195             }
1196         }
1197         /* Mouse release */
1198         else if( xevent.type == ButtonRelease )
1199         {
1200             switch( ((XButtonEvent *)&xevent)->button )
1201             {
1202                 case Button1:
1203                     {
1204                         var_Get( p_vout, "mouse-button-down", &val );
1205                         val.i_int &= ~1;
1206                         var_Set( p_vout, "mouse-button-down", val );
1207
1208                         var_SetBool( p_vout, "mouse-clicked", true );
1209                     }
1210                     break;
1211
1212                 case Button2:
1213                     {
1214                         var_Get( p_vout, "mouse-button-down", &val );
1215                         val.i_int &= ~2;
1216                         var_Set( p_vout, "mouse-button-down", val );
1217
1218                         var_Get( p_vout->p_libvlc, "intf-show", &val );
1219                         val.b_bool = !val.b_bool;
1220                         var_Set( p_vout->p_libvlc, "intf-show", val );
1221                     }
1222                     break;
1223
1224                 case Button3:
1225                     {
1226                         var_Get( p_vout, "mouse-button-down", &val );
1227                         val.i_int &= ~4;
1228                         var_Set( p_vout, "mouse-button-down", val );
1229
1230                     }
1231                     break;
1232
1233                 case Button4:
1234                     var_Get( p_vout, "mouse-button-down", &val );
1235                     val.i_int &= ~8;
1236                     var_Set( p_vout, "mouse-button-down", val );
1237                     break;
1238
1239                 case Button5:
1240                     var_Get( p_vout, "mouse-button-down", &val );
1241                     val.i_int &= ~16;
1242                     var_Set( p_vout, "mouse-button-down", val );
1243                     break;
1244
1245             }
1246         }
1247         /* Mouse move */
1248         else if( xevent.type == MotionNotify )
1249         {
1250             unsigned int i_width, i_height, i_x, i_y;
1251
1252             /* somewhat different use for vout_PlacePicture:
1253              * here the values are needed to give to mouse coordinates
1254              * in the original picture space */
1255             vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
1256                                p_vout->p_sys->window.i_height,
1257                                &i_x, &i_y, &i_width, &i_height );
1258
1259             /* Compute the x coordinate and check if the value is
1260                in [0,p_vout->fmt_in.i_visible_width] */
1261             val.i_int = ( xevent.xmotion.x - i_x ) *
1262                 p_vout->fmt_in.i_visible_width / i_width +
1263                 p_vout->fmt_in.i_x_offset;
1264
1265             if( (int)(xevent.xmotion.x - i_x) < 0 )
1266                 val.i_int = 0;
1267             else if( (unsigned int)val.i_int > p_vout->fmt_in.i_visible_width )
1268                 val.i_int = p_vout->fmt_in.i_visible_width;
1269
1270             var_Set( p_vout, "mouse-x", val );
1271
1272             /* compute the y coordinate and check if the value is
1273                in [0,p_vout->fmt_in.i_visible_height] */
1274             val.i_int = ( xevent.xmotion.y - i_y ) *
1275                 p_vout->fmt_in.i_visible_height / i_height +
1276                 p_vout->fmt_in.i_y_offset;
1277
1278             if( (int)(xevent.xmotion.y - i_y) < 0 )
1279                 val.i_int = 0;
1280             else if( (unsigned int)val.i_int > p_vout->fmt_in.i_visible_height )
1281                 val.i_int = p_vout->fmt_in.i_visible_height;
1282
1283             var_Set( p_vout, "mouse-y", val );
1284
1285             var_SetBool( p_vout, "mouse-moved", true );
1286
1287             p_vout->p_sys->i_time_mouse_last_moved = mdate();
1288             if( ! p_vout->p_sys->b_mouse_pointer_visible )
1289             {
1290                 ToggleCursor( p_vout );
1291             }
1292         }
1293         else if( xevent.type == ReparentNotify /* XXX: why do we get this? */
1294                   || xevent.type == MapNotify
1295                   || xevent.type == UnmapNotify )
1296         {
1297             /* Ignore these events */
1298         }
1299         else /* Other events */
1300         {
1301             msg_Warn( p_vout, "unhandled event %d received", xevent.type );
1302         }
1303     }
1304
1305     /* Handle events for video output sub-window */
1306     while( XCheckWindowEvent( p_vout->p_sys->p_display,
1307                               p_vout->p_sys->window.video_window,
1308                               ExposureMask, &xevent ) == True )
1309     {
1310         /* Window exposed (only handled if stream playback is paused) */
1311         if( xevent.type == Expose )
1312         {
1313             if( ((XExposeEvent *)&xevent)->count == 0 )
1314             {
1315                 /* (if this is the last a collection of expose events...) */
1316
1317 #if defined(MODULE_NAME_IS_xvideo)
1318                 x11_window_t *p_win = &p_vout->p_sys->window;
1319
1320                 /* Paint the colour key if needed */
1321                 if( p_vout->p_sys->b_paint_colourkey &&
1322                     xevent.xexpose.window == p_win->video_window )
1323                 {
1324                     XSetForeground( p_vout->p_sys->p_display,
1325                                     p_win->gc, p_vout->p_sys->i_colourkey );
1326                     XFillRectangle( p_vout->p_sys->p_display,
1327                                     p_win->video_window, p_win->gc, 0, 0,
1328                                     p_win->i_width, p_win->i_height );
1329                 }
1330 #endif
1331
1332 #if 0
1333                 if( p_vout->p_libvlc->p_input_bank->pp_input[0] != NULL )
1334                 {
1335                     if( PAUSE_S == p_vout->p_libvlc->p_input_bank->pp_input[0]
1336                                                    ->stream.control.i_status )
1337                     {
1338                         /* XVideoDisplay( p_vout )*/;
1339                     }
1340                 }
1341 #endif
1342             }
1343         }
1344     }
1345
1346     /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
1347      * are handled - according to the man pages, the format is always 32
1348      * in this case */
1349     while( XCheckTypedEvent( p_vout->p_sys->p_display,
1350                              ClientMessage, &xevent ) )
1351     {
1352         if( (xevent.xclient.message_type == p_vout->p_sys->window.wm_protocols)
1353                && ((Atom)xevent.xclient.data.l[0]
1354                      == p_vout->p_sys->window.wm_delete_window ) )
1355         {
1356             /* the user wants to close the window */
1357             playlist_t * p_playlist = pl_Hold( p_vout );
1358             if( p_playlist != NULL )
1359             {
1360                 playlist_Stop( p_playlist );
1361                 pl_Release( p_vout );
1362             }
1363         }
1364     }
1365
1366     /*
1367      * Fullscreen Change
1368      */
1369     if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
1370     {
1371         /* Update the object variable and trigger callback */
1372         var_SetBool( p_vout, "fullscreen", !p_vout->b_fullscreen );
1373
1374         ToggleFullScreen( p_vout );
1375         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
1376     }
1377
1378     /* autoscale toggle */
1379     if( p_vout->i_changes & VOUT_SCALE_CHANGE )
1380     {
1381         p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
1382
1383         p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
1384         p_vout->i_zoom = ZOOM_FP_FACTOR;
1385
1386         p_vout->i_changes |= VOUT_SIZE_CHANGE;
1387     }
1388
1389     /* scaling factor */
1390     if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
1391     {
1392         p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
1393
1394         p_vout->b_autoscale = false;
1395         p_vout->i_zoom =
1396             (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
1397
1398         p_vout->i_changes |= VOUT_SIZE_CHANGE;
1399     }
1400
1401     if( p_vout->i_changes & VOUT_CROP_CHANGE ||
1402         p_vout->i_changes & VOUT_ASPECT_CHANGE )
1403     {
1404         p_vout->i_changes &= ~VOUT_CROP_CHANGE;
1405         p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
1406
1407         p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
1408         p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
1409         p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
1410         p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
1411         p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
1412         p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
1413         p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
1414         p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
1415
1416         p_vout->i_changes |= VOUT_SIZE_CHANGE;
1417     }
1418
1419     /*
1420      * Size change
1421      *
1422      * (Needs to be placed after VOUT_FULLSREEN_CHANGE because we can activate
1423      *  the size flag inside the fullscreen routine)
1424      */
1425     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1426     {
1427         unsigned int i_width, i_height, i_x, i_y;
1428
1429 #ifdef MODULE_NAME_IS_x11
1430         /* We need to signal the vout thread about the size change because it
1431          * is doing the rescaling */
1432 #else
1433         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1434 #endif
1435
1436         vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
1437                            p_vout->p_sys->window.i_height,
1438                            &i_x, &i_y, &i_width, &i_height );
1439
1440         XMoveResizeWindow( p_vout->p_sys->p_display,
1441                            p_vout->p_sys->window.video_window,
1442                            i_x, i_y, i_width, i_height );
1443     }
1444
1445     /* cursor hiding depending on --vout-event option
1446      *      activated if:
1447      *            value = 1 (Fullsupport) (default value)
1448      *         or value = 2 (Fullscreen-Only) and condition met
1449      */
1450     bool b_vout_event = (   ( p_vout->p_sys->i_vout_event == 1 )
1451                          || ( p_vout->p_sys->i_vout_event == 2 && p_vout->b_fullscreen )
1452                         );
1453
1454     /* Autohide Cursour */
1455     if( mdate() - p_vout->p_sys->i_time_mouse_last_moved >
1456         p_vout->p_sys->i_mouse_hide_timeout )
1457     {
1458         /* Hide the mouse automatically */
1459         if( b_vout_event && p_vout->p_sys->b_mouse_pointer_visible )
1460         {
1461             ToggleCursor( p_vout );
1462         }
1463     }
1464
1465 #ifdef MODULE_NAME_IS_xvmc
1466     xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1467 #endif
1468
1469 #ifdef HAVE_OSSO
1470     if ( p_vout->p_sys->p_octx != NULL ) {
1471         if ( p_vout->p_sys->i_backlight_on_counter == i_backlight_on_interval ) {
1472             if ( osso_display_blanking_pause( p_vout->p_sys->p_octx ) != OSSO_OK ) {
1473                 msg_Err( p_vout, "Could not disable backlight blanking" );
1474         } else {
1475                 msg_Dbg( p_vout, "Backlight blanking disabled" );
1476             }
1477             p_vout->p_sys->i_backlight_on_counter = 0;
1478         } else {
1479             p_vout->p_sys->i_backlight_on_counter ++;
1480         }
1481     }
1482 #endif
1483     return 0;
1484 }
1485
1486 /*****************************************************************************
1487  * EndVideo: terminate X11 video thread output method
1488  *****************************************************************************
1489  * Destroy the X11 XImages created by Init. It is called at the end of
1490  * the thread, but also each time the window is resized.
1491  *****************************************************************************/
1492 static void EndVideo( vout_thread_t *p_vout )
1493 {
1494     int i_index;
1495
1496     /* Free the direct buffers we allocated */
1497     for( i_index = I_OUTPUTPICTURES ; i_index ; )
1498     {
1499         i_index--;
1500         FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
1501     }
1502 }
1503
1504 /* following functions are local */
1505
1506 /*****************************************************************************
1507  * CreateWindow: open and set-up X11 main window
1508  *****************************************************************************/
1509 static int CreateWindow( vout_thread_t *p_vout, x11_window_t *p_win )
1510 {
1511     XSizeHints              xsize_hints;
1512     XSetWindowAttributes    xwindow_attributes;
1513     XGCValues               xgcvalues;
1514     XEvent                  xevent;
1515
1516     bool              b_map_notify = false;
1517
1518     /* Prepare window manager hints and properties */
1519     p_win->wm_protocols =
1520              XInternAtom( p_vout->p_sys->p_display, "WM_PROTOCOLS", True );
1521     p_win->wm_delete_window =
1522              XInternAtom( p_vout->p_sys->p_display, "WM_DELETE_WINDOW", True );
1523
1524     /* Never have a 0-pixel-wide window */
1525     xsize_hints.min_width = 2;
1526     xsize_hints.min_height = 1;
1527
1528     /* Prepare window attributes */
1529     xwindow_attributes.backing_store = Always;       /* save the hidden part */
1530     xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
1531                                                      p_vout->p_sys->i_screen);
1532     xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
1533
1534     {
1535         vout_window_cfg_t wnd_cfg;
1536         memset( &wnd_cfg, 0, sizeof(wnd_cfg) );
1537         wnd_cfg.type   = VOUT_WINDOW_TYPE_XID;
1538         wnd_cfg.x      = p_win->i_x;
1539         wnd_cfg.y      = p_win->i_y;
1540         wnd_cfg.width  = p_win->i_width;
1541         wnd_cfg.height = p_win->i_height;
1542
1543         p_win->owner_window = vout_window_New( VLC_OBJECT(p_vout), NULL, &wnd_cfg );
1544         if( !p_win->owner_window )
1545             return VLC_EGENERIC;
1546         xsize_hints.base_width  = xsize_hints.width = p_win->i_width;
1547         xsize_hints.base_height = xsize_hints.height = p_win->i_height;
1548         xsize_hints.flags       = PSize | PMinSize;
1549
1550         if( p_win->i_x >=0 || p_win->i_y >= 0 )
1551         {
1552             xsize_hints.x = p_win->i_x;
1553             xsize_hints.y = p_win->i_y;
1554             xsize_hints.flags |= PPosition;
1555         }
1556
1557         /* Select events we are interested in. */
1558         XSelectInput( p_vout->p_sys->p_display,
1559                       p_win->owner_window->handle.xid, StructureNotifyMask );
1560
1561         /* Get the parent window's geometry information */
1562         XGetGeometry( p_vout->p_sys->p_display,
1563                       p_win->owner_window->handle.xid,
1564                       &(Window){ 0 }, &(int){ 0 }, &(int){ 0 },
1565                       &p_win->i_width,
1566                       &p_win->i_height,
1567                       &(unsigned){ 0 }, &(unsigned){ 0 } );
1568
1569         /* From man XSelectInput: only one client at a time can select a
1570          * ButtonPress event, so we need to open a new window anyway. */
1571         p_win->base_window =
1572             XCreateWindow( p_vout->p_sys->p_display,
1573                            p_win->owner_window->handle.xid,
1574                            0, 0,
1575                            p_win->i_width, p_win->i_height,
1576                            0,
1577                            0, CopyFromParent, 0,
1578                            CWBackingStore | CWBackPixel | CWEventMask,
1579                            &xwindow_attributes );
1580     }
1581
1582     if( (p_win->wm_protocols == None)        /* use WM_DELETE_WINDOW */
1583         || (p_win->wm_delete_window == None)
1584         || !XSetWMProtocols( p_vout->p_sys->p_display, p_win->base_window,
1585                              &p_win->wm_delete_window, 1 ) )
1586     {
1587         /* WM_DELETE_WINDOW is not supported by window manager */
1588         msg_Warn( p_vout, "missing or bad window manager" );
1589     }
1590
1591     /* Creation of a graphic context that doesn't generate a GraphicsExpose
1592      * event when using functions like XCopyArea */
1593     xgcvalues.graphics_exposures = False;
1594     p_win->gc = XCreateGC( p_vout->p_sys->p_display,
1595                            p_win->base_window,
1596                            GCGraphicsExposures, &xgcvalues );
1597
1598     /* Wait till the window is mapped */
1599     XMapWindow( p_vout->p_sys->p_display, p_win->base_window );
1600     do
1601     {
1602         XWindowEvent( p_vout->p_sys->p_display, p_win->base_window,
1603                       SubstructureNotifyMask | StructureNotifyMask, &xevent);
1604         if( (xevent.type == MapNotify)
1605                  && (xevent.xmap.window == p_win->base_window) )
1606         {
1607             b_map_notify = true;
1608         }
1609         else if( (xevent.type == ConfigureNotify)
1610                  && (xevent.xconfigure.window == p_win->base_window) )
1611         {
1612             p_win->i_width = xevent.xconfigure.width;
1613             p_win->i_height = xevent.xconfigure.height;
1614         }
1615     } while( !b_map_notify );
1616
1617     /* key and mouse events handling depending on --vout-event option
1618      *      activated if:
1619      *            value = 1 (Fullsupport) (default value)
1620      *         or value = 2 (Fullscreen-Only) and condition met
1621      */
1622     bool b_vout_event = (   ( p_vout->p_sys->i_vout_event == 1 )
1623                          || ( p_vout->p_sys->i_vout_event == 2 && p_vout->b_fullscreen )
1624                         );
1625     if ( b_vout_event )
1626         XSelectInput( p_vout->p_sys->p_display, p_win->base_window,
1627                       StructureNotifyMask |
1628                       ButtonPressMask | ButtonReleaseMask |
1629                       PointerMotionMask );
1630
1631 #ifdef MODULE_NAME_IS_x11
1632     if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
1633     {
1634         /* Allocate a new palette */
1635         p_vout->p_sys->colormap =
1636             XCreateColormap( p_vout->p_sys->p_display,
1637                              DefaultRootWindow( p_vout->p_sys->p_display ),
1638                              DefaultVisual( p_vout->p_sys->p_display,
1639                                             p_vout->p_sys->i_screen ),
1640                              AllocAll );
1641
1642         xwindow_attributes.colormap = p_vout->p_sys->colormap;
1643         XChangeWindowAttributes( p_vout->p_sys->p_display, p_win->base_window,
1644                                  CWColormap, &xwindow_attributes );
1645     }
1646 #endif
1647
1648     /* Create video output sub-window. */
1649     p_win->video_window =  XCreateSimpleWindow(
1650                                       p_vout->p_sys->p_display,
1651                                       p_win->base_window, 0, 0,
1652                                       p_win->i_width, p_win->i_height,
1653                                       0,
1654                                       BlackPixel( p_vout->p_sys->p_display,
1655                                                   p_vout->p_sys->i_screen ),
1656                                       WhitePixel( p_vout->p_sys->p_display,
1657                                                   p_vout->p_sys->i_screen ) );
1658
1659     XSetWindowBackground( p_vout->p_sys->p_display, p_win->video_window,
1660                           BlackPixel( p_vout->p_sys->p_display,
1661                                       p_vout->p_sys->i_screen ) );
1662
1663     XMapWindow( p_vout->p_sys->p_display, p_win->video_window );
1664     XSelectInput( p_vout->p_sys->p_display, p_win->video_window,
1665                   ExposureMask );
1666
1667     /* make sure the video window will be centered in the next ManageVideo() */
1668     p_vout->i_changes |= VOUT_SIZE_CHANGE;
1669
1670     /* If the cursor was formerly blank than blank it again */
1671     if( !p_vout->p_sys->b_mouse_pointer_visible )
1672     {
1673         ToggleCursor( p_vout );
1674         ToggleCursor( p_vout );
1675     }
1676
1677     /* Do NOT use XFlush here ! */
1678     XSync( p_vout->p_sys->p_display, False );
1679
1680     return VLC_SUCCESS;
1681 }
1682
1683 /*****************************************************************************
1684  * DestroyWindow: destroy the window
1685  *****************************************************************************
1686  *
1687  *****************************************************************************/
1688 static void DestroyWindow( vout_thread_t *p_vout, x11_window_t *p_win )
1689 {
1690     /* Do NOT use XFlush here ! */
1691     XSync( p_vout->p_sys->p_display, False );
1692
1693     if( p_win->video_window != None )
1694         XDestroyWindow( p_vout->p_sys->p_display, p_win->video_window );
1695
1696     XFreeGC( p_vout->p_sys->p_display, p_win->gc );
1697
1698     XUnmapWindow( p_vout->p_sys->p_display, p_win->base_window );
1699     XDestroyWindow( p_vout->p_sys->p_display, p_win->base_window );
1700
1701     /* make sure base window is destroyed before proceeding further */
1702     bool b_destroy_notify = false;
1703     do
1704     {
1705         XEvent      xevent;
1706         XWindowEvent( p_vout->p_sys->p_display, p_win->base_window,
1707                       SubstructureNotifyMask | StructureNotifyMask, &xevent);
1708         if( (xevent.type == DestroyNotify)
1709                  && (xevent.xmap.window == p_win->base_window) )
1710         {
1711             b_destroy_notify = true;
1712         }
1713     } while( !b_destroy_notify );
1714
1715     vout_window_Delete( p_win->owner_window );
1716 }
1717
1718 /*****************************************************************************
1719  * NewPicture: allocate a picture
1720  *****************************************************************************
1721  * Returns 0 on success, -1 otherwise
1722  *****************************************************************************/
1723 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
1724 {
1725 #ifndef MODULE_NAME_IS_glx
1726
1727 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1728     int i_plane;
1729 #endif
1730
1731     /* We know the chroma, allocate a buffer which will be used
1732      * directly by the decoder */
1733     p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
1734
1735     if( p_pic->p_sys == NULL )
1736     {
1737         return -1;
1738     }
1739
1740 #ifdef MODULE_NAME_IS_xvmc
1741     p_pic->p_sys->p_vout = p_vout;
1742     p_pic->p_sys->xvmc_surf = NULL;
1743     p_pic->p_sys->xxmc_data.decoded = 0;
1744     p_pic->p_sys->xxmc_data.proc_xxmc_update_frame = xxmc_do_update_frame;
1745     //    p_pic->p_accel_data = &p_pic->p_sys->xxmc_data;
1746     p_pic->p_sys->nb_display = 0;
1747 #endif
1748
1749     /* Fill in picture_t fields */
1750     if( picture_Setup( p_pic, p_vout->output.i_chroma,
1751                        p_vout->output.i_width, p_vout->output.i_height,
1752                        p_vout->output.i_aspect ) )
1753         return -1;
1754
1755 #ifdef HAVE_SYS_SHM_H
1756     if( p_vout->p_sys->i_shm_opcode )
1757     {
1758         /* Create image using XShm extension */
1759         p_pic->p_sys->p_image =
1760             CreateShmImage( p_vout, p_vout->p_sys->p_display,
1761 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1762                             p_vout->p_sys->i_xvport,
1763                             VLC2X11_FOURCC(p_vout->output.i_chroma),
1764 #else
1765                             p_vout->p_sys->p_visual,
1766                             p_vout->p_sys->i_screen_depth,
1767 #endif
1768                             &p_pic->p_sys->shminfo,
1769                             p_vout->output.i_width, p_vout->output.i_height );
1770     }
1771
1772     if( !p_vout->p_sys->i_shm_opcode || !p_pic->p_sys->p_image )
1773 #endif /* HAVE_SYS_SHM_H */
1774     {
1775         /* Create image without XShm extension */
1776         p_pic->p_sys->p_image =
1777             CreateImage( p_vout, p_vout->p_sys->p_display,
1778 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1779                          p_vout->p_sys->i_xvport,
1780                          VLC2X11_FOURCC(p_vout->output.i_chroma),
1781                          p_pic->format.i_bits_per_pixel,
1782 #else
1783                          p_vout->p_sys->p_visual,
1784                          p_vout->p_sys->i_screen_depth,
1785                          p_vout->p_sys->i_bytes_per_pixel,
1786 #endif
1787                          p_vout->output.i_width, p_vout->output.i_height );
1788
1789 #ifdef HAVE_SYS_SHM_H
1790         if( p_pic->p_sys->p_image && p_vout->p_sys->i_shm_opcode )
1791         {
1792             msg_Warn( p_vout, "couldn't create SHM image, disabling SHM" );
1793             p_vout->p_sys->i_shm_opcode = 0;
1794         }
1795 #endif /* HAVE_SYS_SHM_H */
1796     }
1797
1798     if( p_pic->p_sys->p_image == NULL )
1799     {
1800         free( p_pic->p_sys );
1801         return -1;
1802     }
1803
1804     switch( p_vout->output.i_chroma )
1805     {
1806 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
1807         case VLC_CODEC_I420:
1808         case VLC_CODEC_YV12:
1809         case VLC_CODEC_Y211:
1810         case VLC_CODEC_YUYV:
1811         case VLC_CODEC_UYVY:
1812         case VLC_CODEC_RGB15:
1813         case VLC_CODEC_RGB16:
1814         case VLC_CODEC_RGB24: /* Fixme: pixel pitch == 4 ? */
1815         case VLC_CODEC_RGB32:
1816
1817             for( i_plane = 0; i_plane < p_pic->p_sys->p_image->num_planes;
1818                  i_plane++ )
1819             {
1820                 p_pic->p[i_plane].p_pixels = (uint8_t*)p_pic->p_sys->p_image->data
1821                     + p_pic->p_sys->p_image->offsets[i_plane];
1822                 p_pic->p[i_plane].i_pitch =
1823                     p_pic->p_sys->p_image->pitches[i_plane];
1824             }
1825             if( p_vout->output.i_chroma == VLC_CODEC_YV12 )
1826             {
1827                 /* U and V inverted compared to I420
1828                  * Fixme: this should be handled by the vout core */
1829                 p_pic->U_PIXELS = (uint8_t*)p_pic->p_sys->p_image->data
1830                     + p_pic->p_sys->p_image->offsets[2];
1831                 p_pic->V_PIXELS = (uint8_t*)p_pic->p_sys->p_image->data
1832                     + p_pic->p_sys->p_image->offsets[1];
1833             }
1834
1835             break;
1836
1837 #else
1838         case VLC_CODEC_RGB8:
1839         case VLC_CODEC_RGB16:
1840         case VLC_CODEC_RGB15:
1841         case VLC_CODEC_RGB24:
1842         case VLC_CODEC_RGB32:
1843
1844             p_pic->p->i_lines = p_pic->p_sys->p_image->height;
1845             p_pic->p->i_visible_lines = p_pic->p_sys->p_image->height;
1846             p_pic->p->p_pixels = (uint8_t*)p_pic->p_sys->p_image->data
1847                                   + p_pic->p_sys->p_image->xoffset;
1848             p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line;
1849
1850             /* p_pic->p->i_pixel_pitch = 4 for RV24 but this should be set
1851              * properly by picture_Setup() */
1852             p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch
1853                                          * p_pic->p_sys->p_image->width;
1854             break;
1855 #endif
1856
1857         default:
1858             /* Unknown chroma, tell the guy to get lost */
1859             IMAGE_FREE( p_pic->p_sys->p_image );
1860             free( p_pic->p_sys );
1861             msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
1862                      p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
1863             p_pic->i_planes = 0;
1864             return -1;
1865     }
1866 #else
1867
1868     VLC_UNUSED(p_vout); VLC_UNUSED(p_pic);
1869
1870 #endif /* !MODULE_NAME_IS_glx */
1871
1872     return 0;
1873 }
1874
1875 /*****************************************************************************
1876  * FreePicture: destroy a picture allocated with NewPicture
1877  *****************************************************************************
1878  * Destroy XImage AND associated data. If using Shm, detach shared memory
1879  * segment from server and process, then free it. The XDestroyImage manpage
1880  * says that both the image structure _and_ the data pointed to by the
1881  * image structure are freed, so no need to free p_image->data.
1882  *****************************************************************************/
1883 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1884 {
1885     /* The order of operations is correct */
1886 #ifdef HAVE_SYS_SHM_H
1887     if( p_vout->p_sys->i_shm_opcode )
1888     {
1889         XShmDetach( p_vout->p_sys->p_display, &p_pic->p_sys->shminfo );
1890         IMAGE_FREE( p_pic->p_sys->p_image );
1891
1892         shmctl( p_pic->p_sys->shminfo.shmid, IPC_RMID, 0 );
1893         if( shmdt( p_pic->p_sys->shminfo.shmaddr ) )
1894         {
1895             msg_Err( p_vout, "cannot detach shared memory (%m)" );
1896         }
1897     }
1898     else
1899 #endif
1900     {
1901         IMAGE_FREE( p_pic->p_sys->p_image );
1902     }
1903
1904 #ifdef MODULE_NAME_IS_xvmc
1905     if( p_pic->p_sys->xvmc_surf != NULL )
1906     {
1907         xxmc_xvmc_free_surface(p_vout , p_pic->p_sys->xvmc_surf);
1908         p_pic->p_sys->xvmc_surf = NULL;
1909     }
1910 #endif
1911
1912     /* Do NOT use XFlush here ! */
1913     XSync( p_vout->p_sys->p_display, False );
1914
1915     free( p_pic->p_sys );
1916 }
1917
1918 /*****************************************************************************
1919  * ToggleFullScreen: Enable or disable full screen mode
1920  *****************************************************************************
1921  * This function will switch between fullscreen and window mode.
1922  *****************************************************************************/
1923 static void ToggleFullScreen ( vout_thread_t *p_vout )
1924 {
1925     p_vout->b_fullscreen = !p_vout->b_fullscreen;
1926     vout_window_SetFullScreen( p_vout->p_sys->window.owner_window,
1927                                p_vout->b_fullscreen );
1928
1929 #ifdef HAVE_XSP
1930     if( p_vout->b_fullscreen )
1931         EnablePixelDoubling( p_vout );
1932     else
1933         DisablePixelDoubling( p_vout );
1934 #endif
1935 }
1936
1937 /*****************************************************************************
1938  * EnableXScreenSaver: enable screen saver
1939  *****************************************************************************
1940  * This function enables the screen saver on a display after it has been
1941  * disabled by XDisableScreenSaver.
1942  * FIXME: what happens if multiple vlc sessions are running at the same
1943  *        time ???
1944  *****************************************************************************/
1945 static void EnableXScreenSaver( vout_thread_t *p_vout )
1946 {
1947 #ifdef DPMSINFO_IN_DPMS_H
1948     int dummy;
1949 #endif
1950
1951     if( p_vout->p_sys->i_ss_timeout )
1952     {
1953         XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1954                          p_vout->p_sys->i_ss_interval,
1955                          p_vout->p_sys->i_ss_blanking,
1956                          p_vout->p_sys->i_ss_exposure );
1957     }
1958
1959     /* Restore DPMS settings */
1960 #ifdef DPMSINFO_IN_DPMS_H
1961     if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1962     {
1963         if( p_vout->p_sys->b_ss_dpms )
1964         {
1965             DPMSEnable( p_vout->p_sys->p_display );
1966         }
1967     }
1968 #endif
1969 }
1970
1971 /*****************************************************************************
1972  * DisableXScreenSaver: disable screen saver
1973  *****************************************************************************
1974  * See XEnableXScreenSaver
1975  *****************************************************************************/
1976 static void DisableXScreenSaver( vout_thread_t *p_vout )
1977 {
1978 #ifdef DPMSINFO_IN_DPMS_H
1979     int dummy;
1980 #endif
1981
1982     /* Save screen saver information */
1983     XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1984                      &p_vout->p_sys->i_ss_interval,
1985                      &p_vout->p_sys->i_ss_blanking,
1986                      &p_vout->p_sys->i_ss_exposure );
1987
1988     /* Disable screen saver */
1989     if( p_vout->p_sys->i_ss_timeout )
1990     {
1991         XSetScreenSaver( p_vout->p_sys->p_display, 0,
1992                          p_vout->p_sys->i_ss_interval,
1993                          p_vout->p_sys->i_ss_blanking,
1994                          p_vout->p_sys->i_ss_exposure );
1995     }
1996
1997     /* Disable DPMS */
1998 #ifdef DPMSINFO_IN_DPMS_H
1999     if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
2000     {
2001         CARD16 unused;
2002         /* Save DPMS current state */
2003         DPMSInfo( p_vout->p_sys->p_display, &unused,
2004                   &p_vout->p_sys->b_ss_dpms );
2005         DPMSDisable( p_vout->p_sys->p_display );
2006    }
2007 #endif
2008 }
2009
2010 /*****************************************************************************
2011  * CreateCursor: create a blank mouse pointer
2012  *****************************************************************************/
2013 static void CreateCursor( vout_thread_t *p_vout )
2014 {
2015     XColor cursor_color;
2016
2017     p_vout->p_sys->cursor_pixmap =
2018         XCreatePixmap( p_vout->p_sys->p_display,
2019                        DefaultRootWindow( p_vout->p_sys->p_display ),
2020                        1, 1, 1 );
2021
2022     XParseColor( p_vout->p_sys->p_display,
2023                  XCreateColormap( p_vout->p_sys->p_display,
2024                                   DefaultRootWindow(
2025                                                     p_vout->p_sys->p_display ),
2026                                   DefaultVisual(
2027                                                 p_vout->p_sys->p_display,
2028                                                 p_vout->p_sys->i_screen ),
2029                                   AllocNone ),
2030                  "black", &cursor_color );
2031
2032     p_vout->p_sys->blank_cursor =
2033         XCreatePixmapCursor( p_vout->p_sys->p_display,
2034                              p_vout->p_sys->cursor_pixmap,
2035                              p_vout->p_sys->cursor_pixmap,
2036                              &cursor_color, &cursor_color, 1, 1 );
2037 }
2038
2039 /*****************************************************************************
2040  * DestroyCursor: destroy the blank mouse pointer
2041  *****************************************************************************/
2042 static void DestroyCursor( vout_thread_t *p_vout )
2043 {
2044     XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
2045 }
2046
2047 /*****************************************************************************
2048  * ToggleCursor: hide or show the mouse pointer
2049  *****************************************************************************
2050  * This function hides the X pointer if it is visible by setting the pointer
2051  * sprite to a blank one. To show it again, we disable the sprite.
2052  *****************************************************************************/
2053 static void ToggleCursor( vout_thread_t *p_vout )
2054 {
2055     if( p_vout->p_sys->b_mouse_pointer_visible )
2056     {
2057         XDefineCursor( p_vout->p_sys->p_display,
2058                        p_vout->p_sys->window.base_window,
2059                        p_vout->p_sys->blank_cursor );
2060         p_vout->p_sys->b_mouse_pointer_visible = 0;
2061     }
2062     else
2063     {
2064         XUndefineCursor( p_vout->p_sys->p_display,
2065                          p_vout->p_sys->window.base_window );
2066         p_vout->p_sys->b_mouse_pointer_visible = 1;
2067     }
2068 }
2069
2070 #if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
2071 /*****************************************************************************
2072  * XVideoGetPort: get YUV12 port
2073  *****************************************************************************/
2074 static int XVideoGetPort( vout_thread_t *p_vout,
2075                           vlc_fourcc_t i_chroma, picture_heap_t *p_heap )
2076 {
2077     XvAdaptorInfo *p_adaptor;
2078     unsigned int i;
2079     unsigned int i_adaptor, i_num_adaptors;
2080     int i_requested_adaptor;
2081     int i_selected_port;
2082
2083     switch( XvQueryExtension( p_vout->p_sys->p_display, &i, &i, &i, &i, &i ) )
2084     {
2085         case Success:
2086             break;
2087
2088         case XvBadExtension:
2089             msg_Warn( p_vout, "XvBadExtension" );
2090             return -1;
2091
2092         case XvBadAlloc:
2093             msg_Warn( p_vout, "XvBadAlloc" );
2094             return -1;
2095
2096         default:
2097             msg_Warn( p_vout, "XvQueryExtension failed" );
2098             return -1;
2099     }
2100
2101     switch( XvQueryAdaptors( p_vout->p_sys->p_display,
2102                              DefaultRootWindow( p_vout->p_sys->p_display ),
2103                              &i_num_adaptors, &p_adaptor ) )
2104     {
2105         case Success:
2106             break;
2107
2108         case XvBadExtension:
2109             msg_Warn( p_vout, "XvBadExtension for XvQueryAdaptors" );
2110             return -1;
2111
2112         case XvBadAlloc:
2113             msg_Warn( p_vout, "XvBadAlloc for XvQueryAdaptors" );
2114             return -1;
2115
2116         default:
2117             msg_Warn( p_vout, "XvQueryAdaptors failed" );
2118             return -1;
2119     }
2120
2121     i_selected_port = -1;
2122 #ifdef MODULE_NAME_IS_xvmc
2123     i_requested_adaptor = config_GetInt( p_vout, "xvmc-adaptor" );
2124 #else
2125     i_requested_adaptor = config_GetInt( p_vout, "xvideo-adaptor" );
2126 #endif
2127     for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
2128     {
2129         XvImageFormatValues *p_formats;
2130         int i_format, i_num_formats;
2131         int i_port;
2132
2133         /* If we requested an adaptor and it's not this one, we aren't
2134          * interested */
2135         if( i_requested_adaptor != -1 && ((int)i_adaptor != i_requested_adaptor) )
2136         {
2137             continue;
2138         }
2139
2140         /* If the adaptor doesn't have the required properties, skip it */
2141         if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
2142             !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
2143         {
2144             continue;
2145         }
2146
2147         /* Check that adaptor supports our requested format... */
2148         p_formats = XvListImageFormats( p_vout->p_sys->p_display,
2149                                         p_adaptor[i_adaptor].base_id,
2150                                         &i_num_formats );
2151
2152         for( i_format = 0;
2153              i_format < i_num_formats && ( i_selected_port == -1 );
2154              i_format++ )
2155         {
2156             XvAttribute     *p_attr;
2157             int             i_attr, i_num_attributes;
2158             Atom            autopaint = None, colorkey = None;
2159
2160             /* If this is not the format we want, or at least a
2161              * similar one, forget it */
2162             if( !vout_ChromaCmp( p_formats[ i_format ].id, i_chroma ) )
2163             {
2164                 continue;
2165             }
2166
2167             /* Look for the first available port supporting this format */
2168             for( i_port = p_adaptor[i_adaptor].base_id;
2169                  ( i_port < (int)(p_adaptor[i_adaptor].base_id
2170                                    + p_adaptor[i_adaptor].num_ports) )
2171                    && ( i_selected_port == -1 );
2172                  i_port++ )
2173             {
2174                 if( XvGrabPort( p_vout->p_sys->p_display, i_port, CurrentTime )
2175                      == Success )
2176                 {
2177                     i_selected_port = i_port;
2178                     p_heap->i_chroma = p_formats[ i_format ].id;
2179 #if XvVersion > 2 || ( XvVersion == 2 && XvRevision >= 2 )
2180                     p_heap->i_rmask = p_formats[ i_format ].red_mask;
2181                     p_heap->i_gmask = p_formats[ i_format ].green_mask;
2182                     p_heap->i_bmask = p_formats[ i_format ].blue_mask;
2183 #endif
2184                 }
2185             }
2186
2187             /* If no free port was found, forget it */
2188             if( i_selected_port == -1 )
2189             {
2190                 continue;
2191             }
2192
2193             /* If we found a port, print information about it */
2194             msg_Dbg( p_vout, "adaptor %i, port %i, format 0x%x (%4.4s) %s",
2195                      i_adaptor, i_selected_port, p_formats[ i_format ].id,
2196                      (char *)&p_formats[ i_format ].id,
2197                      ( p_formats[ i_format ].format == XvPacked ) ?
2198                          "packed" : "planar" );
2199
2200             /* Use XV_AUTOPAINT_COLORKEY if supported, otherwise we will
2201              * manually paint the colour key */
2202             p_attr = XvQueryPortAttributes( p_vout->p_sys->p_display,
2203                                             i_selected_port,
2204                                             &i_num_attributes );
2205
2206             for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
2207             {
2208                 if( !strcmp( p_attr[i_attr].name, "XV_AUTOPAINT_COLORKEY" ) )
2209                 {
2210                     autopaint = XInternAtom( p_vout->p_sys->p_display,
2211                                              "XV_AUTOPAINT_COLORKEY", False );
2212                     XvSetPortAttribute( p_vout->p_sys->p_display,
2213                                         i_selected_port, autopaint, 1 );
2214                 }
2215                 if( !strcmp( p_attr[i_attr].name, "XV_COLORKEY" ) )
2216                 {
2217                     /* Find out the default colour key */
2218                     colorkey = XInternAtom( p_vout->p_sys->p_display,
2219                                             "XV_COLORKEY", False );
2220                     XvGetPortAttribute( p_vout->p_sys->p_display,
2221                                         i_selected_port, colorkey,
2222                                         &p_vout->p_sys->i_colourkey );
2223                 }
2224             }
2225             p_vout->p_sys->b_paint_colourkey =
2226                 autopaint == None && colorkey != None;
2227
2228             if( p_attr != NULL )
2229             {
2230                 XFree( p_attr );
2231             }
2232         }
2233
2234         if( p_formats != NULL )
2235         {
2236             XFree( p_formats );
2237         }
2238
2239     }
2240
2241     if( i_num_adaptors > 0 )
2242     {
2243         XvFreeAdaptorInfo( p_adaptor );
2244     }
2245
2246     if( i_selected_port == -1 )
2247     {
2248         int i_chroma_tmp = X112VLC_FOURCC( i_chroma );
2249         if( i_requested_adaptor == -1 )
2250         {
2251             msg_Warn( p_vout, "no free XVideo port found for format "
2252                       "0x%.8x (%4.4s)", i_chroma_tmp, (char*)&i_chroma_tmp );
2253         }
2254         else
2255         {
2256             msg_Warn( p_vout, "XVideo adaptor %i does not have a free "
2257                       "XVideo port for format 0x%.8x (%4.4s)",
2258                       i_requested_adaptor, i_chroma_tmp, (char*)&i_chroma_tmp );
2259         }
2260     }
2261
2262     return i_selected_port;
2263 }
2264
2265 /*****************************************************************************
2266  * XVideoReleasePort: release YUV12 port
2267  *****************************************************************************/
2268 static void XVideoReleasePort( vout_thread_t *p_vout, int i_port )
2269 {
2270     XvUngrabPort( p_vout->p_sys->p_display, i_port, CurrentTime );
2271 }
2272 #endif
2273
2274 /*****************************************************************************
2275  * InitDisplay: open and initialize X11 device
2276  *****************************************************************************
2277  * Create a window according to video output given size, and set other
2278  * properties according to the display properties.
2279  *****************************************************************************/
2280 static int InitDisplay( vout_thread_t *p_vout )
2281 {
2282 #ifdef MODULE_NAME_IS_x11
2283     XPixmapFormatValues *       p_formats;                 /* pixmap formats */
2284     XVisualInfo *               p_xvisual;            /* visuals information */
2285     XVisualInfo                 xvisual_template;         /* visual template */
2286     int                         i_count, i;                    /* array size */
2287 #endif
2288
2289 #ifdef HAVE_SYS_SHM_H
2290     p_vout->p_sys->i_shm_opcode = 0;
2291
2292     if( config_GetInt( p_vout, MODULE_STRING "-shm" ) > 0 )
2293     {
2294         int major, evt, err;
2295
2296         if( XQueryExtension( p_vout->p_sys->p_display, "MIT-SHM", &major,
2297                              &evt, &err )
2298          && XShmQueryExtension( p_vout->p_sys->p_display ) )
2299             p_vout->p_sys->i_shm_opcode = major;
2300
2301         if( p_vout->p_sys->i_shm_opcode )
2302         {
2303             int minor;
2304             Bool pixmaps;
2305
2306             XShmQueryVersion( p_vout->p_sys->p_display, &major, &minor,
2307                               &pixmaps );
2308             msg_Dbg( p_vout, "XShm video extension v%d.%d "
2309                      "(with%s pixmaps, opcode: %d)",
2310                      major, minor, pixmaps ? "" : "out",
2311                      p_vout->p_sys->i_shm_opcode );
2312         }
2313         else
2314             msg_Warn( p_vout, "XShm video extension not available" );
2315     }
2316     else
2317         msg_Dbg( p_vout, "XShm video extension disabled" );
2318 #endif
2319
2320 #ifdef MODULE_NAME_IS_xvideo
2321     /* XXX The brightness and contrast values should be read from environment
2322      * XXX variables... */
2323 #if 0
2324     XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
2325     XVideoSetAttribute( p_vout, "XV_CONTRAST",   0.5 );
2326 #endif
2327 #endif
2328
2329 #ifdef MODULE_NAME_IS_x11
2330     /* Initialize structure */
2331     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
2332
2333     /* Get screen depth */
2334     p_vout->p_sys->i_screen_depth = XDefaultDepth( p_vout->p_sys->p_display,
2335                                                    p_vout->p_sys->i_screen );
2336     switch( p_vout->p_sys->i_screen_depth )
2337     {
2338     case 8:
2339         /*
2340          * Screen depth is 8bpp. Use PseudoColor visual with private colormap.
2341          */
2342         xvisual_template.screen =   p_vout->p_sys->i_screen;
2343         xvisual_template.class =    DirectColor;
2344         p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
2345                                     VisualScreenMask | VisualClassMask,
2346                                     &xvisual_template, &i_count );
2347         if( p_xvisual == NULL )
2348         {
2349             msg_Err( p_vout, "no PseudoColor visual available" );
2350             return VLC_EGENERIC;
2351         }
2352         p_vout->p_sys->i_bytes_per_pixel = 1;
2353         p_vout->output.pf_setpalette = SetPalette;
2354         break;
2355     case 15:
2356     case 16:
2357     case 24:
2358     default:
2359         /*
2360          * Screen depth is higher than 8bpp. TrueColor visual is used.
2361          */
2362         xvisual_template.screen =   p_vout->p_sys->i_screen;
2363         xvisual_template.class =    TrueColor;
2364 /* In some cases, we get a truecolor class adaptor that has a different
2365    color depth. So try to get a real true color one first */
2366         xvisual_template.depth =    p_vout->p_sys->i_screen_depth;
2367
2368         p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
2369                                     VisualScreenMask | VisualClassMask |
2370                                     VisualDepthMask,
2371                                     &xvisual_template, &i_count );
2372         if( p_xvisual == NULL )
2373         {
2374             msg_Warn( p_vout, "No screen matching the required color depth" );
2375             p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
2376                                     VisualScreenMask | VisualClassMask,
2377                                     &xvisual_template, &i_count );
2378             if( p_xvisual == NULL )
2379             {
2380
2381                 msg_Err( p_vout, "no TrueColor visual available" );
2382                 return VLC_EGENERIC;
2383             }
2384         }
2385
2386         p_vout->output.i_rmask = p_xvisual->red_mask;
2387         p_vout->output.i_gmask = p_xvisual->green_mask;
2388         p_vout->output.i_bmask = p_xvisual->blue_mask;
2389
2390         /* There is no difference yet between 3 and 4 Bpp. The only way
2391          * to find the actual number of bytes per pixel is to list supported
2392          * pixmap formats. */
2393         p_formats = XListPixmapFormats( p_vout->p_sys->p_display, &i_count );
2394         p_vout->p_sys->i_bytes_per_pixel = 0;
2395
2396         for( i = 0; i < i_count; i++ )
2397         {
2398             /* Under XFree4.0, the list contains pixmap formats available
2399              * through all video depths ; so we have to check against current
2400              * depth. */
2401             if( p_formats[i].depth == (int)p_vout->p_sys->i_screen_depth )
2402             {
2403                 if( p_formats[i].bits_per_pixel / 8
2404                         > (int)p_vout->p_sys->i_bytes_per_pixel )
2405                 {
2406                     p_vout->p_sys->i_bytes_per_pixel =
2407                         p_formats[i].bits_per_pixel / 8;
2408                 }
2409             }
2410         }
2411         if( p_formats ) XFree( p_formats );
2412
2413         break;
2414     }
2415     p_vout->p_sys->p_visual = p_xvisual->visual;
2416     XFree( p_xvisual );
2417 #endif
2418
2419     return VLC_SUCCESS;
2420 }
2421
2422 #ifndef MODULE_NAME_IS_glx
2423
2424 #ifdef HAVE_SYS_SHM_H
2425 /*****************************************************************************
2426  * CreateShmImage: create an XImage or XvImage using shared memory extension
2427  *****************************************************************************
2428  * Prepare an XImage or XvImage for display function.
2429  * The order of the operations respects the recommandations of the mit-shm
2430  * document by J.Corbet and K.Packard. Most of the parameters were copied from
2431  * there. See http://ftp.xfree86.org/pub/XFree86/4.0/doc/mit-shm.TXT
2432  *****************************************************************************/
2433 IMAGE_TYPE * CreateShmImage( vout_thread_t *p_vout,
2434                                     Display* p_display, EXTRA_ARGS_SHM,
2435                                     int i_width, int i_height )
2436 {
2437     IMAGE_TYPE *p_image;
2438     Status result;
2439
2440     /* Create XImage / XvImage */
2441 #ifdef MODULE_NAME_IS_xvideo
2442     p_image = XvShmCreateImage( p_display, i_xvport, i_chroma, 0,
2443                                 i_width, i_height, p_shm );
2444 #elif defined(MODULE_NAME_IS_xvmc)
2445     p_image = XvShmCreateImage( p_display, i_xvport, i_chroma, 0,
2446                                 i_width, i_height, p_shm );
2447 #else
2448     p_image = XShmCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
2449                                p_shm, i_width, i_height );
2450 #endif
2451     if( p_image == NULL )
2452     {
2453         msg_Err( p_vout, "image creation failed" );
2454         return NULL;
2455     }
2456
2457     /* For too big image, the buffer returned is sometimes too small, prevent
2458      * VLC to segfault because of it
2459      * FIXME is it normal ? Is there a way to detect it
2460      * before (XvQueryBestSize did not) ? */
2461     if( p_image->width < i_width || p_image->height < i_height )
2462     {
2463         msg_Err( p_vout, "cannot allocate shared image data with the right size "
2464                          "(%dx%d instead of %dx%d)",
2465                          p_image->width, p_image->height,
2466                          i_width, i_height );
2467         IMAGE_FREE( p_image );
2468         return NULL;
2469     }
2470
2471     /* Allocate shared memory segment. */
2472     p_shm->shmid = shmget( IPC_PRIVATE, DATA_SIZE(p_image), IPC_CREAT | 0600 );
2473     if( p_shm->shmid < 0 )
2474     {
2475         msg_Err( p_vout, "cannot allocate shared image data (%m)" );
2476         IMAGE_FREE( p_image );
2477         return NULL;
2478     }
2479
2480     /* Attach shared memory segment to process (read/write) */
2481     p_shm->shmaddr = p_image->data = shmat( p_shm->shmid, 0, 0 );
2482     if(! p_shm->shmaddr )
2483     {
2484         msg_Err( p_vout, "cannot attach shared memory (%m)" );
2485         IMAGE_FREE( p_image );
2486         shmctl( p_shm->shmid, IPC_RMID, 0 );
2487         return NULL;
2488     }
2489
2490     /* Read-only data. We won't be using XShmGetImage */
2491     p_shm->readOnly = True;
2492
2493     /* Attach shared memory segment to X server */
2494     XSynchronize( p_display, True );
2495     i_shm_major = p_vout->p_sys->i_shm_opcode;
2496     result = XShmAttach( p_display, p_shm );
2497     if( result == False || !i_shm_major )
2498     {
2499         msg_Err( p_vout, "cannot attach shared memory to X server" );
2500         IMAGE_FREE( p_image );
2501         shmctl( p_shm->shmid, IPC_RMID, 0 );
2502         shmdt( p_shm->shmaddr );
2503         return NULL;
2504     }
2505     XSynchronize( p_display, False );
2506
2507     /* Send image to X server. This instruction is required, since having
2508      * built a Shm XImage and not using it causes an error on XCloseDisplay,
2509      * and remember NOT to use XFlush ! */
2510     XSync( p_display, False );
2511
2512 #if 0
2513     /* Mark the shm segment to be removed when there are no more
2514      * attachements, so it is automatic on process exit or after shmdt */
2515     shmctl( p_shm->shmid, IPC_RMID, 0 );
2516 #endif
2517
2518     return p_image;
2519 }
2520 #endif
2521
2522 /*****************************************************************************
2523  * CreateImage: create an XImage or XvImage
2524  *****************************************************************************
2525  * Create a simple image used as a buffer.
2526  *****************************************************************************/
2527 static IMAGE_TYPE * CreateImage( vout_thread_t *p_vout,
2528                                  Display *p_display, EXTRA_ARGS,
2529                                  int i_width, int i_height )
2530 {
2531     uint8_t *    p_data;                          /* image data storage zone */
2532     IMAGE_TYPE *p_image;
2533 #ifdef MODULE_NAME_IS_x11
2534     int         i_quantum;                     /* XImage quantum (see below) */
2535     int         i_bytes_per_line;
2536 #endif
2537
2538     /* Allocate memory for image */
2539 #ifdef MODULE_NAME_IS_xvideo
2540     p_data = malloc( i_width * i_height * i_bits_per_pixel / 8 );
2541 #elif defined(MODULE_NAME_IS_x11)
2542     i_bytes_per_line = i_width * i_bytes_per_pixel;
2543     p_data = malloc( i_bytes_per_line * i_height );
2544 #endif
2545     if( !p_data )
2546         return NULL;
2547
2548 #ifdef MODULE_NAME_IS_x11
2549     /* Optimize the quantum of a scanline regarding its size - the quantum is
2550        a diviser of the number of bits between the start of two scanlines. */
2551     if( i_bytes_per_line & 0xf )
2552     {
2553         i_quantum = 0x8;
2554     }
2555     else if( i_bytes_per_line & 0x10 )
2556     {
2557         i_quantum = 0x10;
2558     }
2559     else
2560     {
2561         i_quantum = 0x20;
2562     }
2563 #endif
2564
2565     /* Create XImage. p_data will be automatically freed */
2566 #ifdef MODULE_NAME_IS_xvideo
2567     p_image = XvCreateImage( p_display, i_xvport, i_chroma,
2568                              (char *)p_data, i_width, i_height );
2569 #elif defined(MODULE_NAME_IS_x11)
2570     p_image = XCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
2571                             (char *)p_data, i_width, i_height, i_quantum, 0 );
2572 #endif
2573     if( p_image == NULL )
2574     {
2575         msg_Err( p_vout, "XCreateImage() failed" );
2576         free( p_data );
2577         return NULL;
2578     }
2579
2580     return p_image;
2581 }
2582
2583 #endif
2584 /*****************************************************************************
2585  * X11ErrorHandler: replace error handler so we can intercept some of them
2586  *****************************************************************************/
2587 static int X11ErrorHandler( Display * display, XErrorEvent * event )
2588 {
2589     char txt[1024];
2590
2591     XGetErrorText( display, event->error_code, txt, sizeof( txt ) );
2592     fprintf( stderr,
2593              "[????????] x11 video output error: X11 request %u.%u failed "
2594               "with error code %u:\n %s\n",
2595              event->request_code, event->minor_code, event->error_code, txt );
2596
2597     switch( event->request_code )
2598     {
2599     case X_SetInputFocus:
2600         /* Ignore errors on XSetInputFocus()
2601          * (they happen when a window is not yet mapped) */
2602         return 0;
2603     }
2604
2605 #ifdef HAVE_SYS_SHM_H
2606     if( event->request_code == i_shm_major ) /* MIT-SHM */
2607     {
2608         fprintf( stderr,
2609                  "[????????] x11 video output notice:"
2610                  " buggy X11 server claims shared memory\n"
2611                  "[????????] x11 video output notice:"
2612                  " support though it does not work (OpenSSH?)\n" );
2613         return i_shm_major = 0;
2614     }
2615 #endif
2616
2617 #ifndef HAVE_OSSO
2618     XSetErrorHandler(NULL);
2619     return (XSetErrorHandler(X11ErrorHandler))( display, event );
2620 #else
2621     /* Work-around Maemo Xvideo bug */
2622     return 0;
2623 #endif
2624 }
2625
2626 #ifdef MODULE_NAME_IS_x11
2627 /*****************************************************************************
2628  * SetPalette: sets an 8 bpp palette
2629  *****************************************************************************
2630  * This function sets the palette given as an argument. It does not return
2631  * anything, but could later send information on which colors it was unable
2632  * to set.
2633  *****************************************************************************/
2634 static void SetPalette( vout_thread_t *p_vout,
2635                         uint16_t *red, uint16_t *green, uint16_t *blue )
2636 {
2637     int i;
2638     XColor p_colors[255];
2639
2640     /* allocate palette */
2641     for( i = 0; i < 255; i++ )
2642     {
2643         /* kludge: colors are indexed reversely because color 255 seems
2644          * to be reserved for black even if we try to set it to white */
2645         p_colors[ i ].pixel = 255 - i;
2646         p_colors[ i ].pad   = 0;
2647         p_colors[ i ].flags = DoRed | DoGreen | DoBlue;
2648         p_colors[ i ].red   = red[ 255 - i ];
2649         p_colors[ i ].blue  = blue[ 255 - i ];
2650         p_colors[ i ].green = green[ 255 - i ];
2651     }
2652
2653     XStoreColors( p_vout->p_sys->p_display,
2654                   p_vout->p_sys->colormap, p_colors, 255 );
2655 }
2656 #endif
2657
2658 /*****************************************************************************
2659  * Control: control facility for the vout
2660  *****************************************************************************/
2661 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
2662 {
2663     unsigned int i_width, i_height;
2664
2665     switch( i_query )
2666     {
2667         case VOUT_SET_SIZE:
2668             i_width  = va_arg( args, unsigned int );
2669             i_height = va_arg( args, unsigned int );
2670             if( !i_width ) i_width = p_vout->i_window_width;
2671             if( !i_height ) i_height = p_vout->i_window_height;
2672
2673             return vout_window_SetSize( p_vout->p_sys->window.owner_window,
2674                                         i_width, i_height);
2675
2676         case VOUT_SET_STAY_ON_TOP:
2677             return vout_window_SetOnTop( p_vout->p_sys->window.owner_window,
2678                                          va_arg( args, int ) );
2679
2680        default:
2681             return VLC_EGENERIC;
2682     }
2683 }