]> git.sesse.net Git - vlc/blobdiff - modules/video_output/msw/common.c
Win32: use video-x and video-y (fixes #3215)
[vlc] / modules / video_output / msw / common.c
index ca32c5538906f5b42a5b800272b85d96cdb015d1..8dd2d79f061b362e6e89cf39fc7f9b343e67d45b 100644 (file)
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
-
-#include <errno.h>                                                 /* ENOMEM */
-#include <ctype.h>                                              /* tolower() */
-
-#ifndef _WIN32_WINNT
-#   define _WIN32_WINNT 0x0500
-#endif
+#include <assert.h>
 
 #include <vlc_common.h>
-#include <vlc_interface.h>
-#include <vlc_playlist.h>
-#include <vlc_vout.h>
+#include <vlc_vout_display.h>
 #include <vlc_vout_window.h>
 
 #include <windows.h>
-#include <tchar.h>
 #include <windowsx.h>
 #include <shellapi.h>
 
 #include <d3d9.h>
 #endif
 #ifdef MODULE_NAME_IS_glwin32
-#include <GL/gl.h>
+#include "../opengl.h"
 #endif
 
-#include <vlc_keys.h>
-#include "vout.h"
+#include "common.h"
 
 #ifndef UNDER_CE
 #include <vlc_windows_interfaces.h>
     //WINSHELLAPI BOOL WINAPI SHFullScreen(HWND hwndRequester, DWORD dwState);
 #endif
 
-static int vaControlParentWindow( vout_thread_t *, int, va_list );
+static int CommonControlSetFullscreen(vout_display_t *, bool is_fullscreen);
+
+static void DisableScreensaver(vout_display_t *);
+static void RestoreScreensaver(vout_display_t *);
 
 /* */
-int CommonInit( vout_thread_t *p_vout )
+int CommonInit(vout_display_t *vd)
 {
-    vout_sys_t *p_sys = p_vout->p_sys;
-
-    p_sys->hwnd      = NULL;
-    p_sys->hvideownd = NULL;
-    p_sys->hparent   = NULL;
-    p_sys->hfswnd    = NULL;
-    p_sys->i_changes = 0;
-    SetRectEmpty( &p_sys->rect_display );
-    SetRectEmpty( &p_sys->rect_parent );
-    vlc_mutex_init( &p_sys->lock );
-
-    var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-
-    /* Set main window's size */
-    p_sys->i_window_width  = p_vout->i_window_width;
-    p_sys->i_window_height = p_vout->i_window_height;
-
-    p_sys->p_event = EventThreadCreate( p_vout );
-    if( !p_sys->p_event )
+    vout_display_sys_t *sys = vd->sys;
+
+    sys->hwnd      = NULL;
+    sys->hvideownd = NULL;
+    sys->hparent   = NULL;
+    sys->hfswnd    = NULL;
+    sys->changes   = 0;
+    SetRectEmpty(&sys->rect_display);
+    SetRectEmpty(&sys->rect_parent);
+    sys->is_first_display = true;
+    sys->is_on_top = false;
+
+    var_Create(vd, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
+    var_Create(vd, "video-deco", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
+
+    /* FIXME remove mouse hide from msw */
+    var_Create(vd, "mouse-hide-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
+
+    /* */
+    sys->event = EventThreadCreate(vd);
+    if (!sys->event)
         return VLC_EGENERIC;
-    if( EventThreadStart( p_sys->p_event ) )
+
+    event_cfg_t cfg;
+    memset(&cfg, 0, sizeof(cfg));
+#ifdef MODULE_NAME_IS_direct3d
+    cfg.use_desktop = sys->use_desktop;
+#endif
+#ifdef MODULE_NAME_IS_directx
+    cfg.use_overlay = sys->use_overlay;
+#endif
+    cfg.win.type   = VOUT_WINDOW_TYPE_HWND;
+    cfg.win.x      = var_InheritInteger(vd, "video-x");
+    cfg.win.y      = var_InheritInteger(vd, "video-y");
+    cfg.win.width  = vd->cfg->display.width;
+    cfg.win.height = vd->cfg->display.height;
+
+    event_hwnd_t hwnd;
+    if (EventThreadStart(sys->event, &hwnd, &cfg))
         return VLC_EGENERIC;
 
-    /* Variable to indicate if the window should be on top of others */
-    /* Trigger a callback right now */
-    var_TriggerCallback( p_vout, "video-on-top" );
+    sys->parent_window = hwnd.parent_window;
+    sys->hparent       = hwnd.hparent;
+    sys->hwnd          = hwnd.hwnd;
+    sys->hvideownd     = hwnd.hvideownd;
+    sys->hfswnd        = hwnd.hfswnd;
+
+    if (vd->cfg->is_fullscreen) {
+        if (CommonControlSetFullscreen(vd, true))
+            vout_display_SendEventFullscreen(vd, false);
+    }
 
     /* Why not with glwin32 */
 #if !defined(UNDER_CE) && !defined(MODULE_NAME_IS_glwin32)
-    var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    DisableScreensaver ( p_vout );
+    var_Create(vd, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
+    DisableScreensaver (vd);
 #endif
 
     return VLC_SUCCESS;
 }
 
 /* */
-void CommonClean( vout_thread_t *p_vout )
+void CommonClean(vout_display_t *vd)
 {
-    vout_sys_t *p_sys = p_vout->p_sys;
+    vout_display_sys_t *sys = vd->sys;
 
-    ExitFullscreen( p_vout );
-    if( p_sys->p_event )
-    {
-        EventThreadStop( p_sys->p_event );
-        EventThreadDestroy( p_sys->p_event );
+    if (sys->event) {
+        EventThreadStop(sys->event);
+        EventThreadDestroy(sys->event);
     }
 
-    vlc_mutex_destroy( &p_sys->lock );
-
 #if !defined(UNDER_CE) && !defined(MODULE_NAME_IS_glwin32)
-    RestoreScreensaver( p_vout );
+    RestoreScreensaver(vd);
 #endif
 }
 
-void CommonManage( vout_thread_t *p_vout )
+void CommonManage(vout_display_t *vd)
 {
+    vout_display_sys_t *sys = vd->sys;
+
+    /* We used to call the Win32 PeekMessage function here to read the window
+     * messages. But since window can stay blocked into this function for a
+     * long time (for example when you move your window on the screen), I
+     * decided to isolate PeekMessage in another thread. */
+
     /* If we do not control our window, we check for geometry changes
      * ourselves because the parent might not send us its events. */
-    vlc_mutex_lock( &p_vout->p_sys->lock );
-    if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
-    {
+    if (sys->hparent) {
         RECT rect_parent;
         POINT point;
 
-        vlc_mutex_unlock( &p_vout->p_sys->lock );
-
-        GetClientRect( p_vout->p_sys->hparent, &rect_parent );
+        GetClientRect(sys->hparent, &rect_parent);
         point.x = point.y = 0;
-        ClientToScreen( p_vout->p_sys->hparent, &point );
-        OffsetRect( &rect_parent, point.x, point.y );
+        ClientToScreen(sys->hparent, &point);
+        OffsetRect(&rect_parent, point.x, point.y);
 
-        if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
-        {
-            p_vout->p_sys->rect_parent = rect_parent;
+        if (!EqualRect(&rect_parent, &sys->rect_parent)) {
+            sys->rect_parent = rect_parent;
 
             /* FIXME I find such #ifdef quite weirds. Are they really needed ? */
 
-#if defined(MODULE_NAME_IS_direct3d)
-            SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
-                          rect_parent.right - rect_parent.left,
-                          rect_parent.bottom - rect_parent.top,
-                          SWP_NOZORDER );
-            UpdateRects( p_vout, true );
+#if defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_wingdi) || defined(MODULE_NAME_IS_wingapi)
+            SetWindowPos(sys->hwnd, 0, 0, 0,
+                         rect_parent.right - rect_parent.left,
+                         rect_parent.bottom - rect_parent.top,
+                         SWP_NOZORDER);
+            UpdateRects(vd, NULL, NULL, true);
 #else
             /* This one is to force the update even if only
              * the position has changed */
-            SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
-                          rect_parent.right - rect_parent.left,
-                          rect_parent.bottom - rect_parent.top, 0 );
-
-            SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
-                          rect_parent.right - rect_parent.left,
-                          rect_parent.bottom - rect_parent.top, 0 );
-
-#if defined(MODULE_NAME_IS_wingdi) || defined(MODULE_NAME_IS_wingapi)
-            unsigned int i_x, i_y, i_width, i_height;
-            vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left,
-                               rect_parent.bottom - rect_parent.top,
-                               &i_x, &i_y, &i_width, &i_height );
-
-            SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
-                          i_x, i_y, i_width, i_height, 0 );
-#endif
-#endif
-        }
-    }
-    else
-    {
-        vlc_mutex_unlock( &p_vout->p_sys->lock );
-    }
-
-    /* autoscale toggle */
-    if( p_vout->i_changes & VOUT_SCALE_CHANGE )
-    {
-        p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
+            SetWindowPos(sys->hwnd, 0, 1, 1,
+                         rect_parent.right - rect_parent.left,
+                         rect_parent.bottom - rect_parent.top, 0);
 
-        p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
-        p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
-
-        UpdateRects( p_vout, true );
-    }
+            SetWindowPos(sys->hwnd, 0, 0, 0,
+                         rect_parent.right - rect_parent.left,
+                         rect_parent.bottom - rect_parent.top, 0);
 
-    /* scaling factor */
-    if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
-    {
-        p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
-
-        p_vout->b_autoscale = false;
-        p_vout->i_zoom =
-            (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
-        UpdateRects( p_vout, true );
-    }
-
-    /* Check for cropping / aspect changes */
-    if( p_vout->i_changes & VOUT_CROP_CHANGE ||
-        p_vout->i_changes & VOUT_ASPECT_CHANGE )
-    {
-        p_vout->i_changes &= ~VOUT_CROP_CHANGE;
-        p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
-
-        p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
-        p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
-        p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
-        p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
-        p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
-        p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
-        p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
-        p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
-        UpdateRects( p_vout, true );
+#endif
+        }
     }
 
-    /* We used to call the Win32 PeekMessage function here to read the window
-     * messages. But since window can stay blocked into this function for a
-     * long time (for example when you move your window on the screen), I
-     * decided to isolate PeekMessage in another thread. */
+    /* */
+    if (EventThreadGetAndResetHasMoved(sys->event))
+        UpdateRects(vd, NULL, NULL, false);
 
-    /*
-     * Fullscreen change
-     */
-    if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
-        || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
-    {
-        Win32ToggleFullscreen( p_vout );
+    /* Pointer change */
+    EventThreadMouseAutoHide(sys->event);
+}
 
-        p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
-        p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
-    }
+/**
+ * It ensures that the video window is shown after the first picture
+ * is displayed.
+ */
+void CommonDisplay(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
 
-    /*
-     * Pointer change
-     */
-    EventThreadMouseAutoHide( p_vout->p_sys->p_event );
+    if (!sys->is_first_display)
+        return;
 
-    /*
-     * "Always on top" status change
+    /* Video window is initially hidden, show it now since we got a
+     * picture to show.
      */
-    if( p_vout->p_sys->b_on_top_change )
-    {
-        HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
-        bool b = var_GetBool( p_vout, "video-on-top" );
-
-        /* Set the window on top if necessary */
-        if( b && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
-                           & WS_EX_TOPMOST ) )
-        {
-            CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
-                           MF_BYCOMMAND | MFS_CHECKED );
-            SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
-                          SWP_NOSIZE | SWP_NOMOVE );
-        }
-        else
-        /* The window shouldn't be on top */
-        if( !b && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
-                           & WS_EX_TOPMOST ) )
-        {
-            CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
-                           MF_BYCOMMAND | MFS_UNCHECKED );
-            SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
-                          SWP_NOSIZE | SWP_NOMOVE );
-        }
+    SetWindowPos(sys->hvideownd, 0, 0, 0, 0, 0,
+                 SWP_ASYNCWINDOWPOS|
+                 SWP_FRAMECHANGED|
+                 SWP_SHOWWINDOW|
+                 SWP_NOMOVE|
+                 SWP_NOSIZE|
+                 SWP_NOZORDER);
+    sys->is_first_display = false;
+}
 
