]> git.sesse.net Git - vlc/blobdiff - modules/video_output/msw/directx.c
Wayland/shell: fix NULL dereference in pathological case
[vlc] / modules / video_output / msw / directx.c
index 827c81bd08eccbae7200ffb15422a60ca56a192a..afaa8f8df3023791b345e2149c1334d143d8fb33 100644 (file)
@@ -1,24 +1,24 @@
 /*****************************************************************************
  * directx.c: Windows DirectDraw video output
  *****************************************************************************
- * Copyright (C) 2001-2009 the VideoLAN team
+ * Copyright (C) 2001-2009 VLC authors and VideoLAN
  * $Id$
  *
  * Authors: Gildas Bazin <gbazin@videolan.org>
  *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
  * display video in window mode.
  *
  *****************************************************************************/
+
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
+
 #include <assert.h>
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_vout_display.h>
-#include <vlc_playlist.h>   /* needed for wallpaper */
+#include <vlc_charset.h>    /* FromT */
 
+#include <windows.h>
 #include <ddraw.h>
 #include <commctrl.h>       /* ListView_(Get|Set)* */
 
-#ifndef UNDER_CE
-#   include <multimon.h>
-#endif
-#undef GetSystemMetrics
-
-#ifndef MONITOR_DEFAULTTONEAREST
-#   define MONITOR_DEFAULTTONEAREST 2
-#endif
-
 #include "common.h"
 
+/* Unicode function "DirectDrawEnumerateExW" has been desactivated
+   since in some cases this function fails and the callbacks are not
+   called. If the Unicode mode is restored, one should modify the
+   prototype of the callbacks and call the FromT conversion function.
+*/
+#define DIRECTDRAWENUMERATEEX_NAME "DirectDrawEnumerateExA"
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
@@ -69,7 +70,7 @@
 #define SYSMEM_TEXT N_("Use video buffers in system memory")
 #define SYSMEM_LONGTEXT N_(\
     "Create video buffers in system memory instead of video memory. This " \
-    "isn't recommended as usually using video memory allows to benefit from " \
+    "isn't recommended as usually using video memory allows benefiting from " \
     "more hardware acceleration (like rescaling or YUV->RGB conversions). " \
     "This option doesn't have any effect when using overlays.")
 
 #define DX_HELP N_("Recommended video output for Windows XP. " \
     "Incompatible with Vista's Aero interface" )
 
-static const char * const device[] = { "" };
-static const char * const device_text[] = { N_("Default") };
-
 static int  Open (vlc_object_t *);
 static void Close(vlc_object_t *);
 
-static int  FindDevicesCallback(vlc_object_t *, char const *,
-                                vlc_value_t, vlc_value_t, void *);
+static int FindDevicesCallback(vlc_object_t *, const char *,
+                               char ***, char ***);
 vlc_module_begin()
     set_shortname("DirectX")
     set_description(N_("DirectX (DirectDraw) video output"))
     set_help(DX_HELP)
     set_category(CAT_VIDEO)
     set_subcategory(SUBCAT_VIDEO_VOUT)
