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