-        p_vout->p_sys->b_on_top_change = false;
-    }
+void AlignRect(RECT *r, int align_boundary, int align_size)
+{
+    if (align_boundary)
+        r->left = (r->left + align_boundary/2) & ~align_boundary;
+    if (align_size)
+        r->right = ((r->right - r->left + align_size/2) & ~align_size) + r->left;
 }
 
 /*****************************************************************************
@@ -288,89 +237,103 @@ void CommonManage( vout_thread_t *p_vout )
  * its job is to update the source and destination RECTs used to display the
  * picture.
  *****************************************************************************/
-void UpdateRects( vout_thread_t *p_vout, bool b_force )
+void UpdateRects(vout_display_t *vd,
+                  const vout_display_cfg_t *cfg,
+                  const video_format_t *source,
+                  bool is_forced)
 {
-#define rect_src p_vout->p_sys->rect_src
-#define rect_src_clipped p_vout->p_sys->rect_src_clipped
-#define rect_dest p_vout->p_sys->rect_dest
-#define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
-
-    unsigned int i_width, i_height, i_x, i_y;
+    vout_display_sys_t *sys = vd->sys;
+#define rect_src sys->rect_src
+#define rect_src_clipped sys->rect_src_clipped
+#define rect_dest sys->rect_dest
+#define rect_dest_clipped sys->rect_dest_clipped
 
     RECT  rect;
     POINT point;
 
+    /* */
+    if (!cfg)
+        cfg = vd->cfg;
+    if (!source)
+        source = &vd->source;
+
     /* Retrieve the window size */
-    GetClientRect( p_vout->p_sys->hwnd, &rect );
+    GetClientRect(sys->hwnd, &rect);
 
     /* Retrieve the window position */
     point.x = point.y = 0;
-    ClientToScreen( p_vout->p_sys->hwnd, &point );
+    ClientToScreen(sys->hwnd, &point);
 
     /* If nothing changed, we can return */
-    if( !b_force
-         && p_vout->p_sys->i_window_width == rect.right
-         && p_vout->p_sys->i_window_height == rect.bottom
-         && p_vout->p_sys->i_window_x == point.x
-         && p_vout->p_sys->i_window_y == point.y )
-    {
+    bool has_moved;
+    bool is_resized;
+    EventThreadUpdateWindowPosition(sys->event, &has_moved, &is_resized,
+                                    point.x, point.y,
+                                    rect.right, rect.bottom);
+    if (is_resized)
+        vout_display_SendEventDisplaySize(vd, rect.right, rect.bottom, cfg->is_fullscreen);
+    if (!is_forced && !has_moved && !is_resized )
         return;
-    }
 
     /* Update the window position and size */
-    p_vout->p_sys->i_window_x = point.x;
-    p_vout->p_sys->i_window_y = point.y;
-    p_vout->p_sys->i_window_width = rect.right;
-    p_vout->p_sys->i_window_height = rect.bottom;
+    vout_display_cfg_t place_cfg = *cfg;
+    place_cfg.display.width  = rect.right;
+    place_cfg.display.height = rect.bottom;
 
-    vout_PlacePicture( p_vout, rect.right, rect.bottom,
-                       &i_x, &i_y, &i_width, &i_height );
+    vout_display_place_t place;
+    vout_display_PlacePicture(&place, source, &place_cfg, true);
 
-    if( p_vout->p_sys->hvideownd )
-        SetWindowPos( p_vout->p_sys->hvideownd, 0,
-                      i_x, i_y, i_width, i_height,
-                      SWP_NOCOPYBITS|SWP_NOZORDER|SWP_ASYNCWINDOWPOS );
+    EventThreadUpdateSourceAndPlace(sys->event, source, &place);
+#if defined(MODULE_NAME_IS_wingapi)
+    if (place.width != vd->fmt.i_width || place.height != vd->fmt.i_height)
+        vout_display_SendEventPicturesInvalid(vd);
+#endif
+
+    if (sys->hvideownd)
+        SetWindowPos(sys->hvideownd, 0,
+                     place.x, place.y, place.width, place.height,
+                     SWP_NOCOPYBITS|SWP_NOZORDER|SWP_ASYNCWINDOWPOS);
 
     /* Destination image position and dimensions */
-    rect_dest.left = point.x + i_x;
-    rect_dest.right = rect_dest.left + i_width;
-    rect_dest.top = point.y + i_y;
-    rect_dest.bottom = rect_dest.top + i_height;
+#if defined(MODULE_NAME_IS_direct3d)
+    rect_dest.left   = 0;
+    rect_dest.right  = place.width;
+    rect_dest.top    = 0;
+    rect_dest.bottom = place.height;
+#else
+    rect_dest.left = point.x + place.x;
+    rect_dest.right = rect_dest.left + place.width;
+    rect_dest.top = point.y + place.y;
+    rect_dest.bottom = rect_dest.top + place.height;
 
 #ifdef MODULE_NAME_IS_directx
     /* Apply overlay hardware constraints */
-    if( p_vout->p_sys->b_using_overlay )
-    {
-        if( p_vout->p_sys->i_align_dest_boundary )
-            rect_dest.left = ( rect_dest.left +
-                p_vout->p_sys->i_align_dest_boundary / 2 ) &
-                ~p_vout->p_sys->i_align_dest_boundary;
-
-        if( p_vout->p_sys->i_align_dest_size )
-            rect_dest.right = (( rect_dest.right - rect_dest.left +
-                p_vout->p_sys->i_align_dest_size / 2 ) &
-                ~p_vout->p_sys->i_align_dest_size) + rect_dest.left;
-    }
+    if (sys->use_overlay)
+        AlignRect(&rect_dest, sys->i_align_dest_boundary, sys->i_align_dest_size);
+#endif
+
+#endif
 
+#if defined(MODULE_NAME_IS_directx) || defined(MODULE_NAME_IS_direct3d)
     /* UpdateOverlay directdraw function doesn't automatically clip to the
-     * display size so we need to do it otherwise it will fail */
+     * display size so we need to do it otherwise it will fail
+     * It is also needed for d3d to avoid exceding our surface size */
 
     /* Clip the destination window */
-    if( !IntersectRect( &rect_dest_clipped, &rect_dest,
-                        &p_vout->p_sys->rect_display ) )
-    {
-        SetRectEmpty( &rect_src_clipped );
+    if (!IntersectRect(&rect_dest_clipped, &rect_dest,
+                       &sys->rect_display)) {
+        SetRectEmpty(&rect_src_clipped);
         return;
     }
 
 #ifndef NDEBUG
-    msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:"
-                     " %li,%li,%li,%li",
-                     rect_dest_clipped.left, rect_dest_clipped.top,
-                     rect_dest_clipped.right, rect_dest_clipped.bottom );
+    msg_Dbg(vd, "DirectXUpdateRects image_dst_clipped coords:"
+                " %li,%li,%li,%li",
+                rect_dest_clipped.left, rect_dest_clipped.top,
+                rect_dest_clipped.right, rect_dest_clipped.bottom);
 #endif
 
-#else /* MODULE_NAME_IS_directx */
+#else
 
     /* AFAIK, there are no clipping constraints in Direct3D, OpenGL and GDI */
     rect_dest_clipped = rect_dest;
@@ -378,106 +341,95 @@ void UpdateRects( vout_thread_t *p_vout, bool b_force )
 #endif
 
     /* the 2 following lines are to fix a bug when clicking on the desktop */
-    if( (rect_dest_clipped.right - rect_dest_clipped.left)==0 ||
-        (rect_dest_clipped.bottom - rect_dest_clipped.top)==0 )
-    {
-        SetRectEmpty( &rect_src_clipped );
+    if ((rect_dest_clipped.right - rect_dest_clipped.left) == 0 ||
+        (rect_dest_clipped.bottom - rect_dest_clipped.top) == 0) {
+        SetRectEmpty(&rect_src_clipped);
         return;
     }
 
     /* src image dimensions */
-    rect_src.left = 0;
-    rect_src.top = 0;
-    rect_src.right = p_vout->render.i_width;
-    rect_src.bottom = p_vout->render.i_height;
+    rect_src.left   = 0;
+    rect_src.top    = 0;
+    rect_src.right  = source->i_width;
+    rect_src.bottom = source->i_height;
 
     /* Clip the source image */
-    rect_src_clipped.left = p_vout->fmt_out.i_x_offset +
+    rect_src_clipped.left = source->i_x_offset +
       (rect_dest_clipped.left - rect_dest.left) *
-      p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left);
-    rect_src_clipped.right = p_vout->fmt_out.i_x_offset +
-      p_vout->fmt_out.i_visible_width -
+      source->i_visible_width / (rect_dest.right - rect_dest.left);
+    rect_src_clipped.right = source->i_x_offset +
+      source->i_visible_width -
       (rect_dest.right - rect_dest_clipped.right) *
-      p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left);
-    rect_src_clipped.top = p_vout->fmt_out.i_y_offset +
+      source->i_visible_width / (rect_dest.right - rect_dest.left);
+    rect_src_clipped.top = source->i_y_offset +
       (rect_dest_clipped.top - rect_dest.top) *
