xcommon.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:85k
源码类别:

多媒体

开发平台:

MultiPlatform

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