]> git.sesse.net Git - vlc/blobdiff - plugins/x11/vout_xvideo.c
* Mandatory step for video output IV and the audio output quality
[vlc] / plugins / x11 / vout_xvideo.c
index 197a9216ce76c7b8e47a7d9d44ffcdda8ca00724..6cd0ef1ecd2876017fbb8cfb5cb4092982ec1a73 100644 (file)
@@ -2,11 +2,12 @@
  * vout_xvideo.c: Xvideo video output display method
  *****************************************************************************
  * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
- * $Id: vout_xvideo.c,v 1.4 2001/04/08 16:57:47 sam Exp $
+ * $Id: vout_xvideo.c,v 1.13 2001/05/01 04:18:18 sam Exp $
  *
  * Authors: Shane Harper <shanegh@optusnet.com.au>
  *          Vincent Seguin <seguin@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
+ *          David Kennedy <dkennedy@tinytoad.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include "interface.h"
 #include "intf_msg.h"
 
+#include "netutils.h"                                 /* network_ChannelJoin */
+
 #include "main.h"
 
+#include "stream_control.h"                 /* needed by input_ext-intf.h... */
+#include "input_ext-intf.h"
+
+
+#define GUID_YUV12_PLANAR 0x32315659
+
+
 /*****************************************************************************
  * vout_sys_t: video output X11 method descriptor
  *****************************************************************************
  * This structure is part of the video output thread descriptor.
- * It describes the X11 specific properties of an output thread. X11 video
- * output is performed through regular resizable windows. Windows can be
- * dynamically resized to adapt to the size of the streams.
+ * It describes the XVideo specific properties of an output thread.
  *****************************************************************************/
 typedef struct vout_sys_s
 {
@@ -86,31 +94,57 @@ typedef struct vout_sys_s
     int                 i_screen;                           /* screen number */
     Window              window;                               /* root window */
     GC                  gc;              /* graphic context instance handler */
+    Window              yuv_window;   /* sub-window for displaying yuv video
+                                                                        data */
+    GC                  yuv_gc;
     int                 xv_port;
 
     /* Display buffers and shared memory information */
-    /* Note: only 1 buffer (I don't know why the X11 plugin had 2.) */
+    /* Note: only 1 buffer... Xv ext does double buffering. */
     XvImage *           p_xvimage;
+    int                 i_image_width;
+    int                 i_image_height;
+                                /* i_image_width & i_image_height reflect the
+                                 * size of the XvImage. They are used by
+                                 * vout_Display() to check if the image to be
+                                 * displayed can use the current XvImage. */
     XShmSegmentInfo     shm_info;       /* shared memory zone information */
 
     /* X11 generic properties */
     Atom                wm_protocols;
     Atom                wm_delete_window;
 
-    int                 i_width;                     /* width of main window */
-    int                 i_height;                   /* height of main window */
+    int                 i_window_width;              /* width of main window */
+    int                 i_window_height;            /* height of main window */
+
 
     /* Screen saver properties */
     int                 i_ss_timeout;                             /* timeout */
     int                 i_ss_interval;           /* interval between changes */
     int                 i_ss_blanking;                      /* blanking mode */
     int                 i_ss_exposure;                      /* exposure mode */
-
+    
     /* Mouse pointer properties */
-    boolean_t           b_mouse;         /* is the mouse pointer displayed ? */
+    boolean_t           b_mouse_pointer_visible;
+    mtime_t             i_time_mouse_last_moved; /* used to auto-hide pointer*/
+
+    /* Displaying fullscreen */
+    boolean_t           b_fullscreen;
 
 } vout_sys_t;
 
+/* Fullscreen needs to be able to hide the wm decorations */
+#define MWM_HINTS_DECORATIONS   (1L << 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+typedef struct mwmhints_s
+{
+    u32 flags;
+    u32 functions;
+    u32 decorations;
+    s32 input_mode;
+    u32 status;
+} mwmhints_t;
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -124,20 +158,25 @@ static void vout_Display   ( vout_thread_t * );
 static void vout_SetPalette( vout_thread_t *, u16 *, u16 *, u16 *, u16 * );
 
 static int  XVideoCreateWindow       ( vout_thread_t * );
-static int  XVideoCreateShmImage     ( vout_thread_t *, XvImage **,
-                                       XShmSegmentInfo *p_shm_info );
+static void XVideoDestroyWindow      ( vout_thread_t *p_vout );
+static int  XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout );
+static int  XVideoCreateShmImage     ( Display* dpy, int xv_port,
+                                       XvImage **pp_xvimage,
+                                       XShmSegmentInfo *p_shm_info,
+                                       int i_width, int i_height );
 static void XVideoDestroyShmImage    ( vout_thread_t *, XvImage *,
                                        XShmSegmentInfo * );
-static void XVideoTogglePointer      ( vout_thread_t * );
+static void XVideoSetMousePointer    ( const vout_thread_t * );
 static void XVideoEnableScreenSaver  ( vout_thread_t * );
 static void XVideoDisableScreenSaver ( vout_thread_t * );