-      p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top);
-    rect_src_clipped.bottom = p_vout->fmt_out.i_y_offset +
-      p_vout->fmt_out.i_visible_height -
+      source->i_visible_height / (rect_dest.bottom - rect_dest.top);
+    rect_src_clipped.bottom = source->i_y_offset +
+      source->i_visible_height -
       (rect_dest.bottom - rect_dest_clipped.bottom) *
-      p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top);
+      source->i_visible_height / (rect_dest.bottom - rect_dest.top);
 
 #ifdef MODULE_NAME_IS_directx
     /* Apply overlay hardware constraints */
-    if( p_vout->p_sys->b_using_overlay )
-    {
-        if( p_vout->p_sys->i_align_src_boundary )
-            rect_src_clipped.left = ( rect_src_clipped.left +
-                p_vout->p_sys->i_align_src_boundary / 2 ) &
-                ~p_vout->p_sys->i_align_src_boundary;
-
-        if( p_vout->p_sys->i_align_src_size )
-            rect_src_clipped.right = (( rect_src_clipped.right -
-                rect_src_clipped.left +
-                p_vout->p_sys->i_align_src_size / 2 ) &
-                ~p_vout->p_sys->i_align_src_size) + rect_src_clipped.left;
-    }
+    if (sys->use_overlay)
+        AlignRect(&rect_src_clipped, sys->i_align_src_boundary, sys->i_align_src_size);
+#elif defined(MODULE_NAME_IS_direct3d)
+    /* Needed at least with YUV content */
+    rect_src_clipped.left &= ~1;
+    rect_src_clipped.right &= ~1;
+    rect_src_clipped.top &= ~1;
+    rect_src_clipped.bottom &= ~1;
 #endif
 
 #ifndef NDEBUG