-    add_bool("directx-hw-yuv", true, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT,
+    add_bool("directx-hw-yuv", true, HW_YUV_TEXT, HW_YUV_LONGTEXT,
               true)
-    add_bool("directx-use-sysmem", false, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT,
+    add_bool("directx-use-sysmem", false, SYSMEM_TEXT, SYSMEM_LONGTEXT,
               true)
-    add_bool("directx-3buffering", true, NULL, TRIPLEBUF_TEXT,
+    add_bool("directx-3buffering", true, TRIPLEBUF_TEXT,
               TRIPLEBUF_LONGTEXT, true)
-    add_string("directx-device", "", NULL, DEVICE_TEXT, DEVICE_LONGTEXT, true)
-        change_string_list(device, device_text, FindDevicesCallback)
-        change_action_add(FindDevicesCallback, N_("Refresh list"))
+    add_string("directx-device", "", DEVICE_TEXT, DEVICE_LONGTEXT, true)
+        change_string_cb(FindDevicesCallback)
 
-    set_capability("vout display", 100)
+    set_capability("vout display", 230)
     add_shortcut("directx")
     set_callbacks(Open, Close)
-
-    /* FIXME: Hack to avoid unregistering our window class */
-    cannot_unload_broken_library()
 vlc_module_end()
 
-#if 0 /* FIXME */
-    /* check if we registered a window class because we need to
-     * unregister it */
-    WNDCLASS wndclass;
-    if (GetClassInfo(GetModuleHandle(NULL), "VLC DirectX", &wndclass))
-        UnregisterClass("VLC DirectX", GetModuleHandle(NULL));
-#endif
-
 /*****************************************************************************
  * Local prototypes.
  *****************************************************************************/
@@ -134,6 +120,7 @@ vlc_module_end()
 struct picture_sys_t {
     LPDIRECTDRAWSURFACE2 surface;
     LPDIRECTDRAWSURFACE2 front_surface;
+    picture_t            *fallback;
 };
 
 /*****************************************************************************
@@ -148,7 +135,7 @@ DEFINE_GUID(IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,
 DEFINE_GUID(IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27);
 
 static picture_pool_t *Pool  (vout_display_t *, unsigned);
-static void           Display(vout_display_t *, picture_t *);
+static void           Display(vout_display_t *, picture_t *, subpicture_t *);
 static int            Control(vout_display_t *, int, va_list);
 static void           Manage (vout_display_t *);
 
@@ -186,20 +173,11 @@ static int Open(vlc_object_t *object)
         return VLC_EGENERIC;
     }
 
-    /* */
-    HMODULE huser32 = GetModuleHandle(_T("USER32"));
-    if (huser32) {
-        sys->MonitorFromWindow = (void*)GetProcAddress(huser32, _T("MonitorFromWindow"));
-        sys->GetMonitorInfo = (void*)GetProcAddress(huser32, _T("GetMonitorInfoW"));
-    } else {
-        sys->MonitorFromWindow = NULL;
-        sys->GetMonitorInfo = NULL;
-    }
-
     /* */
     sys->use_wallpaper = var_CreateGetBool(vd, "video-wallpaper");
     /* FIXME */
     sys->use_overlay = false;//var_CreateGetBool(vd, "overlay"); /* FIXME */
+    sys->restore_overlay = false;
     var_Create(vd, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
 
     /* Initialisation */
@@ -216,8 +194,9 @@ static int Open(vlc_object_t *object)
     vout_display_info_t info = vd->info;
     info.is_slow = true;
     info.has_double_click = true;
-    info.has_hide_mouse = true;
+    info.has_hide_mouse = false;
     info.has_pictures_invalid = true;
+    info.has_event_thread = true;
 
     /* Interaction TODO support starting with wallpaper mode */
     vlc_mutex_init(&sys->lock);
@@ -231,7 +210,8 @@ static int Open(vlc_object_t *object)
     var_AddCallback(vd, "video-wallpaper", WallpaperCallback, NULL);
 
     /* Setup vout_display now that everything is fine */
-    vd->fmt     = fmt;
+    video_format_Clean(&vd->fmt);
+    video_format_Copy(&vd->fmt, &fmt);
     vd->info    = info;
 
     vd->pool    = Pool;
@@ -242,7 +222,11 @@ static int Open(vlc_object_t *object)
     return VLC_SUCCESS;
 
 error:
-    Close(VLC_OBJECT(vd));
+    DirectXClose(vd);
+    CommonClean(vd);
+    if (sys->hddraw_dll)
+        FreeLibrary(sys->hddraw_dll);
+    free(sys);
     return VLC_EGENERIC;
 }
 
@@ -273,7 +257,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
     VLC_UNUSED(count);
     return vd->sys->pool;
 }
-static void Display(vout_display_t *vd, picture_t *picture)
+static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
 {
     vout_display_sys_t *sys = vd->sys;
 
@@ -287,6 +271,8 @@ static void Display(vout_display_t *vd, picture_t *picture)
                 DirectXUpdateOverlay(vd, NULL);
         }
     }
+    if (sys->restore_overlay)
+        DirectXUpdateOverlay(vd, NULL);
 
     /* */
     DirectXUnlock(picture);
@@ -328,6 +314,7 @@ static void Display(vout_display_t *vd, picture_t *picture)
     CommonDisplay(vd);
 
     picture_Release(picture);
+    VLC_UNUSED(subpicture);
 }
 static int Control(vout_display_t *vd, int query, va_list args)
 {
@@ -364,8 +351,8 @@ static void Manage(vout_display_t *vd)
             DirectXUpdateOverlay(vd, NULL);
 
         /* Check if we are still on the same monitor */
-        if (sys->MonitorFromWindow &&
-            sys->hmonitor != sys->MonitorFromWindow(sys->hwnd, MONITOR_DEFAULTTONEAREST)) {
+        HMONITOR hmon = MonitorFromWindow(sys->hwnd, MONITOR_DEFAULTTONEAREST);
+        if (sys->hmonitor != hmon) {
             vout_display_SendEventPicturesInvalid(vd);
         }
         /* */
@@ -381,6 +368,10 @@ static void Manage(vout_display_t *vd)
 
     if (ch_wallpaper)
         WallpaperChange(vd, wallpaper_requested);
+
+    /* */
+    if (sys->restore_overlay)
+        DirectXUpdateOverlay(vd, NULL);
 }
 
 /* */
@@ -445,8 +436,8 @@ static void DirectXClose(vout_display_t *vd)
 }
 
 /* */