-static void XVideoSetAttribute       ( vout_thread_t *, char *, float );
+/*static void XVideoSetAttribute       ( vout_thread_t *, char *, float );*/
 
 static int  XVideoCheckForXv         ( Display * );
 static int  XVideoGetPort            ( Display * );
 static void XVideoOutputCoords       ( const picture_t *, const boolean_t,
                                        const int, const int,
                                        int *, int *, int *, int * );
+static void XVideoDisplay            ( vout_thread_t * );
 
 /*****************************************************************************
  * Functions exported as capabilities. They are declared as static so that
@@ -168,15 +207,15 @@ static int vout_Probe( probedata_t *p_data )
         return( 999 );
     }
 
-    return( 90 );
+    return( 60 );
 }
 
 /*****************************************************************************
  * vout_Create: allocate XVideo video thread output method
  *****************************************************************************
- * This function allocate and initialize a X11 vout method. It uses some of the
- * vout properties to choose the window size, and change them according to the
- * actual properties of the display.
+ * This function allocate and initialize a XVideo vout method. It uses some of
+ * the vout properties to choose the window size, and change them according to
+ * the actual properties of the display.
  *****************************************************************************/
 static int vout_Create( vout_thread_t *p_vout )
 {
@@ -202,6 +241,9 @@ static int vout_Create( vout_thread_t *p_vout )
     }
     p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
 