-    msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped"
-                     " coords: %li,%li,%li,%li",
-                     rect_src_clipped.left, rect_src_clipped.top,
-                     rect_src_clipped.right, rect_src_clipped.bottom );
+    msg_Dbg(vd, "DirectXUpdateRects image_src_clipped"
+                " coords: %li,%li,%li,%li",
+                rect_src_clipped.left, rect_src_clipped.top,
+                rect_src_clipped.right, rect_src_clipped.bottom);
 #endif
 
 #ifdef MODULE_NAME_IS_directx
     /* The destination coordinates need to be relative to the current
      * directdraw primary surface (display) */
-    rect_dest_clipped.left -= p_vout->p_sys->rect_display.left;
-    rect_dest_clipped.right -= p_vout->p_sys->rect_display.left;
-    rect_dest_clipped.top -= p_vout->p_sys->rect_display.top;
-    rect_dest_clipped.bottom -= p_vout->p_sys->rect_display.top;
-
-    if( p_vout->p_sys->b_using_overlay )
-        DirectDrawUpdateOverlay( p_vout );
+    rect_dest_clipped.left -= sys->rect_display.left;
+    rect_dest_clipped.right -= sys->rect_display.left;
+    rect_dest_clipped.top -= sys->rect_display.top;
+    rect_dest_clipped.bottom -= sys->rect_display.top;
 #endif
 
 #ifndef UNDER_CE
     /* Windows 7 taskbar thumbnail code */
