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