+    p_vout->p_sys->b_fullscreen
+        = main_GetIntVariable( VOUT_FULLSCREEN_VAR, VOUT_FULLSCREEN_DEFAULT );
+    
     if( !XVideoCheckForXv( p_vout->p_sys->p_display ) )
     {
         intf_ErrMsg( "vout error: no XVideo extension" );
@@ -222,13 +264,16 @@ static int vout_Create( vout_thread_t *p_vout )
 
     if( (p_vout->p_sys->xv_port = XVideoGetPort( p_vout->p_sys->p_display ))<0 )
         return 1;
+    intf_DbgMsg( "Using xv port %d" , p_vout->p_sys->xv_port );
 
+#if 0
     /* XXX The brightness and contrast values should be read from environment
      * XXX variables... */
     XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
     XVideoSetAttribute( p_vout, "XV_CONTRAST",   0.5 );
+#endif
 
-    p_vout->p_sys->b_mouse = 1;
+    p_vout->p_sys->b_mouse_pointer_visible = 1;
 
     /* Disable screen saver and return */
     XVideoDisableScreenSaver( p_vout );
@@ -238,56 +283,24 @@ static int vout_Create( vout_thread_t *p_vout )
 
 /*****************************************************************************
  * vout_Init: initialize XVideo video thread output method
- *****************************************************************************
- * This function creates the XvImage needed by the output thread. It is called
- * at the beginning of the thread, but also each time the window is resized.
  *****************************************************************************/
 static int vout_Init( vout_thread_t *p_vout )
 {
-    int i_err;
-
 #ifdef SYS_DARWIN1_3
     /* FIXME : As of 2001-03-16, XFree4 for MacOS X does not support Xshm. */
     p_vout->p_sys->b_shm = 0;
 #endif
-
-    /* Create XvImage using XShm extension */
-    i_err = XVideoCreateShmImage( p_vout, &p_vout->p_sys->p_xvimage,
-                                  &p_vout->p_sys->shm_info );
-    if( i_err )
-    {
-        intf_Msg( "vout: XShm video extension unavailable" );
-        /* p_vout->p_sys->b_shm = 0; */
-    }
     p_vout->b_need_render = 0;
+    p_vout->p_sys->i_image_width = p_vout->p_sys->i_image_height = 0;
 
-    /* Set bytes per line and initialize buffers */
-    p_vout->i_bytes_per_line =
-        (p_vout->p_sys->p_xvimage->data_size) /
-        (p_vout->p_sys->p_xvimage->height);
-
-    /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage[0]->data,
-     *                          p_vout->p_sys->p_xvimage[1]->data ); */
-    p_vout->p_buffer[0].i_pic_x =         0;
-    p_vout->p_buffer[0].i_pic_y =         0;
-    p_vout->p_buffer[0].i_pic_width =     0;
-    p_vout->p_buffer[0].i_pic_height =    0;
-
-    /* The first area covers all the screen */
-    p_vout->p_buffer[0].i_areas =           1;
-    p_vout->p_buffer[0].pi_area_begin[0] =  0;
-    p_vout->p_buffer[0].pi_area_end[0] =    p_vout->i_height - 1;
-
-    /* Set addresses */
-    p_vout->p_buffer[0].p_data = p_vout->p_sys->p_xvimage->data;
     return( 0 );
 }
 
 /*****************************************************************************
  * vout_End: terminate XVideo video thread output method
  *****************************************************************************
- * Destroy the XVideo xImages created by vout_Init. It is called at the end of
- * the thread, but also each time the window is resized.
+ * Destroy the XvImage. It is called at the end of the thread, but also each
+ * time the image is resized.
  *****************************************************************************/
 static void vout_End( vout_thread_t *p_vout )
 {
@@ -298,18 +311,12 @@ static void vout_End( vout_thread_t *p_vout )
 /*****************************************************************************
  * vout_Destroy: destroy XVideo video thread output method
  *****************************************************************************
- * Terminate an output method created by vout_CreateOutputMethod
+ * Terminate an output method created by vout_Create
  *****************************************************************************/
 static void vout_Destroy( vout_thread_t *p_vout )
 {
-    /* Enable screen saver */
     XVideoEnableScreenSaver( p_vout );
-
-    /* Destroy window */
-    XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
-    XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
-    XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
-
+    XVideoDestroyWindow( p_vout );
     XCloseDisplay( p_vout->p_sys->p_display );
 
     /* Destroy structure */
@@ -329,30 +336,30 @@ static void vout_Destroy( vout_thread_t *p_vout )
 static int vout_Manage( vout_thread_t *p_vout )
 {
     XEvent      xevent;                                         /* X11 event */
-    boolean_t   b_resized;                        /* window has been resized */
+    boolean_t   b_toggle_fullscreen;               /* user wants full-screen */
     char        i_key;                                    /* ISO Latin-1 key */
+    KeySym      x_key_symbol;
+
+    b_toggle_fullscreen = 0;
 
     /* Handle X11 events: ConfigureNotify events are parsed to know if the
      * output window's size changed, MapNotify and UnmapNotify to know if the
      * window is mapped (and if the display is useful), and ClientMessages
      * to intercept window destruction requests */
-    b_resized = 0;
     while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
                               StructureNotifyMask | KeyPressMask |
-                              ButtonPressMask | ButtonReleaseMask, &xevent )
+                              ButtonPressMask | ButtonReleaseMask | 
+                              PointerMotionMask, &xevent )
            == True )
     {
         /* ConfigureNotify event: prepare  */
         if( (xevent.type == ConfigureNotify)
-            && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
-                || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
+            /*&& ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
+                || (xevent.xconfigure.height != p_vout->p_sys->i_window_height))*/ )
         {
             /* Update dimensions */
-/* XXX XXX
-            b_resized = 1;
-            p_vout->p_sys->i_width = xevent.xconfigure.width;
-            p_vout->p_sys->i_height = xevent.xconfigure.height;
-   XXX XXX */
+            p_vout->p_sys->i_window_width = xevent.xconfigure.width;
+            p_vout->p_sys->i_window_height = xevent.xconfigure.height;
         }
         /* MapNotify event: change window status and disable screen saver */
         else if( xevent.type == MapNotify)
@@ -375,16 +382,76 @@ static int vout_Manage( vout_thread_t *p_vout )
         /* Keyboard event */
         else if( xevent.type == KeyPress )
         {
-            if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
+            /* We may have keys like F1 trough F12, ESC ... */
+            x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
+                                             xevent.xkey.keycode, 0 );
+            switch( x_key_symbol )
             {
-                /* FIXME: handle stuff here */
-                switch( i_key )
-                {
-                case 'q':
-                    /* FIXME: need locking ! */
-                    p_main->p_intf->b_die = 1;
-                    break;
-                }
+                 case XK_Escape:
+                     p_main->p_intf->b_die = 1;
+                     break;
+                 case XK_Menu:
+                     p_main->p_intf->b_menu_change = 1;
+                     break;
+                 default:
+                     /* "Normal Keys"
+                      * The reason why I use this instead of XK_0 is that 
+                      * with XLookupString, we don't have to care about
+                      * keymaps. */
+
+                    if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
+                    {
+                        switch( i_key )
+                        {
+                        case 'q':
+                        case 'Q':
+                            p_main->p_intf->b_die = 1;
+                            break;
+                        case 'f':
+                        case 'F':
+                            b_toggle_fullscreen = 1;
+                            break;
+                        case '0':
+                            network_ChannelJoin( 0 );
+                            break;
+                        case '1':
+                            network_ChannelJoin( 1 );
+                            break;
+                        case '2':
+                            network_ChannelJoin( 2 );
+                            break;
+                        case '3':
+                            network_ChannelJoin( 3 );
+                            break;
+                        case '4':
+                            network_ChannelJoin( 4 );
+                            break;
+                        case '5':
+                            network_ChannelJoin( 5 );
+                            break;
+                        case '6':
+                            network_ChannelJoin( 6 );
+                            break;
+                        case '7':
+                            network_ChannelJoin( 7 );
+                            break;
+                        case '8':
+                            network_ChannelJoin( 8 );
+                            break;
+                        case '9':
+                            network_ChannelJoin( 9 );
+                            break;
+                        default:
+                            if( intf_ProcessKey( p_main->p_intf, 
+                                                 (char )i_key ) )
+                            {
+                               intf_DbgMsg( "unhandled key '%c' (%i)", 
+                                            (char)i_key, i_key );
+                            }
+                            break;
+                        }
+                    }
+                break;
             }
         }
         /* Mouse click */
@@ -396,10 +463,6 @@ static int vout_Manage( vout_thread_t *p_vout )
                     /* in this part we will eventually manage
                      * clicks for DVD navigation for instance */
                     break;
-
-                case Button2:
-                    XVideoTogglePointer( p_vout );
-                    break;
             }
         }
         /* Mouse release */