-    LPTASKBARLIST3 p_taskbl;
+    LPTASKBARLIST3 taskbl;
     OSVERSIONINFO winVer;
     winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-    if( GetVersionEx(&winVer) && winVer.dwMajorVersion > 5 )
-    {
-        CoInitialize( 0 );
-
-        if( S_OK == CoCreateInstance( &clsid_ITaskbarList,
-                    NULL, CLSCTX_INPROC_SERVER,
-                    &IID_ITaskbarList3,
-                    &p_taskbl) )
-        {
+    if (GetVersionEx(&winVer) && winVer.dwMajorVersion > 5) {
+        CoInitialize(0);
+
+        if (S_OK == CoCreateInstance(&clsid_ITaskbarList,
+                                     NULL, CLSCTX_INPROC_SERVER,
+                                     &IID_ITaskbarList3,
+                                     &taskbl)) {
             RECT rect_video, rect_parent, rect_relative;
-            HWND hroot = GetAncestor(p_vout->p_sys->hwnd,GA_ROOT);
+            HWND hroot = GetAncestor(sys->hwnd,GA_ROOT);
 
-            p_taskbl->vt->HrInit(p_taskbl);
-            GetWindowRect(p_vout->p_sys->hvideownd, &rect_video);
+            taskbl->vt->HrInit(taskbl);
+            GetWindowRect(sys->hvideownd, &rect_video);
             GetWindowRect(hroot, &rect_parent);
             rect_relative.left = rect_video.left - rect_parent.left - 8;
             rect_relative.right = rect_video.right - rect_video.left + rect_relative.left;
             rect_relative.top = rect_video.top - rect_parent.top - 10;
             rect_relative.bottom = rect_video.bottom - rect_video.top + rect_relative.top - 25;
 
-            if (S_OK != p_taskbl->vt->SetThumbnailClip(p_taskbl, hroot, &rect_relative))
-                msg_Err( p_vout, "SetThumbNailClip failed");
+            if (S_OK != taskbl->vt->SetThumbnailClip(taskbl, hroot, &rect_relative))
+                msg_Err(vd, "SetThumbNailClip failed");
 
-            p_taskbl->vt->Release(p_taskbl);
+            taskbl->vt->Release(taskbl);
         }
         CoUninitialize();
     }
 #endif
     /* Signal the change in size/position */
-    p_vout->p_sys->i_changes |= DX_POSITION_CHANGE;
+    sys->changes |= DX_POSITION_CHANGE;
 
 #undef rect_src
 #undef rect_src_clipped
@@ -485,253 +437,239 @@ void UpdateRects( vout_thread_t *p_vout, bool b_force )
 #undef rect_dest_clipped
 }
 
-/*****************************************************************************
- * Control: control facility for the vout
- *****************************************************************************/
-int Control( vout_thread_t *p_vout, int i_query, va_list args )
+static int CommonControlSetFullscreen(vout_display_t *vd, bool is_fullscreen)
 {
-    RECT rect_window;
-
-    switch( i_query )
-    {
-    case VOUT_SET_SIZE:
-        if( p_vout->p_sys->parent_window )
-            return vaControlParentWindow( p_vout, i_query, args );
-
-        /* Update dimensions */
-        rect_window.top = rect_window.left = 0;
-        rect_window.right  = va_arg( args, unsigned int );
-        rect_window.bottom = va_arg( args, unsigned int );
-        if( !rect_window.right ) rect_window.right = p_vout->i_window_width;
-        if( !rect_window.bottom ) rect_window.bottom = p_vout->i_window_height;
-        AdjustWindowRect( &rect_window, p_vout->p_sys->i_window_style, 0 );
-
-        SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
-                      rect_window.right - rect_window.left,
-                      rect_window.bottom - rect_window.top, SWP_NOMOVE );
-
-        return VLC_SUCCESS;
-
-    case VOUT_SET_STAY_ON_TOP:
-        if( p_vout->p_sys->hparent && !var_GetBool( p_vout, "fullscreen" ) )
-            return vaControlParentWindow( p_vout, i_query, args );
-
-        p_vout->p_sys->b_on_top_change = true;
-        return VLC_SUCCESS;
-
-    default:
-        return VLC_EGENERIC;
-    }
-}
+    vout_display_sys_t *sys = vd->sys;
 
