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