@@ -413,16 +476,38 @@ static int vout_Manage( vout_thread_t *p_vout )
                     break;
             }
         }
-#ifdef DEBUG
+        /* Mouse move */
+        else if( xevent.type == MotionNotify )
+        {
+            p_vout->p_sys->i_time_mouse_last_moved = mdate();
+            p_vout->p_sys->b_mouse_pointer_visible = 1; 
+            XVideoSetMousePointer( p_vout ); 
+        }
         /* Other event */
         else
         {
-            intf_DbgMsg( "%p -> unhandled event type %d received",
+            intf_WarnMsg( 1, "%p -> unhandled event type %d received",
                          p_vout, xevent.type );
         }
-#endif
     }
 
+    /* Handle events for YUV video output sub-window */
+    while( XCheckWindowEvent( p_vout->p_sys->p_display,
+                              p_vout->p_sys->yuv_window,
+                              ExposureMask, &xevent ) == True )
+    {
+        /* Window exposed (only handled if stream playback is paused) */
+        if( xevent.type == Expose )
+        {
+            if( ((XExposeEvent *)&xevent)->count == 0 )
+                /* (if this is the last a collection of expose events...) */
+                if( p_main->p_intf->p_input )
+                    if( PAUSE_S ==
+                            p_main->p_intf->p_input->stream.control.i_status )
+                        XVideoDisplay( p_vout );
+        }
+    }
+        
     /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
      * are handled - according to the man pages, the format is always 32
      * in this case */
@@ -440,17 +525,27 @@ static int vout_Manage( vout_thread_t *p_vout )
         }
     }
 
-    if( (p_vout->i_width  != p_vout->p_sys->i_width) ||
-             (p_vout->i_height != p_vout->p_sys->i_height) )
+    if ( b_toggle_fullscreen )
     {
-        /* If video output size has changed, change interface window size */
-        intf_DbgMsg( "resizing output window" );
-        p_vout->p_sys->i_width =    p_vout->i_width;
-        p_vout->p_sys->i_height =   p_vout->i_height;
-        XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                       p_vout->p_sys->i_width, p_vout->p_sys->i_height );
+        intf_DbgMsg( "vout: changing full-screen status" );
+
+        p_vout->p_sys->b_fullscreen = !p_vout->p_sys->b_fullscreen;
+
+        /* Get rid of the old window */
+        XVideoDestroyWindow( p_vout );
+
+        /* And create a new one */
+        if( XVideoCreateWindow( p_vout ) )
+        {
+            intf_ErrMsg( "vout error: cannot create X11 window" );
+            XCloseDisplay( p_vout->p_sys->p_display );
+
+            free( p_vout->p_sys );
+            return( 1 );
+        }
     }
 
+    
     if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE))
     {
         /* FIXME: clear flags ?? */
@@ -463,39 +558,38 @@ static int vout_Manage( vout_thread_t *p_vout )
     {
         intf_DbgMsg( "vout: resizing window" );
         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
-
-        /* Resize window */
-        XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                       p_vout->i_width, p_vout->i_height );
-
-        /* Destroy XImages to change their size */
-        vout_End( p_vout );
-
-        /* Recreate XImages. If SysInit failed, the thread cannot go on. */
-        if( vout_Init( p_vout ) )
-        {
-            intf_ErrMsg( "vout error: cannot resize display" );
-            return( 1 );
-       }
-
+        /* Nothing to do here...
+         * vout_Display() detects size changes of the image to be displayed and
+         * re-creates the XvImage.*/
         intf_Msg( "vout: video display resized (%dx%d)",
                   p_vout->i_width, p_vout->i_height );
     }
 
+    /* Autohide Cursor */
+    if( p_vout->p_sys->b_mouse_pointer_visible &&
+        mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
+    {
+        p_vout->p_sys->b_mouse_pointer_visible = 0; 
+        XVideoSetMousePointer( p_vout );
+    }
+    
     return 0;
 }
 