-
-/* Internal wrapper over GetWindowPlacement */
-static WINDOWPLACEMENT getWindowState(HWND hwnd)
-{
-    WINDOWPLACEMENT window_placement;
-    window_placement.length = sizeof(WINDOWPLACEMENT);
-    GetWindowPlacement( hwnd, &window_placement );
-    return window_placement;
-}
-
-/* Internal wrapper to call vout_ControlWindow for hparent */
-static int vaControlParentWindow( vout_thread_t *p_vout, int i_query,
-                                   va_list args )
-{
-    switch( i_query )
-    {
-    case VOUT_SET_SIZE:
-    {
-        const unsigned i_width  = va_arg(args, unsigned);
-        const unsigned i_height = va_arg(args, unsigned);
-        return vout_window_SetSize( p_vout->p_sys->parent_window, i_width, i_height );
-    }
-    case VOUT_SET_STAY_ON_TOP:
-    {
-        const bool is_on_top = va_arg(args, int);
-        return vout_window_SetOnTop( p_vout->p_sys->parent_window, is_on_top );
-    }
-    default:
+#ifdef MODULE_NAME_IS_direct3d
+    if (sys->use_desktop && is_fullscreen)
         return VLC_EGENERIC;
-    }
-}
-
-#if 0
-static int ControlParentWindow( vout_thread_t *p_vout, int i_query, ... )
-{
-    va_list args;
-    int ret;
-
-    va_start( args, i_query );
-    ret = vaControlParentWindow( p_vout, i_query, args );
-    va_end( args );
-    return ret;
-}
 #endif
 
-void ExitFullscreen( vout_thread_t *p_vout )
-{
-    if( p_vout->b_fullscreen )
-    {
-        msg_Dbg( p_vout, "Quitting fullscreen" );
-        Win32ToggleFullscreen( p_vout );
-        /* Force fullscreen in the core for the next video */
-        var_SetBool( p_vout, "fullscreen", true );
-    }
-}
+    /* */
+    if (sys->parent_window)
+        return vout_window_SetFullScreen(sys->parent_window, is_fullscreen);
 