-static BOOL WINAPI DirectXOpenDDrawCallback(GUID *guid, LPTSTR desc,
-                                            LPTSTR drivername, VOID *context,
+static BOOL WINAPI DirectXOpenDDrawCallback(GUID *guid, LPSTR desc,
+                                            LPSTR drivername, VOID *context,
                                             HMONITOR hmon)
 {
     vout_display_t *vd = context;
@@ -460,16 +451,19 @@ static BOOL WINAPI DirectXOpenDDrawCallback(GUID *guid, LPTSTR desc,
     if (!hmon)
         return TRUE;
 
-    msg_Dbg(vd, "DirectXEnumCallback: %s, %s", desc, drivername);
+    char *psz_drivername = drivername;
+    char *psz_desc = desc;
+
+    msg_Dbg(vd, "DirectXEnumCallback: %s, %s", psz_desc, psz_drivername);
 
     char *device = var_GetString(vd, "directx-device");
 
     /* Check for forced device */
-    if (device && *device && !strcmp(drivername, device)) {
+    if (device && *device && !strcmp(psz_drivername, device)) {
         MONITORINFO monitor_info;
         monitor_info.cbSize = sizeof(MONITORINFO);
 
-        if (sys->GetMonitorInfo(hmon, &monitor_info)) {
+        if (GetMonitorInfoA(hmon, &monitor_info)) {
             RECT rect;
 
             /* Move window to the right screen */
@@ -489,7 +483,7 @@ static BOOL WINAPI DirectXOpenDDrawCallback(GUID *guid, LPTSTR desc,
     free(device);
 
     if (hmon == sys->hmonitor) {
-        msg_Dbg(vd, "selecting %s, %s", desc, drivername);
+        msg_Dbg(vd, "selecting %s, %s", psz_desc, psz_drivername);
 
         free(sys->display_driver);
         sys->display_driver = malloc(sizeof(*guid));
@@ -578,31 +572,29 @@ static int DirectXOpenDDraw(vout_display_t *vd)
     /* */
     HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
     OurDirectDrawCreate =
-        (void *)GetProcAddress(sys->hddraw_dll, _T("DirectDrawCreate"));
+        (void *)GetProcAddress(sys->hddraw_dll, "DirectDrawCreate");
     if (!OurDirectDrawCreate) {
         msg_Err(vd, "DirectXInitDDraw failed GetProcAddress");
         return VLC_EGENERIC;
     }
 
     /* */
-    if (sys->MonitorFromWindow) {
-        HRESULT (WINAPI *OurDirectDrawEnumerateEx)(LPDDENUMCALLBACKEXA, LPVOID, DWORD);
-        OurDirectDrawEnumerateEx =
-          (void *)GetProcAddress(sys->hddraw_dll, _T("DirectDrawEnumerateExW"));
-
-        if (OurDirectDrawEnumerateEx) {
-            char *device = var_GetString(vd, "directx-device");
-            if (device) {
-                msg_Dbg(vd, "directx-device: %s", device);
-                free(device);
-            }
+    HRESULT (WINAPI *OurDirectDrawEnumerateEx)(LPDDENUMCALLBACKEXA, LPVOID, DWORD);
+    OurDirectDrawEnumerateEx =
+      (void *)GetProcAddress(sys->hddraw_dll, DIRECTDRAWENUMERATEEX_NAME);
+
+    if (OurDirectDrawEnumerateEx) {
+        char *device = var_GetString(vd, "directx-device");
+        if (device) {
+            msg_Dbg(vd, "directx-device: %s", device);
+            free(device);
+        }
 
-            sys->hmonitor = sys->MonitorFromWindow(sys->hwnd, MONITOR_DEFAULTTONEAREST);
+        sys->hmonitor = MonitorFromWindow(sys->hwnd, MONITOR_DEFAULTTONEAREST);
 
-            /* Enumerate displays */
-            OurDirectDrawEnumerateEx(DirectXOpenDDrawCallback,
-                                     vd, DDENUM_ATTACHEDSECONDARYDEVICES);
-        }
+        /* Enumerate displays */
+        OurDirectDrawEnumerateEx(DirectXOpenDDrawCallback,
+                                 vd, DDENUM_ATTACHEDSECONDARYDEVICES);
     }
 
     /* Initialize DirectDraw now */
@@ -614,8 +606,9 @@ static int DirectXOpenDDraw(vout_display_t *vd)
     }
 
     /* Get the IDirectDraw2 interface */
+    void *ptr;
     hr = IDirectDraw_QueryInterface(ddobject, &IID_IDirectDraw2,
-                                    &sys->ddobject);
+                                    &ptr);
     /* Release the unused interface */
     IDirectDraw_Release(ddobject);
 
@@ -624,6 +617,7 @@ static int DirectXOpenDDraw(vout_display_t *vd)
         sys->ddobject = NULL;
         return VLC_EGENERIC;
     }
+    sys->ddobject = ptr;
 
     /* Set DirectDraw Cooperative level, ie what control we want over Windows
      * display */
@@ -634,10 +628,10 @@ static int DirectXOpenDDraw(vout_display_t *vd)
     }
 
     /* Get the size of the current display device */
-    if (sys->hmonitor && sys->GetMonitorInfo) {
+    if (sys->hmonitor) {
         MONITORINFO monitor_info;
         monitor_info.cbSize = sizeof(MONITORINFO);
-        sys->GetMonitorInfo(vd->sys->hmonitor, &monitor_info);
+        GetMonitorInfoA(vd->sys->hmonitor, &monitor_info);
         sys->rect_display = monitor_info.rcMonitor;
     } else {
         sys->rect_display.left   = 0;
@@ -795,8 +789,9 @@ static int DirectXOpenDisplay(vout_display_t *vd)
         return VLC_EGENERIC;
     }
 
+    void *ptr;
     hr = IDirectDrawSurface_QueryInterface(display, &IID_IDirectDrawSurface2,
-                                           &sys->display);
+                                           &ptr);
     /* Release the old interface */
     IDirectDrawSurface_Release(display);
 
@@ -805,6 +800,7 @@ static int DirectXOpenDisplay(vout_display_t *vd)
         sys->display = NULL;
         return VLC_EGENERIC;
     }
+    sys->display = ptr;
 
     /* The clipper will be used only in non-overlay mode */
     DirectXCreateClipper(vd);
@@ -855,8 +851,8 @@ static int DirectXCreateSurface(vout_display_t *vd,
     ddsd.dwSize   = sizeof(ddsd);
     ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
     ddsd.dwFlags  = DDSD_HEIGHT | DDSD_WIDTH;
-    ddsd.dwWidth  = fmt->i_width;
-    ddsd.dwHeight = fmt->i_height;
+    ddsd.dwWidth  = fmt->i_visible_width;
+    ddsd.dwHeight = fmt->i_visible_height;
     if (fourcc) {
         ddsd.dwFlags |= DDSD_PIXELFORMAT;
         ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
@@ -956,6 +952,7 @@ static int DirectXLockSurface(LPDIRECTDRAWSURFACE2 front_surface,
 static void DirectXUnlockSurface(LPDIRECTDRAWSURFACE2 front_surface,
                                  LPDIRECTDRAWSURFACE2 surface)
 {
+    VLC_UNUSED(front_surface);
     IDirectDrawSurface2_Unlock(surface, NULL);
 }
 static int DirectXCheckLockingSurface(LPDIRECTDRAWSURFACE2 front_surface,
@@ -1038,9 +1035,10 @@ static int DirectXCreatePictureResourceYuvOverlay(vout_display_t *vd,
     }
 
     /* */
-    picture_resource_t *rsc = &sys->resource;
-    rsc->p_sys->front_surface = front_surface;
-    rsc->p_sys->surface       = surface;
+    picture_sys_t *picsys = sys->picsys;
+    picsys->front_surface = front_surface;
+    picsys->surface       = surface;
+    picsys->fallback      = NULL;
     return VLC_SUCCESS;
 }
 static int DirectXCreatePictureResourceYuv(vout_display_t *vd,
@@ -1093,9 +1091,10 @@ static int DirectXCreatePictureResourceYuv(vout_display_t *vd,
     }
 
     /* */
-    picture_resource_t *rsc = &sys->resource;
-    rsc->p_sys->front_surface = surface;
-    rsc->p_sys->surface       = surface;
+    picture_sys_t *picsys = sys->picsys;
+    picsys->front_surface = surface;
+    picsys->surface       = surface;
+    picsys->fallback      = NULL;
     return VLC_SUCCESS;
 }
 static int DirectXCreatePictureResourceRgb(vout_display_t *vd,
@@ -1152,9 +1151,10 @@ static int DirectXCreatePictureResourceRgb(vout_display_t *vd,
     }
 
     /* */
-    picture_resource_t *rsc = &sys->resource;
-    rsc->p_sys->front_surface = surface;
-    rsc->p_sys->surface       = surface;
+    picture_sys_t *picsys = sys->picsys;
+    picsys->front_surface = surface;
+    picsys->surface       = surface;
+    picsys->fallback      = NULL;
     return VLC_SUCCESS;
 }
 
@@ -1165,10 +1165,10 @@ static int DirectXCreatePictureResource(vout_display_t *vd,
     vout_display_sys_t *sys = vd->sys;
 
     /* */
-    picture_resource_t *rsc = &sys->resource;
-    rsc->p_sys = calloc(1, sizeof(*rsc->p_sys));
-    if (!rsc->p_sys)
+    picture_sys_t *picsys = calloc(1, sizeof(*picsys));
+    if (unlikely(picsys == NULL))
         return VLC_ENOMEM;
+    sys->picsys = picsys;
 
     /* */
     bool allow_hw_yuv  = sys->can_blit_fourcc &&
@@ -1208,7 +1208,11 @@ static void DirectXDestroyPictureResource(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
 
-    DirectXDestroySurface(sys->resource.p_sys->front_surface);
+    if (sys->picsys->front_surface != sys->picsys->surface)
+        DirectXDestroySurface(sys->picsys->surface);
+    DirectXDestroySurface(sys->picsys->front_surface);
+    if (sys->picsys->fallback)
+        picture_Release(sys->picsys->fallback);
 }
 
 static int DirectXLock(picture_t *picture)
@@ -1216,33 +1220,9 @@ static int DirectXLock(picture_t *picture)
     DDSURFACEDESC ddsd;
     if (DirectXLockSurface(picture->p_sys->front_surface,
                            picture->p_sys->surface, &ddsd))
-        return VLC_EGENERIC;
-
-    /* fill in buffer info in first plane */
-    picture->p->p_pixels = ddsd.lpSurface;
-    picture->p->i_pitch  = ddsd.lPitch;
-    picture->p->i_lines  = picture->format.i_height;
+        return CommonUpdatePicture(picture, &picture->p_sys->fallback, NULL, 0);
 
-    /*  Fill chroma planes for planar YUV */
-    if (picture->format.i_chroma == VLC_CODEC_I420 ||
-        picture->format.i_chroma == VLC_CODEC_J420 ||
-        picture->format.i_chroma == VLC_CODEC_YV12) {
-
-        for (int n = 1; n < picture->i_planes; n++) {
-            const plane_t *o = &picture->p[n-1];
-            plane_t *p = &picture->p[n];
-
-            p->p_pixels = o->p_pixels + o->i_lines * o->i_pitch;
-            p->i_pitch  = ddsd.lPitch / 2;
-            p->i_lines  = picture->format.i_height / 2;
-        }
-        /* The dx buffer is always allocated as YV12 */
-        if (vlc_fourcc_AreUVPlanesSwapped(picture->format.i_chroma, VLC_CODEC_YV12)) {
-            uint8_t *p_tmp = picture->p[1].p_pixels;
-            picture->p[1].p_pixels = picture->p[2].p_pixels;
-            picture->p[2].p_pixels = p_tmp;
-        }
-    }
+    CommonUpdatePicture(picture, NULL, ddsd.lpSurface, ddsd.lPitch);
     return VLC_SUCCESS;
 }
 static void DirectXUnlock(picture_t *picture)
@@ -1263,16 +1243,11 @@ static int DirectXCreatePool(vout_display_t *vd,
         return VLC_EGENERIC;
 
     /* Create the associated picture */
-    picture_resource_t *rsc = &sys->resource;
-    for (int i = 0; i < PICTURE_PLANE_MAX; i++) {
-        rsc->p[i].p_pixels = NULL;
-        rsc->p[i].i_pitch  = 0;
-        rsc->p[i].i_lines  = 0;
-    }
-    picture_t *picture = picture_NewFromResource(fmt, rsc);
+    picture_resource_t resource = { .p_sys = sys->picsys };
+    picture_t *picture = picture_NewFromResource(fmt, &resource);
     if (!picture) {
         DirectXDestroyPictureResource(vd);
-        free(rsc->p_sys);
+        free(sys->picsys);
         return VLC_ENOMEM;
     }
 
@@ -1341,7 +1316,7 @@ static int DirectXUpdateOverlay(vout_display_t *vd, LPDIRECTDRAWSURFACE2 surface
     if (!surface) {
         if (!sys->pool)
             return VLC_EGENERIC;
-        surface = sys->resource.p_sys->front_surface;
+        surface = sys->picsys->front_surface;
     }
 
     /* The new window dimensions should already have been computed by the
@@ -1357,6 +1332,8 @@ static int DirectXUpdateOverlay(vout_display_t *vd, LPDIRECTDRAWSURFACE2 surface
     HRESULT hr = IDirectDrawSurface2_UpdateOverlay(surface,
                                                    &src, sys->display, &dst,
                                                    DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE, &ddofx);
+    sys->restore_overlay = hr != DD_OK;
+
     if (hr != DD_OK) {
         msg_Warn(vd, "DirectDrawUpdateOverlay cannot move/resize overlay");
         return VLC_EGENERIC;
@@ -1418,85 +1395,69 @@ static int WallpaperCallback(vlc_object_t *object, char const *cmd,
     sys->ch_wallpaper |= ch_wallpaper;
     sys->wallpaper_requested = newval.b_bool;
     vlc_mutex_unlock(&sys->lock);
-
-    /* FIXME we should have a way to export variable to be saved */
-    if (ch_wallpaper) {
-        playlist_t *p_playlist = pl_Get(vd);
-        /* Modify playlist as well because the vout might have to be
-         * restarted */
-        var_Create(p_playlist, "video-wallpaper", VLC_VAR_BOOL);
-        var_SetBool(p_playlist, "video-wallpaper", newval.b_bool);
-    }
     return VLC_SUCCESS;
 }
 
+typedef struct
+{
+    char **values;
+    char **descs;
+    size_t count;
+} enum_context_t;
+
 /*****************************************************************************
  * config variable callback
  *****************************************************************************/
-static BOOL WINAPI DirectXEnumCallback2(GUID *guid, LPTSTR desc,
-                                        LPTSTR drivername, VOID *context,
+static BOOL WINAPI DirectXEnumCallback2(GUID *guid, LPSTR desc,
+                                        LPSTR drivername, VOID *data,
                                         HMONITOR hmon)
 {
-    VLC_UNUSED(guid); VLC_UNUSED(desc); VLC_UNUSED(hmon);
+    enum_context_t *ctx = data;
 
-    module_config_t *item = context;
+    VLC_UNUSED(guid); VLC_UNUSED(desc); VLC_UNUSED(hmon);
 
-    item->ppsz_list = xrealloc(item->ppsz_list,
-                               (item->i_list+2) * sizeof(char *));
-    item->ppsz_list_text = xrealloc(item->ppsz_list_text,
-                                    (item->i_list+2) * sizeof(char *));
+    char *psz_drivername = drivername;
+    ctx->values = xrealloc(ctx->values, (ctx->count + 1) * sizeof(char *));
+    ctx->descs = xrealloc(ctx->descs, (ctx->count + 1) * sizeof(char *));
 
-    item->ppsz_list[item->i_list] = strdup(drivername);
-    item->ppsz_list_text[item->i_list] = NULL;
-    item->i_list++;
-    item->ppsz_list[item->i_list] = NULL;
-    item->ppsz_list_text[item->i_list] = NULL;
+    ctx->values[ctx->count] = strdup(psz_drivername);
+    ctx->descs[ctx->count] = strdup(psz_drivername);
+    ctx->count++;
 
     return TRUE; /* Keep enumerating */
 }
 
-static int FindDevicesCallback(vlc_object_t *object, char const *name,
-                               vlc_value_t newval, vlc_value_t oldval, void *data)
+static int FindDevicesCallback(vlc_object_t *object, const char *name,
+                               char ***values, char ***descs)
 {
-    VLC_UNUSED(newval); VLC_UNUSED(oldval); VLC_UNUSED(data);
-
-    module_config_t *item = config_FindConfig(object, name);
-    if (!item)
-        return VLC_SUCCESS;
-
-    /* Clear-up the current list */
-    if (item->i_list > 0) {
-        int i;
-        /* Keep the first entry */
-        for (i = 1; i < item->i_list; i++) {
-            free(item->ppsz_list[i]);
-            free(item->ppsz_list_text[i]);
-        }
-        /* TODO: Remove when no more needed */
-        item->ppsz_list[i] = NULL;
-        item->ppsz_list_text[i] = NULL;
-    }
-    item->i_list = 1;
+    enum_context_t ctx;
+
+    ctx.values = xmalloc(sizeof(char *));
+    ctx.descs = xmalloc(sizeof(char *));
+    ctx.values[0] = strdup("");
+    ctx.descs[0] = strdup(_("Default"));
+    ctx.count = 1;
 
     /* Load direct draw DLL */
     HINSTANCE hddraw_dll = LoadLibrary(_T("DDRAW.DLL"));
-    if (!hddraw_dll)
-        return VLC_SUCCESS;
-
-    /* Enumerate displays */
-    HRESULT (WINAPI *OurDirectDrawEnumerateEx)(LPDDENUMCALLBACKEXA,
-                                               LPVOID, DWORD) =
-        (void *)GetProcAddress(hddraw_dll, _T("DirectDrawEnumerateExW"));
-    if (OurDirectDrawEnumerateEx)
-        OurDirectDrawEnumerateEx(DirectXEnumCallback2, item,
-                                 DDENUM_ATTACHEDSECONDARYDEVICES);
-
-    FreeLibrary(hddraw_dll);
+    if (hddraw_dll != NULL)
+    {
+        /* Enumerate displays */
+        HRESULT (WINAPI *OurDirectDrawEnumerateEx)(LPDDENUMCALLBACKEXA,
+                                                   LPVOID, DWORD) =
+              (void *)GetProcAddress(hddraw_dll, DIRECTDRAWENUMERATEEX_NAME);
+        if (OurDirectDrawEnumerateEx != NULL)
+            OurDirectDrawEnumerateEx(DirectXEnumCallback2, &ctx,
+                                     DDENUM_ATTACHEDSECONDARYDEVICES);
+        FreeLibrary(hddraw_dll);
+    }
 
-    /* Signal change to the interface */
-    item->b_dirty = true;
+    VLC_UNUSED(object);
+    VLC_UNUSED(name);
 
-    return VLC_SUCCESS;
+    *values = ctx.values;
+    *descs = ctx.descs;
+    return ctx.count;
 }