-
 /*****************************************************************************
  * vout_Display: displays previously rendered output
  *****************************************************************************
- * This function send the currently rendered image to X11 server, wait until
- * it is displayed and switch the two rendering buffer, preparing next frame.
+ * This function sends the currently rendered image to X11 server.
+ * (The Xv extension takes care of "double-buffering".)
  *****************************************************************************/
 static void vout_Display( vout_thread_t *p_vout )
 {
     boolean_t b_draw = 1;
-    const int i_size = p_vout->i_width * p_vout->i_height;
+    int i_size = p_vout->p_rendered_pic->i_width *
+                   p_vout->p_rendered_pic->i_height;
+
+    if( XVideoUpdateImgSizeIfRequired( p_vout ) )
+        return;
 
     switch( p_vout->p_rendered_pic->i_type )
     {
@@ -520,30 +614,7 @@ static void vout_Display( vout_thread_t *p_vout )
     }
 
     if( b_draw )
-    {
-        int     i_dummy, i_src_width, i_src_height,
-                i_dest_width, i_dest_height, i_dest_x, i_dest_y;
-        Window  window;
-
-        /* Could use p_vout->p_sys->i_width and p_vout->p_sys->i_height
-         *instead of calling XGetGeometry? */
-        XGetGeometry( p_vout->p_sys->p_display, p_vout->p_sys->window,
-                      &window, &i_dummy, &i_dummy,
-                      &i_src_width, &i_src_height, &i_dummy, &i_dummy );
-
-        XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
-                            i_src_width, i_src_height, &i_dest_x, &i_dest_y,
-                            &i_dest_width, &i_dest_height);
-  
-        XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
-                       p_vout->p_sys->window, p_vout->p_sys->gc,
-                       p_vout->p_sys->p_xvimage,
-                       0 /*src_x*/, 0 /*src_y*/,
-                       p_vout->p_rendered_pic->i_width,
-                       p_vout->p_rendered_pic->i_height,
-                       i_dest_x, i_dest_y, i_dest_width, i_dest_height,
-                       True );
-    }
+        XVideoDisplay( p_vout );
 }
 
 static void vout_SetPalette( p_vout_thread_t p_vout,
@@ -554,6 +625,53 @@ static void vout_SetPalette( p_vout_thread_t p_vout,
 
 /* following functions are local */
 
+/*****************************************************************************
+ * XVideoUpdateImgSizeIfRequired 
+ *****************************************************************************
+ * This function checks to see if the image to be displayed is of a different
+ * size to the last image displayed. If so, the old shm block must be
+ * destroyed and a new one created.
+ * Note: the "image size" is the size of the image to be passed to the Xv
+ * extension (which is probably different to the size of the output window).
+ *****************************************************************************/
+static int XVideoUpdateImgSizeIfRequired( vout_thread_t *p_vout )
+{
+    int i_img_width         = p_vout->p_rendered_pic->i_width;
+    int i_img_height        = p_vout->p_rendered_pic->i_height;
+
+    if( p_vout->p_sys->i_image_width != i_img_width
+            || p_vout->p_sys->i_image_height != i_img_height )
+    {
+        p_vout->p_sys->i_image_width  = i_img_width;
+        p_vout->p_sys->i_image_height = i_img_height;
+
+        /* Destroy XvImage to change its size */
+        vout_End( p_vout );
+            /* Note: vout_End does nothing if no XvImage to destroy. */
+
+        /* Create XvImage using XShm extension */
+        if( XVideoCreateShmImage( p_vout->p_sys->p_display,
+                                  p_vout->p_sys->xv_port,
+                                  &p_vout->p_sys->p_xvimage,
+                                  &p_vout->p_sys->shm_info,
+                                  i_img_width, i_img_height ) )
+        {
+            intf_ErrMsg( "vout: failed to create xvimage." );
+            p_vout->p_sys->i_image_width = 0;
+            return( 1 );
+        }
+
+        /* Set bytes per line and initialize buffers */
+        p_vout->i_bytes_per_line =
+            (p_vout->p_sys->p_xvimage->data_size) /
+            (p_vout->p_sys->p_xvimage->height);
+
+        /* vout_SetBuffers( p_vout, p_vout->p_sys->p_xvimage->data ); */
+    }
+
+    return( 0 );
+}
+
 /*****************************************************************************
  * XVideoCheckForXv: check for the XVideo extension
  *****************************************************************************/
@@ -589,19 +707,36 @@ static int XVideoCreateWindow( vout_thread_t *p_vout )
     XSetWindowAttributes    xwindow_attributes;
     XGCValues               xgcvalues;
     XEvent                  xevent;
+    Atom                    prop;
+    mwmhints_t              mwmhints;
+    
     boolean_t               b_expose;
     boolean_t               b_configure_notify;
     boolean_t               b_map_notify;
 
+
     /* Set main window's size */
-    p_vout->p_sys->i_width =  main_GetIntVariable( VOUT_WIDTH_VAR,
-                                                   VOUT_WIDTH_DEFAULT );
-    p_vout->p_sys->i_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
-                                                   VOUT_HEIGHT_DEFAULT );
+    /* If we're full screen, we're full screen! */
+    if( p_vout->p_sys->b_fullscreen )
+    {
+        p_vout->p_sys->i_window_width = DisplayWidth( p_vout->p_sys->p_display,
+                                                      p_vout->p_sys->i_screen );
+        p_vout->p_sys->i_window_height =  DisplayHeight( p_vout->p_sys->p_display,
+                                                         p_vout->p_sys->i_screen );
+/*      p_vout->i_width =  p_vout->p_sys->i_window_width;
+        p_vout->i_height = p_vout->p_sys->i_window_height; */
+    }
+    else
+    {
+        p_vout->p_sys->i_window_width =  main_GetIntVariable( VOUT_WIDTH_VAR,
+                                                       VOUT_WIDTH_DEFAULT );
+        p_vout->p_sys->i_window_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
+                                                       VOUT_HEIGHT_DEFAULT );
+    }
 
     /* Prepare window manager hints and properties */
-    xsize_hints.base_width          = p_vout->p_sys->i_width;
-    xsize_hints.base_height         = p_vout->p_sys->i_height;
+    xsize_hints.base_width          = p_vout->p_sys->i_window_width;
+    xsize_hints.base_height         = p_vout->p_sys->i_window_height;
     xsize_hints.flags               = PSize;
     p_vout->p_sys->wm_protocols     = XInternAtom( p_vout->p_sys->p_display,
                                                    "WM_PROTOCOLS", True );