-void Win32ToggleFullscreen( vout_thread_t *p_vout )
-{
-    HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
-        p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
+    /* */
+    HWND hwnd = sys->hparent && sys->hfswnd ? sys->hfswnd : sys->hwnd;
 
     /* Save the current windows placement/placement to restore
        when fullscreen is over */
-    WINDOWPLACEMENT window_placement = getWindowState( hwnd );
-
-    p_vout->b_fullscreen = ! p_vout->b_fullscreen;
+    WINDOWPLACEMENT window_placement;
+    window_placement.length = sizeof(WINDOWPLACEMENT);
+    GetWindowPlacement(hwnd, &window_placement);
 
-    /* We want to go to Fullscreen */
-    if( p_vout->b_fullscreen )
-    {
-        msg_Dbg( p_vout, "entering fullscreen mode" );
+    if (is_fullscreen) {
+        msg_Dbg(vd, "entering fullscreen mode");
 
         /* Change window style, no borders and no title bar */
-        int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
-        SetWindowLong( hwnd, GWL_STYLE, i_style );
+        SetWindowLong(hwnd, GWL_STYLE, WS_CLIPCHILDREN | WS_VISIBLE);
 
-        if( p_vout->p_sys->hparent )
-        {
+        if (sys->hparent) {
 #ifdef UNDER_CE
             POINT point = {0,0};
             RECT rect;
-            ClientToScreen( p_vout->p_sys->hwnd, &point );
-            GetClientRect( p_vout->p_sys->hwnd, &rect );
-            SetWindowPos( hwnd, 0, point.x, point.y,
-                          rect.right, rect.bottom,
-                          SWP_NOZORDER|SWP_FRAMECHANGED );
+            ClientToScreen(sys->hwnd, &point);
+            GetClientRect(sys->hwnd, &rect);
+            SetWindowPos(hwnd, 0, point.x, point.y,
+                         rect.right, rect.bottom,
+                         SWP_NOZORDER|SWP_FRAMECHANGED);
 #else
             /* Retrieve current window position so fullscreen will happen
             *on the right screen */
-            HMONITOR hmon = MonitorFromWindow(p_vout->p_sys->hparent,
-                                            MONITOR_DEFAULTTONEAREST);
+            HMONITOR hmon = MonitorFromWindow(sys->hparent,
+                                              MONITOR_DEFAULTTONEAREST);
             MONITORINFO mi;
+            mi.cbSize = sizeof(MONITORINFO);
             if (GetMonitorInfo(hmon, &mi))
-            SetWindowPos( hwnd, 0,
-                            mi.rcMonitor.left,
-                            mi.rcMonitor.top,
-                            mi.rcMonitor.right - mi.rcMonitor.left,
-                            mi.rcMonitor.bottom - mi.rcMonitor.top,
-                            SWP_NOZORDER|SWP_FRAMECHANGED );
+                SetWindowPos(hwnd, 0,
+                             mi.rcMonitor.left,
+                             mi.rcMonitor.top,
+                             mi.rcMonitor.right - mi.rcMonitor.left,
+                             mi.rcMonitor.bottom - mi.rcMonitor.top,
+                             SWP_NOZORDER|SWP_FRAMECHANGED);
 #endif
-        }
-        else
-        {
+        } else {
             /* Maximize non embedded window */
-            ShowWindow( hwnd, SW_SHOWMAXIMIZED );
+            ShowWindow(hwnd, SW_SHOWMAXIMIZED);
         }
 
-        if( p_vout->p_sys->hparent )
-        {
+        if (sys->hparent) {
             /* Hide the previous window */
             RECT rect;
-            GetClientRect( hwnd, &rect );
-            SetParent( p_vout->p_sys->hwnd, hwnd );
-            SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
-                          rect.right, rect.bottom,
-                          SWP_NOZORDER|SWP_FRAMECHANGED );
+            GetClientRect(hwnd, &rect);
+            SetParent(sys->hwnd, hwnd);
+            SetWindowPos(sys->hwnd, 0, 0, 0,
+                         rect.right, rect.bottom,
+                         SWP_NOZORDER|SWP_FRAMECHANGED);
 
 #ifdef UNDER_CE
-            HWND topLevelParent = GetParent( p_vout->p_sys->hparent );
+            HWND topLevelParent = GetParent(sys->hparent);
 #else
-            HWND topLevelParent = GetAncestor( p_vout->p_sys->hparent, GA_ROOT );
+            HWND topLevelParent = GetAncestor(sys->hparent, GA_ROOT);
 #endif
-            ShowWindow( topLevelParent, SW_HIDE );
+            ShowWindow(topLevelParent, SW_HIDE);
         }
+        SetForegroundWindow(hwnd);
+    } else {
+        msg_Dbg(vd, "leaving fullscreen mode");
 
-        SetForegroundWindow( hwnd );
-    }
-    else
-    {
-        msg_Dbg( p_vout, "leaving fullscreen mode" );
         /* Change window style, no borders and no title bar */
-        SetWindowLong( hwnd, GWL_STYLE, p_vout->p_sys->i_window_style );
+        SetWindowLong(hwnd, GWL_STYLE, EventThreadGetWindowStyle(sys->event));
 
-        if( p_vout->p_sys->hparent )
-        {
+        if (sys->hparent) {
             RECT rect;
-            GetClientRect( p_vout->p_sys->hparent, &rect );
-            SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
-            SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
-                          rect.right, rect.bottom,
-                          SWP_NOZORDER|SWP_FRAMECHANGED );
+            GetClientRect(sys->hparent, &rect);
+            SetParent(sys->hwnd, sys->hparent);
+            SetWindowPos(sys->hwnd, 0, 0, 0,
+                         rect.right, rect.bottom,
+                         SWP_NOZORDER|SWP_FRAMECHANGED);
 
 #ifdef UNDER_CE
-            HWND topLevelParent = GetParent( p_vout->p_sys->hparent );
+            HWND topLevelParent = GetParent(sys->hparent);
 #else
-            HWND topLevelParent = GetAncestor( p_vout->p_sys->hparent, GA_ROOT );
+            HWND topLevelParent = GetAncestor(sys->hparent, GA_ROOT);
 #endif
-            ShowWindow( topLevelParent, SW_SHOW );
-            SetForegroundWindow( p_vout->p_sys->hparent );
-            ShowWindow( hwnd, SW_HIDE );
-        }
-        else
-        {
+            ShowWindow(topLevelParent, SW_SHOW);
+            SetForegroundWindow(sys->hparent);
+            ShowWindow(hwnd, SW_HIDE);
+        } else {
             /* return to normal window for non embedded vout */
-            SetWindowPlacement( hwnd, &window_placement );
-            ShowWindow( hwnd, SW_SHOWNORMAL );
+            SetWindowPlacement(hwnd, &window_placement);
+            ShowWindow(hwnd, SW_SHOWNORMAL);
         }
 
         /* Make sure the mouse cursor is displayed */
-        PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
+        EventThreadMouseShow(sys->event);
     }
+    return VLC_SUCCESS;
+}
 
-    /* Update the object variable and trigger callback */
-    var_SetBool( p_vout, "fullscreen", p_vout->b_fullscreen );
+int CommonControl(vout_display_t *vd, int query, va_list args)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    switch (query) {
+    case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:   /* const vout_display_cfg_t *p_cfg, int is_forced */
+    case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: /* const vout_display_cfg_t *p_cfg */
+    case VOUT_DISPLAY_CHANGE_ZOOM:           /* const vout_display_cfg_t *p_cfg */
+    case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:  /* const video_format_t *p_source */
+    case VOUT_DISPLAY_CHANGE_SOURCE_CROP: {  /* const video_format_t *p_source */
+        const vout_display_cfg_t *cfg;
+        const video_format_t *source;
+        bool  is_forced = true;
+        if (query == VOUT_DISPLAY_CHANGE_SOURCE_CROP ||
+            query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT) {
+            cfg    = vd->cfg;
+            source = va_arg(args, const video_format_t *);
+        } else {
+            cfg    = va_arg(args, const vout_display_cfg_t *);
+            source = &vd->source;
+            if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE)
+                is_forced = va_arg(args, int);
+        }
+        if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE && is_forced) {
+            /* Update dimensions */
+            if (sys->parent_window) {
+                vout_window_SetSize(sys->parent_window, cfg->display.width, cfg->display.height);
+            } else {
+                RECT rect_window;
+                rect_window.top    = 0;
+                rect_window.left   = 0;
+                rect_window.right  = cfg->display.width;
+                rect_window.bottom = cfg->display.height;
+                AdjustWindowRect(&rect_window, EventThreadGetWindowStyle(sys->event), 0);
+
+                SetWindowPos(sys->hwnd, 0, 0, 0,
+                             rect_window.right - rect_window.left,
+                             rect_window.bottom - rect_window.top, SWP_NOMOVE);
+            }
+        }
+        UpdateRects(vd, cfg, source, is_forced);
+        return VLC_SUCCESS;
+    }
+    case VOUT_DISPLAY_CHANGE_WINDOW_STATE: {       /* unsigned state */
+        const unsigned state = va_arg(args, unsigned);
+        const bool is_on_top = (state & VOUT_WINDOW_STATE_ABOVE) != 0;
+#ifdef MODULE_NAME_IS_direct3d
+        if (sys->use_desktop && is_on_top)
+            return VLC_EGENERIC;
+#endif
+        if (sys->parent_window) {
+            if (vout_window_SetState(sys->parent_window, state))
+                return VLC_EGENERIC;
+        } else {
+            HMENU hMenu = GetSystemMenu(sys->hwnd, FALSE);
+
+            if (is_on_top && !(GetWindowLong(sys->hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)) {
+                CheckMenuItem(hMenu, IDM_TOGGLE_ON_TOP, MF_BYCOMMAND | MFS_CHECKED);
+                SetWindowPos(sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+            } else if (!is_on_top && (GetWindowLong(sys->hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)) {
+                CheckMenuItem(hMenu, IDM_TOGGLE_ON_TOP, MF_BYCOMMAND | MFS_UNCHECKED);
+                SetWindowPos(sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
+            }
+        }
+        sys->is_on_top = is_on_top;
+        return VLC_SUCCESS;
+    }
+    case VOUT_DISPLAY_CHANGE_FULLSCREEN: {   /* const vout_display_cfg_t *p_cfg */
+        const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
+        return CommonControlSetFullscreen(vd, cfg->is_fullscreen);
+    }
+
+    case VOUT_DISPLAY_RESET_PICTURES:
+    case VOUT_DISPLAY_HIDE_MOUSE:
+        assert(0);
+    default:
+        return VLC_EGENERIC;
+    }
 }
 
 #ifndef UNDER_CE
-void DisableScreensaver( vout_thread_t *p_vout )
+static void DisableScreensaver(vout_display_t *vd)
 {
+    vout_display_sys_t *sys = vd->sys;
+
     /* disable screensaver by temporarily changing system settings */
-    p_vout->p_sys->i_spi_lowpowertimeout = 0;
-    p_vout->p_sys->i_spi_powerofftimeout = 0;
-    p_vout->p_sys->i_spi_screensavetimeout = 0;
-    if( var_GetBool( p_vout, "disable-screensaver" ) )
-    {
-        msg_Dbg(p_vout, "disabling screen saver");
-        SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
-            0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
-        if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
+    sys->i_spi_lowpowertimeout = 0;
+    sys->i_spi_powerofftimeout = 0;
+    sys->i_spi_screensavetimeout = 0;
+    if (var_GetBool(vd, "disable-screensaver")) {
+        msg_Dbg(vd, "disabling screen saver");
+        SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT, 0,
+                             &sys->i_spi_lowpowertimeout, 0);
+        if (0 != sys->i_spi_lowpowertimeout) {
             SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
         }
         SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
-            &(p_vout->p_sys->i_spi_powerofftimeout), 0);
-        if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
+                             &sys->i_spi_powerofftimeout, 0);
+        if (0 != sys->i_spi_powerofftimeout) {
             SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
         }
         SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
-            &(p_vout->p_sys->i_spi_screensavetimeout), 0);
-        if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
+                             &sys->i_spi_screensavetimeout, 0);
+        if (0 != sys->i_spi_screensavetimeout) {
             SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
         }
     }
 }
 
-void RestoreScreensaver( vout_thread_t *p_vout )
+static void RestoreScreensaver(vout_display_t *vd)
 {
+    vout_display_sys_t *sys = vd->sys;
+
     /* restore screensaver system settings */
-    if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
+    if (0 != sys->i_spi_lowpowertimeout) {
         SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
-            p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
+                             sys->i_spi_lowpowertimeout, NULL, 0);
     }
-    if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
+    if (0 != sys->i_spi_powerofftimeout) {
         SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
-            p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
+                             sys->i_spi_powerofftimeout, NULL, 0);
     }
-    if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
+    if (0 != sys->i_spi_screensavetimeout) {
         SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
-            p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
+                             sys->i_spi_screensavetimeout, NULL, 0);
     }
 }
 #endif