@@ -609,7 +744,6 @@ static int XVideoCreateWindow( vout_thread_t *p_vout )
                                                    "WM_DELETE_WINDOW", True );
 
     /* Prepare window attributes */
-    xwindow_attributes.backing_store = Always;       /* save the hidden part */
     xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
                                                       p_vout->p_sys->i_screen );
 
@@ -621,11 +755,27 @@ static int XVideoCreateWindow( vout_thread_t *p_vout )
             XCreateWindow( p_vout->p_sys->p_display,
                            DefaultRootWindow( p_vout->p_sys->p_display ),
                            0, 0,
-                           p_vout->p_sys->i_width, p_vout->p_sys->i_height, 1,
+                           p_vout->p_sys->i_window_width,
+                           p_vout->p_sys->i_window_height, 1,
                            0, InputOutput, 0,
-                           CWBackingStore | CWBackPixel | CWEventMask,
+                           CWBackPixel | CWEventMask,
                            &xwindow_attributes );
 
+    if ( p_vout->p_sys->b_fullscreen )
+    {
+        prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
+        mwmhints.flags = MWM_HINTS_DECORATIONS;
+        mwmhints.decorations = 0;
+        XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
+                         prop, prop, 32, PropModeReplace,
+                         (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
+
+        XSetTransientForHint( p_vout->p_sys->p_display,
+                              p_vout->p_sys->window, None );
+        XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
+    }
+
+    
     /* Set window manager hints and properties: size hints, command,
      * window's name, and accepted protocols */
     XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
@@ -677,20 +827,58 @@ static int XVideoCreateWindow( vout_thread_t *p_vout )
                  && (xevent.xconfigure.window == p_vout->p_sys->window) )
         {
             b_configure_notify = 1;
-            p_vout->p_sys->i_width = xevent.xconfigure.width;
-            p_vout->p_sys->i_height = xevent.xconfigure.height;
+            p_vout->p_sys->i_window_width = xevent.xconfigure.width;
+            p_vout->p_sys->i_window_height = xevent.xconfigure.height;
         }
     } while( !( b_expose && b_configure_notify && b_map_notify ) );
 
     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
                   StructureNotifyMask | KeyPressMask |
-                  ButtonPressMask | ButtonReleaseMask );
+                  ButtonPressMask | ButtonReleaseMask | 
+                  PointerMotionMask );
+
+    if( p_vout->p_sys->b_fullscreen )
+    {
+        XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
+                        RevertToNone, CurrentTime );
+        XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
+    }
+
+    /* Create YUV output sub-window. */
+    p_vout->p_sys->yuv_window=XCreateSimpleWindow( p_vout->p_sys->p_display,
+                         p_vout->p_sys->window, 0, 0, 1, 1, 0,
+                         BlackPixel( p_vout->p_sys->p_display,
+                                         p_vout->p_sys->i_screen ),
+                         WhitePixel( p_vout->p_sys->p_display,
+                                         p_vout->p_sys->i_screen ) );
+    p_vout->p_sys->yuv_gc = XCreateGC( p_vout->p_sys->p_display,
+                                        p_vout->p_sys->yuv_window,
+                                        GCGraphicsExposures, &xgcvalues );
+
+    XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
+             BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
+
+    XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
+    XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
+                  ExposureMask );
+
+
+    XVideoSetMousePointer( p_vout );
 
-    /* At this stage, the window is open, displayed, and ready to
-     * receive data */
     return( 0 );
 }
 
+static void XVideoDestroyWindow( vout_thread_t *p_vout )
+{
+    XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->yuv_gc );
+    XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
+
+    XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
+    XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
+    XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
+}
+
 /*****************************************************************************
  * XVideoCreateShmImage: create an XvImage using shared memory extension
  *****************************************************************************
@@ -699,34 +887,48 @@ static int XVideoCreateWindow( vout_thread_t *p_vout )
  * document by J.Corbet and K.Packard. Most of the parameters were copied from
  * there.
  *****************************************************************************/
-static int XVideoCreateShmImage( vout_thread_t *p_vout, XvImage **pp_xvimage,
-                                 XShmSegmentInfo *p_shm_info)
+static int XVideoCreateShmImage( Display* dpy, int xv_port,
+                                    XvImage **pp_xvimage,
+                                    XShmSegmentInfo *p_shm_info,
+                                    int i_width, int i_height )
 {
-    #define GUID_YUV12_PLANAR 0x32315659
-
-    *pp_xvimage = XvShmCreateImage( p_vout->p_sys->p_display,
-                                    p_vout->p_sys->xv_port,
+    *pp_xvimage = XvShmCreateImage( dpy, xv_port,
                                     GUID_YUV12_PLANAR, 0,
-                                    p_vout->i_width, p_vout->i_height,
+                                    i_width, i_height,
                                     p_shm_info );
+    if( !(*pp_xvimage) )
+    {
+        intf_ErrMsg( "vout error: XvShmCreateImage failed." );
+        return( -1 );
+    }
 
     p_shm_info->shmid    = shmget( IPC_PRIVATE, (*pp_xvimage)->data_size,
                                    IPC_CREAT | 0777 );
+    if( p_shm_info->shmid < 0)                                      /* error */
+    {
+        intf_ErrMsg( "vout error: cannot allocate shared image data (%s)",
+                    strerror(errno));
+        return( 1 );
+    }
+
     p_shm_info->shmaddr  = (*pp_xvimage)->data = shmat( p_shm_info->shmid,
                                                         0, 0 );
     p_shm_info->readOnly = False;
 
-    shmctl( p_shm_info->shmid, IPC_RMID, 0 ); /* XXX */
+    /* Mark the shm segment to be removed when there will be no more
+     * attachements, so it is automatic on process exit or after shmdt */
+    shmctl( p_shm_info->shmid, IPC_RMID, 0 );
 
-    if( !XShmAttach(p_vout->p_sys->p_display, p_shm_info) )
+    if( !XShmAttach( dpy, p_shm_info ) )
     {
         intf_ErrMsg( "vout error: XShmAttach failed" );
+        shmdt( p_shm_info->shmaddr );
         return( -1 );
     }
 
     /* Send image to X server. This instruction is required, since having
      * built a Shm XImage and not using it causes an error on XCloseDisplay */
-    XFlush( p_vout->p_sys->p_display );
+    XFlush( dpy );
 
     return( 0 );
 }
@@ -749,9 +951,7 @@ static void XVideoDestroyShmImage( vout_thread_t *p_vout, XvImage *p_xvimage,
 
     XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
 #if 0
-    XDestroyImage( p_ximage );
-#else
-/*    XvDestroyImage( p_xvimage ); XXX */
+    XDestroyImage( p_ximage ); /* XXX */
 #endif
 
     if( shmdt( p_shm_info->shmaddr ) )  /* detach shared memory from process */
@@ -801,22 +1001,18 @@ void XVideoDisableScreenSaver( vout_thread_t *p_vout )
 }
 
 /*****************************************************************************
- * XVideoTogglePointer: hide or show the mouse pointer
+ * XVideoSetMousePointer: hide or show the mouse pointer
  *****************************************************************************
- * This function hides the X pointer if it is visible by putting it at
- * coordinates (32,32) and setting the pointer sprite to a blank one. To
- * show it again, we disable the sprite and restore the original coordinates.
+ * This function hides the X pointer if requested.
  *****************************************************************************/
-void XVideoTogglePointer( vout_thread_t *p_vout )
+void XVideoSetMousePointer( const vout_thread_t *p_vout )
 {
-    static Cursor cursor;
-    static boolean_t b_cursor = 0;
+    static Cursor blank_cursor;
+    static boolean_t b_created_blank_cursor = 0;
 
-    if( p_vout->p_sys->b_mouse )
+    if( !p_vout->p_sys->b_mouse_pointer_visible )
     {
-        p_vout->p_sys->b_mouse = 0;
-
-        if( !b_cursor )
+        if( !b_created_blank_cursor )
         {
             XColor color;
             Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
@@ -833,18 +1029,16 @@ void XVideoTogglePointer( vout_thread_t *p_vout )
                                           AllocNone ),
                          "black", &color );
 
-            cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
+            blank_cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
                            blank, blank, &color, &color, 1, 1 );
 
-            b_cursor = 1;
+            b_created_blank_cursor = 1;
         }
         XDefineCursor( p_vout->p_sys->p_display,
-                       p_vout->p_sys->window, cursor );
+                       p_vout->p_sys->window, blank_cursor );
     }
     else
     {
-        p_vout->p_sys->b_mouse = 1;
-
         XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
     }
 }
@@ -864,11 +1058,22 @@ static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
         *w = win_w;
         switch( p_pic->i_aspect_ratio )
         {
-        case AR_3_4_PICTURE:        *h = win_w * 3 / 4;      break;
-        case AR_16_9_PICTURE:       *h = win_w * 9 / 16;     break;
-        case AR_221_1_PICTURE:      *h = win_w * 100 / 221;  break;
-        case AR_SQUARE_PICTURE:
-                default:            *h = win_w; break;
+            case AR_3_4_PICTURE:
+                *h = win_w * 3 / 4;
+                break;
+
+            case AR_16_9_PICTURE:
+                *h = win_w * 9 / 16;
+                break;
+
+           case AR_221_1_PICTURE:
+                *h = win_w * 100 / 221;
+                break;
+
+            case AR_SQUARE_PICTURE:
+            default:
+                *h = win_w * p_pic->i_height / p_pic->i_width;
+                break;
         }
 
         if( *h > win_h )
@@ -876,11 +1081,22 @@ static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
             *h = win_h;
             switch( p_pic->i_aspect_ratio )
             {
-            case AR_3_4_PICTURE:    *w = win_h * 4 / 3;      break;
-            case AR_16_9_PICTURE:   *w = win_h * 16 / 9;     break;
-            case AR_221_1_PICTURE:  *w = win_h * 221 / 100;  break;
-            case AR_SQUARE_PICTURE:
-                    default:        *w = win_h; break;
+                case AR_3_4_PICTURE:
+                    *w = win_h * 4 / 3;
+                    break;
+
+                case AR_16_9_PICTURE:
+                    *w = win_h * 16 / 9;
+                    break;
+
+                case AR_221_1_PICTURE:
+                    *w = win_h * 221 / 100;
+                    break;
+
+                case AR_SQUARE_PICTURE:
+                default:
+                    *w = win_h * p_pic->i_width / p_pic->i_height;
+                    break;
             }
         }
     }
@@ -894,6 +1110,7 @@ static void XVideoOutputCoords( const picture_t *p_pic, const boolean_t scale,
 static int XVideoGetPort( Display *dpy )
 {
     int            i, i_adaptors;
+    int            xv_port = -1;
     XvAdaptorInfo *adaptor_info;
 
     switch( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ),
@@ -915,23 +1132,81 @@ static int XVideoGetPort( Display *dpy )
             return( -1 );
     }
 
-    for( i=0; i < i_adaptors; ++i )
+    for( i=0; i < i_adaptors && xv_port == -1; ++i )
         if( ( adaptor_info[ i ].type & XvInputMask ) &&
             ( adaptor_info[ i ].type & XvImageMask ) )
-            {
-                return adaptor_info[ i ].base_id;
-            }
+        {
+            /* check that port supports YUV12 planar format... */
+            int port = adaptor_info[ i ].base_id;
+            int i_num_formats, i;
+            XvImageFormatValues *imageFormats;
+
+            imageFormats = XvListImageFormats( dpy, port, &i_num_formats );
 
-    intf_ErrMsg( "vout error: didn't find an Xvideo image input port." );
-    return( -1 );
+            for( i=0; i < i_num_formats && xv_port == -1; ++i )
+                if( imageFormats[ i ].id == GUID_YUV12_PLANAR )
+                    xv_port = port;
+
+            if( xv_port == -1 )
+                intf_WarnMsg( 3, "vout: XVideo image input port %d "
+                        "does not support the YUV12 planar format which is "
+                        "currently required by the xvideo output plugin.",
+                        port );
+
+            if( imageFormats )
+                XFree( imageFormats );
+        }
+
+    if( i_adaptors > 0 )
+        XvFreeAdaptorInfo(adaptor_info);
+
+    if( xv_port == -1 )
+        intf_ErrMsg( "vout error: didn't find a suitable Xvideo image input port." );
+
+    return( xv_port );
 }
 
 
+/*****************************************************************************
+ * XVideoDisplay: display image
+ *****************************************************************************
+ * This function displays the image stored in p_vout->p_sys->p_xvimage.
+ * The image is scaled to fit in the output window (and to have the correct
+ * aspect ratio).
+ *****************************************************************************/
+static void XVideoDisplay( vout_thread_t *p_vout )
+{
+    int     i_dest_width, i_dest_height, i_dest_x, i_dest_y;
+
+    if( !p_vout->p_sys->p_xvimage ) return;
+
+    XVideoOutputCoords( p_vout->p_rendered_pic, p_vout->b_scale,
+                        p_vout->p_sys->i_window_width,
+                        p_vout->p_sys->i_window_height,
+                        &i_dest_x, &i_dest_y,
+                        &i_dest_width, &i_dest_height);
+
+    XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->xv_port,
+                   p_vout->p_sys->yuv_window, p_vout->p_sys->gc,
+                   p_vout->p_sys->p_xvimage,
+                   0 /*src_x*/, 0 /*src_y*/,
+                   p_vout->p_rendered_pic->i_width,
+                   p_vout->p_rendered_pic->i_height,
+                   0 /*dest_x*/, 0 /*dest_y*/, i_dest_width, i_dest_height,
+                   True );
+
+     XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
+             i_dest_width, i_dest_height );
+     XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
+             i_dest_x, i_dest_y );
+}
+
+#if 0
 /*****************************************************************************
  * XVideoSetAttribute
  *****************************************************************************
  * This function can be used to set attributes, e.g. XV_BRIGHTNESS and
- * XV_CONTRAST. "value" should be in the range of 0 to 1.
+ * XV_CONTRAST. "f_value" should be in the range of 0 to 1.
  *****************************************************************************/
 static void XVideoSetAttribute( vout_thread_t *p_vout,
                                 char *attr_name, float f_value )
@@ -947,7 +1222,7 @@ static void XVideoSetAttribute( vout_thread_t *p_vout,
     {
         i_attrib--;
 
-        if( !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
+        if( i_attrib >= 0 && !strcmp( p_attrib[ i_attrib ].name, attr_name ) )
         {
             int i_sv = f_value * ( p_attrib[ i_attrib ].max_value
                                     - p_attrib[ i_attrib ].min_value + 1 )
@@ -955,9 +1230,12 @@ static void XVideoSetAttribute( vout_thread_t *p_vout,
 
             XvSetPortAttribute( p_dpy, xv_port,
                             XInternAtom( p_dpy, attr_name, False ), i_sv );
-            return;
+            break;
         }
 
     } while( i_attrib > 0 );
-}
 
+    if( p_attrib )
+        XFree( p_attrib );
+}
+#endif