diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index cbea8c5..246c3d2 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -454,6 +454,11 @@ extern "C" {
  */
 #define SDL_HINT_VIDEO_HIGHDPI_DISABLED "SDL_VIDEO_HIGHDPI_DISABLED"
 
+ /**
+ *  \brief If set to 1, then allow high-DPI on all windows.
+ */
+#define SDL_HINT_VIDEO_HIGHDPI_ENABLED "SDL_VIDEO_HIGHDPI_ENABLED"
+
 /**
  *  \brief A variable that determines whether ctrl+click should generate a right-click event on Mac
  *
diff --git a/include/SDL_video.h b/include/SDL_video.h
index bee5241..4b04ece 100644
--- a/include/SDL_video.h
+++ b/include/SDL_video.h
@@ -110,7 +110,7 @@ typedef enum
     SDL_WINDOW_MOUSE_FOCUS = 0x00000400,        /**< window has mouse focus */
     SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
     SDL_WINDOW_FOREIGN = 0x00000800,            /**< window not created by SDL */
-    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported */
+    SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,      /**< window should be created in high-DPI mode if supported (deprecated, use SDL_HINT_VIDEO_HIGHDPI_ENABLED) */
     SDL_WINDOW_MOUSE_CAPTURE = 0x00004000,      /**< window has mouse captured (unrelated to INPUT_GRABBED) */
     SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000,      /**< window should always be above others */
     SDL_WINDOW_SKIP_TASKBAR  = 0x00010000,      /**< window should not be added to the taskbar */
diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c
index 3b0c299..3f733a7 100644
--- a/src/render/direct3d/SDL_render_d3d.c
+++ b/src/render/direct3d/SDL_render_d3d.c
@@ -125,6 +125,7 @@ static void PrintShaderData(LPDWORD shader_data, DWORD shader_size)
 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
 static void D3D_WindowEvent(SDL_Renderer * renderer,
                             const SDL_WindowEvent *event);
+static int D3D_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static int D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
@@ -468,8 +469,7 @@ D3D_ActivateRenderer(SDL_Renderer * renderer)
         SDL_Window *window = renderer->window;
         int w, h;
         Uint32 window_flags = SDL_GetWindowFlags(window);
-
-        SDL_GetWindowSize(window, &w, &h);
+        WIN_GetDrawableSize(window, &w, &h);
         data->pparams.BackBufferWidth = w;
         data->pparams.BackBufferHeight = h;
         if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
@@ -542,6 +542,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
     }
 
     renderer->WindowEvent = D3D_WindowEvent;
+    renderer->GetOutputSize = D3D_GetOutputSize;
     renderer->CreateTexture = D3D_CreateTexture;
     renderer->UpdateTexture = D3D_UpdateTexture;
     renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
@@ -568,7 +569,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
     SDL_GetWindowWMInfo(window, &windowinfo);
 
     window_flags = SDL_GetWindowFlags(window);
-    SDL_GetWindowSize(window, &w, &h);
+    WIN_GetDrawableSize(window, &w, &h);
     SDL_GetWindowDisplayMode(window, &fullscreen_mode);
 
     SDL_zero(pparams);
@@ -802,6 +803,13 @@ D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
     }
 }
 
+static int
+D3D_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
+{
+    WIN_GetDrawableSize(renderer->window, w, h);
+    return 0;
+}
+
 static D3DTEXTUREFILTERTYPE
 GetScaleQuality(void)
 {
diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c
index e093ce5..0fd2aee 100644
--- a/src/render/direct3d11/SDL_render_d3d11.c
+++ b/src/render/direct3d11/SDL_render_d3d11.c
@@ -716,6 +716,7 @@ static const DWORD D3D11_VertexShader[] = {
 static SDL_Renderer *D3D11_CreateRenderer(SDL_Window * window, Uint32 flags);
 static void D3D11_WindowEvent(SDL_Renderer * renderer,
                             const SDL_WindowEvent *event);
+static int D3D11_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
 static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                              const SDL_Rect * rect, const void *srcPixels,
@@ -826,6 +827,7 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
     }
 
     renderer->WindowEvent = D3D11_WindowEvent;
+    renderer->GetOutputSize = D3D11_GetOutputSize;
     renderer->CreateTexture = D3D11_CreateTexture;
     renderer->UpdateTexture = D3D11_UpdateTexture;
     renderer->UpdateTextureYUV = D3D11_UpdateTextureYUV;
@@ -1532,7 +1534,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
     /* The width and height of the swap chain must be based on the display's
      * non-rotated size.
      */
-    SDL_GetWindowSize(renderer->window, &w, &h);
+    WIN_GetDrawableSize(renderer->window, &w, &h);
     data->rotation = D3D11_GetCurrentRotation();
     /* SDL_Log("%s: windowSize={%d,%d}, orientation=%d\n", __FUNCTION__, w, h, (int)data->rotation); */
     if (D3D11_IsDisplayRotated90Degrees(data->rotation)) {
@@ -1694,6 +1696,13 @@ D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
     }
 }
 
+static int
+D3D11_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
+{
+    WIN_GetDrawableSize(renderer->window, w, h);
+    return 0;
+}
+
 static D3D11_FILTER
 GetScaleQuality(void)
 {
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index 39c94f6..7925f83 100644
--- a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -195,7 +195,7 @@ SDLTest_CommonArg(SDLTest_CommonState * state, int index)
         return 1;
     }
     if (SDL_strcasecmp(argv[index], "--allow-highdpi") == 0) {
-        state->window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
+        SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_ENABLED, "1");
         return 1;
     }
     if (SDL_strcasecmp(argv[index], "--windows") == 0) {
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 7e0e5ac..cf451f8 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -1390,6 +1390,11 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
         }
     }
 
+    /* This hint adds SDL_WINDOW_ALLOW_HIGHDPI to all windows. */
+    if (SDL_GetHintBoolean(SDL_HINT_VIDEO_HIGHDPI_ENABLED, SDL_FALSE)) {
+        flags |= SDL_WINDOW_ALLOW_HIGHDPI;
+    }
+
     /* Unless the user has specified the high-DPI disabling hint, respect the
      * SDL_WINDOW_ALLOW_HIGHDPI flag.
      */
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 926f526..3e4869f 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -33,6 +33,7 @@
 #include "../../events/scancodes_windows.h"
 #include "SDL_assert.h"
 #include "SDL_hints.h"
+#include "SDL_log.h"
 
 /* Dropfile support */
 #include <shellapi.h>
@@ -46,6 +47,8 @@
 #include "wmmsg.h"
 #endif
 
+/* #define HIGHDPI_DEBUG */
+
 /* For processing mouse WM_*BUTTON* and WM_MOUSEMOVE message-data from GetMessageExtraInfo() */
 #define MOUSEEVENTF_FROMTOUCH 0xFF515700
 
@@ -80,6 +83,9 @@
 #ifndef WM_UNICHAR
 #define WM_UNICHAR 0x0109
 #endif
+#ifndef WM_DPICHANGED
+#define WM_DPICHANGED 0x02E0
+#endif
 
 static SDL_Scancode
 WindowsScanCodeToSDLScanCode(LPARAM lParam, WPARAM wParam)
@@ -364,6 +370,24 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
     /* Get the window data for the window */
     data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
     if (!data) {
+        /* Request that windows scale the non-client area when moving between monitors.
+           This is only for Windows 10 Anniversary Update.
+           In the Windows 10 Creators Update, this is the default behaviour with a per-monitor V2 context.
+        */
+        switch (msg) {
+            case WM_NCCREATE:
+                {
+                    SDL_VideoDevice *device = SDL_GetVideoDevice();
+                    if (device && device->driverdata) {
+                        SDL_VideoData *data = SDL_static_cast(SDL_VideoData *, device->driverdata);
+                        if (data->highdpi_enabled && data->EnableNonClientDpiScaling) {
+                            data->EnableNonClientDpiScaling(hwnd);
+                        }
+                    }
+                }
+            break;
+        }
+
         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
     }
 
@@ -458,7 +482,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             SDL_Mouse *mouse = SDL_GetMouse();
             if (!mouse->relative_mode || mouse->relative_mode_warp) {
                 SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
-                SDL_SendMouseMotion(data->window, mouseID, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+                int x = GET_X_LPARAM(lParam);
+                int y = GET_Y_LPARAM(lParam);
+
+                WIN_PhysicalToVirtual_ClientPoint(data->window, &x, &y);
+
+                SDL_SendMouseMotion(data->window, mouseID, 0, x, y);
             }
         }
         /* don't break here, fall through to check the wParam like the button presses */
@@ -690,8 +719,6 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             int w, h;
             int min_w, min_h;
             int max_w, max_h;
-            int style;
-            BOOL menu;
             BOOL constrain_max_size;
 
             if (SDL_IsShapedWindow(data->window))
@@ -712,6 +739,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
             SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
 
+            /* Convert w, h, min_w, min_h, max_w, max_h to unscaled.
+               We can treat them as a point in the client area. */
+            WIN_VirtualToPhysical_ClientPoint(data->window, &w, &h);
+            WIN_VirtualToPhysical_ClientPoint(data->window, &min_w, &min_h);
+            WIN_VirtualToPhysical_ClientPoint(data->window, &max_w, &max_h);
+
             /* Store in min_w and min_h difference between current size and minimal
                size so we don't need to call AdjustWindowRectEx twice */
             min_w -= w;
@@ -729,14 +762,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             size.bottom = h;
             size.right = w;
 
-            style = GetWindowLong(hwnd, GWL_STYLE);
-            /* DJM - according to the docs for GetMenu(), the
-               return value is undefined if hwnd is a child window.
-               Apparently it's too difficult for MS to check
-               inside their function, so I have to do it here.
-             */
-            menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
-            AdjustWindowRectEx(&size, style, menu, 0);
+            WIN_AdjustRect(data->window, &size);
             w = size.right - size.left;
             h = size.bottom - size.top;
 
@@ -791,10 +817,14 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
             x = rect.left;
             y = rect.top;
+            WIN_PhysicalToVirtual_ScreenPoint(&x, &y, data->window->w, data->window->h);
+
             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
 
             w = rect.right - rect.left;
             h = rect.bottom - rect.top;
+            WIN_PhysicalToVirtual_ClientPoint(data->window, &w, &h);
+
             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
                                 h);
 
@@ -964,7 +994,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             if (window->hit_test) {
                 POINT winpoint = { (int) LOWORD(lParam), (int) HIWORD(lParam) };
                 if (ScreenToClient(hwnd, &winpoint)) {
-                    const SDL_Point point = { (int) winpoint.x, (int) winpoint.y };
+                    int x = (int) winpoint.x;
+                    int y = (int) winpoint.y;
+                    WIN_PhysicalToVirtual_ClientPoint(data->window, &x, &y);
+                    const SDL_Point point = { x, y };
                     const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
                     switch (rc) {
                         #define POST_HIT_TEST(ret) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return ret; }
@@ -986,6 +1019,61 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         }
         break;
 
+    case WM_DPICHANGED:
+
+        if (data->videodata->highdpi_enabled)
+        {
+            const int newDPI = HIWORD(wParam);
+            RECT* const suggestedRect = (RECT*)lParam;
+            RECT size;
+            int w, h;
+
+#ifdef HIGHDPI_DEBUG
+            SDL_Log("WM_DPICHANGED: new DPI: %d suggested rect: (%d, %d), (%dx%d)\n", newDPI, suggestedRect->left, suggestedRect->top, suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top);
+#endif
+
+            /* update the cached DPI value for this window */
+            data->scaling_dpi = newDPI;
+
+            /* Example code for hanling WM_DPICHANGED usually just calls SetWindowPos with the 
+               values from suggestedRect, but this preserves the apparent size of the window rect,
+               whereas we want to preserve the apparent size of the client rect.
+
+               Instead, we'll use the left/top of suggestedRect as provided, but
+               calculate the width/height ourselves such that the apparent size
+               of the client rect remains the same. 
+            */
+            w = data->window->w;
+            h = data->window->h;
+            WIN_VirtualToPhysical_ClientPoint(data->window, &w, &h);
+
+            size.top = 0;
+            size.left = 0;
+            size.bottom = h;
+            size.right = w;
+            WIN_AdjustRect(data->window, &size);
+
+            w = size.right - size.left;
+            h = size.bottom - size.top;
+
+#ifdef HIGHDPI_DEBUG
+            SDL_Log("WM_DPICHANGED: calling SetWindowPos: (%d, %d), (%dx%d)\n", suggestedRect->left, suggestedRect->top, w, h);
+#endif
+
+            data->expected_resize = SDL_TRUE;
+            SetWindowPos(hwnd,
+                NULL,
+                suggestedRect->left,
+                suggestedRect->top,
+                w,
+                h,
+                SWP_NOZORDER | SWP_NOACTIVATE);
+            data->expected_resize = SDL_FALSE;
+
+            /* FIXME: Deliver a SDL event saying the framebuffer size changed */
+            return 0;
+        }
+        break;
     }
 
     /* If there's a window proc, assume it's going to handle messages */
diff --git a/src/video/windows/SDL_windowsmodes.c b/src/video/windows/SDL_windowsmodes.c
index b227678..69e45a9 100644
--- a/src/video/windows/SDL_windowsmodes.c
+++ b/src/video/windows/SDL_windowsmodes.c
@@ -318,11 +318,20 @@ int
 WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
 {
     SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata;
+    SDL_VideoData *vid_data = (SDL_VideoData *)_this->driverdata;
+
 
     rect->x = (int)SDL_ceil(data->DeviceMode.dmPosition.x * data->ScaleX);
     rect->y = (int)SDL_ceil(data->DeviceMode.dmPosition.y * data->ScaleY);
-    rect->w = (int)SDL_ceil(data->DeviceMode.dmPelsWidth * data->ScaleX);
-    rect->h = (int)SDL_ceil(data->DeviceMode.dmPelsHeight * data->ScaleY);
+    // NOTE: For high DPI, only the width/height are scaled. This matches what Windows seems to do
+    // to monitor bounds when non-DPI aware applications ask for monitor bounds of a high DPI monitor
+    if (vid_data->highdpi_enabled) {
+        rect->w = (int)SDL_ceil(data->DeviceMode.dmPelsWidth * data->ScaleX * 96.0f / data->HorzDPI);
+        rect->h = (int)SDL_ceil(data->DeviceMode.dmPelsHeight * data->ScaleY * 96.0f / data->VertDPI);
+    } else {
+        rect->w = (int)SDL_ceil(data->DeviceMode.dmPelsWidth * data->ScaleX);
+        rect->h = (int)SDL_ceil(data->DeviceMode.dmPelsHeight * data->ScaleY);
+    }
 
     return 0;
 }
@@ -348,6 +357,7 @@ WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi,
 int
 WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
 {
+    const SDL_VideoData *vid_data = (SDL_VideoData *)_this->driverdata;
     const SDL_DisplayModeData *data = (const SDL_DisplayModeData *) display->current_mode.driverdata;
     const DEVMODE *pDevMode = &data->DeviceMode;
     POINT pt = {
@@ -358,10 +368,9 @@ WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
     HMONITOR hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
     MONITORINFO minfo;
     const RECT *work;
+    const RECT *monitor;
     BOOL rc = FALSE;
 
-    SDL_assert(hmon != NULL);
-
     if (hmon != NULL) {
         SDL_zero(minfo);
         minfo.cbSize = sizeof (MONITORINFO);
@@ -372,12 +381,23 @@ WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
     if (!rc) {
         return SDL_SetError("Couldn't find monitor data");
     }
-
+    
+    monitor = &minfo.rcMonitor;
     work = &minfo.rcWork;
-    rect->x = (int)SDL_ceil(work->left * data->ScaleX);
-    rect->y = (int)SDL_ceil(work->top * data->ScaleY);
-    rect->w = (int)SDL_ceil((work->right - work->left) * data->ScaleX);
-    rect->h = (int)SDL_ceil((work->bottom - work->top) * data->ScaleY);
+    
+    if (vid_data->highdpi_enabled) {
+        // N.B: For x/y, only the _offset_ of the work rect from the monitor's top-left corner is scaled.
+        rect->x = monitor->left + MulDiv(work->left - monitor->left, 96, (int)data->HorzDPI);
+        rect->y = monitor->top + MulDiv(work->top - monitor->top, 96, (int)data->VertDPI);
+        // Width/height are scaled normally
+        rect->w = MulDiv(work->right - work->left, 96, (int)data->HorzDPI);
+        rect->h = MulDiv(work->bottom - work->top, 96, (int)data->VertDPI);
+    } else {
+        rect->x = (int)SDL_ceil(work->left * data->ScaleX);
+        rect->y = (int)SDL_ceil(work->top * data->ScaleY);
+        rect->w = (int)SDL_ceil((work->right - work->left) * data->ScaleX);
+        rect->h = (int)SDL_ceil((work->bottom - work->top) * data->ScaleY);
+    }
 
     return 0;
 }
diff --git a/src/video/windows/SDL_windowsopengl.c b/src/video/windows/SDL_windowsopengl.c
index ffa6c2b..bc9de74 100644
--- a/src/video/windows/SDL_windowsopengl.c
+++ b/src/video/windows/SDL_windowsopengl.c
@@ -794,6 +794,12 @@ WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
     return 0;
 }
 
+void
+WIN_GL_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
+{
+    WIN_GetDrawableSize(window, w, h);
+}
+
 int
 WIN_GL_SetSwapInterval(_THIS, int interval)
 {
diff --git a/src/video/windows/SDL_windowsopengl.h b/src/video/windows/SDL_windowsopengl.h
index de0a1c7..a2fe6a8 100644
--- a/src/video/windows/SDL_windowsopengl.h
+++ b/src/video/windows/SDL_windowsopengl.h
@@ -69,6 +69,7 @@ extern int WIN_GL_SetupWindow(_THIS, SDL_Window * window);
 extern SDL_GLContext WIN_GL_CreateContext(_THIS, SDL_Window * window);
 extern int WIN_GL_MakeCurrent(_THIS, SDL_Window * window,
                               SDL_GLContext context);
+extern void WIN_GL_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h);
 extern int WIN_GL_SetSwapInterval(_THIS, int interval);
 extern int WIN_GL_GetSwapInterval(_THIS);
 extern int WIN_GL_SwapWindow(_THIS, SDL_Window * window);
diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c
index 4b180c3..a69c83e 100644
--- a/src/video/windows/SDL_windowsvideo.c
+++ b/src/video/windows/SDL_windowsvideo.c
@@ -113,11 +113,17 @@ WIN_CreateDevice(int devindex)
         data->CloseTouchInputHandle = (BOOL (WINAPI *)(HTOUCHINPUT)) SDL_LoadFunction(data->userDLL, "CloseTouchInputHandle");
         data->GetTouchInputInfo = (BOOL (WINAPI *)(HTOUCHINPUT, UINT, PTOUCHINPUT, int)) SDL_LoadFunction(data->userDLL, "GetTouchInputInfo");
         data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG)) SDL_LoadFunction(data->userDLL, "RegisterTouchWindow");
+        data->SetProcessDPIAware = (BOOL (WINAPI *)(void)) SDL_LoadFunction(data->userDLL, "SetProcessDPIAware");
+        data->SetProcessDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT)) SDL_LoadFunction(data->userDLL, "SetProcessDpiAwarenessContext");
+        data->EnableNonClientDpiScaling = (BOOL (WINAPI *)(HWND)) SDL_LoadFunction(data->userDLL, "EnableNonClientDpiScaling");
+        data->AdjustWindowRectExForDpi = (BOOL (WINAPI *)(LPRECT, DWORD, BOOL, DWORD, UINT)) SDL_LoadFunction(data->userDLL, "AdjustWindowRectExForDpi");
+        data->GetDpiForWindow = (UINT (WINAPI *)(HWND)) SDL_LoadFunction(data->userDLL, "GetDpiForWindow");
     }
 
     data->shcoreDLL = SDL_LoadObject("SHCORE.DLL");
     if (data->shcoreDLL) {
         data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *)) SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor");
+        data->SetProcessDpiAwareness = (HRESULT (WINAPI *)(PROCESS_DPI_AWARENESS)) SDL_LoadFunction(data->shcoreDLL, "SetProcessDpiAwareness");
     }
 
     /* Set the function pointers */
@@ -168,6 +174,7 @@ WIN_CreateDevice(int devindex)
     device->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
     device->GL_CreateContext = WIN_GL_CreateContext;
     device->GL_MakeCurrent = WIN_GL_MakeCurrent;
+    device->GL_GetDrawableSize = WIN_GL_GetDrawableSize;
     device->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
     device->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
     device->GL_SwapWindow = WIN_GL_SwapWindow;
@@ -205,6 +212,36 @@ VideoBootStrap WINDOWS_bootstrap = {
 int
 WIN_VideoInit(_THIS)
 {
+    SDL_VideoData *data = SDL_static_cast(SDL_VideoData *, _this->driverdata);
+
+    /* Set the process DPI awareness */
+    if (SDL_GetHintBoolean(SDL_HINT_VIDEO_HIGHDPI_ENABLED, SDL_FALSE)) {
+        /* Set this flag to indicate that the application requested DPI awareness.
+           
+           We don't want to change behaviour of apps that were requesting DPI awareness
+           from Windows, but assumed SDL was non-DPI-aware. So, only enable DPI-awareness
+           codepaths if the application explicitly set the SDL_HINT_VIDEO_HIGHDPI_ENABLED hint.
+        */
+        data->highdpi_enabled = SDL_TRUE;
+
+        if (data->SetProcessDpiAwarenessContext) {
+            /* Windows 10 Anniversary Update+ */
+            BOOL result;
+
+            /* First, try the Windows 10 Creators Update version */
+            result = data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
+            if (!result) {
+                result = data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
+            }
+        } else if (data->SetProcessDpiAwareness) {
+            /* Windows 8.1+ */
+            HRESULT result = data->SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
+        } else if (data->SetProcessDPIAware) {
+            /* Vista+ */
+            BOOL success = data->SetProcessDPIAware();
+        }
+    }
+
     if (WIN_InitModes(_this) < 0) {
         return -1;
     }
diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h
index d3061c6..5cc026e 100644
--- a/src/video/windows/SDL_windowsvideo.h
+++ b/src/video/windows/SDL_windowsvideo.h
@@ -85,8 +85,32 @@ typedef enum MONITOR_DPI_TYPE {
     MDT_DEFAULT = MDT_EFFECTIVE_DPI
 } MONITOR_DPI_TYPE;
 
+typedef enum PROCESS_DPI_AWARENESS {
+    PROCESS_DPI_UNAWARE = 0,
+    PROCESS_SYSTEM_DPI_AWARE = 1,
+    PROCESS_PER_MONITOR_DPI_AWARE = 2
+} PROCESS_DPI_AWARENESS;
+
 #endif /* WINVER < 0x0603 */
 
+/* Windows 10 Anniversary Update */
+#if NTDDI_VERSION < 0x0A000002
+
+DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
+
+#define DPI_AWARENESS_CONTEXT_UNAWARE           ((DPI_AWARENESS_CONTEXT)-1)
+#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE      ((DPI_AWARENESS_CONTEXT)-2)
+#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
+
+#endif /* NTDDI_VERSION < 0x0A000002 */
+
+/* Windows 10 Creators Update */
+#if NTDDI_VERSION < 0x0A000003
+
+#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4)
+
+#endif /* NTDDI_VERSION < 0x0A000003 */
+
 typedef BOOL  (*PFNSHFullScreen)(HWND, DWORD);
 typedef void  (*PFCoordTransform)(SDL_Window*, POINT*);
 
@@ -134,13 +158,21 @@ typedef struct SDL_VideoData
     BOOL (WINAPI *CloseTouchInputHandle)( HTOUCHINPUT );
     BOOL (WINAPI *GetTouchInputInfo)( HTOUCHINPUT, UINT, PTOUCHINPUT, int );
     BOOL (WINAPI *RegisterTouchWindow)( HWND, ULONG );
+    BOOL (WINAPI *SetProcessDPIAware)( void );
+    BOOL (WINAPI *SetProcessDpiAwarenessContext)( DPI_AWARENESS_CONTEXT );
+    BOOL (WINAPI *EnableNonClientDpiScaling)( HWND );
+    BOOL (WINAPI *AdjustWindowRectExForDpi)( LPRECT, DWORD, BOOL, DWORD, UINT );
+    UINT (WINAPI *GetDpiForWindow)( HWND );
 
     void* shcoreDLL;
     HRESULT (WINAPI *GetDpiForMonitor)( HMONITOR         hmonitor,
                                         MONITOR_DPI_TYPE dpiType,
                                         UINT             *dpiX,
                                         UINT             *dpiY );
-    
+    HRESULT (WINAPI *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS dpiAwareness);
+
+    SDL_bool highdpi_enabled;
+
     SDL_bool ime_com_initialized;
     struct ITfThreadMgr *ime_threadmgr;
     SDL_bool ime_initialized;
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 6288f8a..a3bc25a 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -84,9 +84,7 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
     HWND hwnd = data->hwnd;
     RECT rect;
-    DWORD style;
     HWND top;
-    BOOL menu;
     int x, y;
     int w, h;
 
@@ -96,23 +94,107 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
     } else {
         top = HWND_NOTOPMOST;
     }
-    style = GetWindowLong(hwnd, GWL_STYLE);
-    rect.left = 0;
-    rect.top = 0;
-    rect.right = window->w;
-    rect.bottom = window->h;
-    menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
-    AdjustWindowRectEx(&rect, style, menu, 0);
-    w = (rect.right - rect.left);
-    h = (rect.bottom - rect.top);
-    x = window->x + rect.left;
-    y = window->y + rect.top;
+
+    /* The SetWindowPos we are going to do might move the window to a new monitor
+       with a different DPI.
+
+       Calculate the new "physical" screen space position from SDL "virtual" screen coordinates
+       without using any information about the current state of the window;
+       this is a best-effort conversion, because depending on the size of the
+       window and what monitors it touches, we can't tell exactly what
+       monitor Windows will decide it belongs to.
+    
+       Calculate the new width/height in pixels assuming the destination monitor
+       will have the same DPI as the current one. If it doesn't, the WM_DPICHANGED 
+       will correct the size in pixels.
+    */
+    x = window->x;
+    y = window->y;
+    WIN_VirtualToPhysical_ScreenPoint(&x, &y, window->w, window->h);
+
+    w = data->window->w;
+    h = data->window->h;
+    WIN_VirtualToPhysical_ClientPoint(data->window, &w, &h);
+
+    rect.left = x;
+    rect.top = y;
+    rect.right = x + w;
+    rect.bottom = y + h;
+    WIN_AdjustRect(window, &rect);
 
     data->expected_resize = SDL_TRUE;
-    SetWindowPos(hwnd, top, x, y, w, h, flags);
+    SetWindowPos(hwnd, top, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags);
     data->expected_resize = SDL_FALSE;
 }
 
+static UINT
+WIN_DPIForHWND(const SDL_VideoData *videodata, HWND hwnd)
+{
+    if (!videodata->highdpi_enabled)
+        return 96;
+
+    // window 10+
+    if (videodata->GetDpiForWindow) { 
+        return videodata->GetDpiForWindow(hwnd);
+    }
+
+    // window 8.1+
+    if (videodata->GetDpiForMonitor) {
+        HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+        if (monitor) {
+            UINT xdpi, ydpi;
+            if (S_OK == videodata->GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi)) {
+                return xdpi;
+            }
+        }
+    }
+
+    // windows 8.0 and below
+    {
+        HDC hdc = GetDC(NULL);
+        if (hdc) {
+            UINT dpi = GetDeviceCaps(hdc, LOGPIXELSX);
+            ReleaseDC(NULL, hdc);
+            return dpi;
+        }
+    }
+
+    return 96;
+}
+
+static void
+WIN_AdjustRectForStyle(const SDL_Window * window, DWORD style, LPRECT rect)
+{
+    const SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+    HWND hwnd = data->hwnd;
+    BOOL menu;
+
+    /* DJM - according to the docs for GetMenu(), the
+    return value is undefined if hwnd is a child window.
+    Apparently it's too difficult for MS to check
+    inside their function, so I have to do it here.
+    */
+    menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
+    if (data->videodata->highdpi_enabled && data->videodata->AdjustWindowRectExForDpi) {
+        data->videodata->AdjustWindowRectExForDpi(rect, style, menu, 0, data->scaling_dpi);
+    } else {
+        AdjustWindowRectEx(rect, style, menu, 0);
+    }
+}
+
+void 
+WIN_AdjustRect(const SDL_Window * window, LPRECT rect)
+{
+    const SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+    HWND hwnd = data->hwnd;
+    DWORD style;
+
+    /* Figure out what the window area will be */
+    style = GetWindowLong(hwnd, GWL_STYLE);
+
+    WIN_AdjustRectForStyle(window, style, rect);
+}
+
 static int
 SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
 {
@@ -132,6 +214,7 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
     data->mouse_button_flags = 0;
     data->videodata = videodata;
     data->initializing = SDL_TRUE;
+    data->scaling_dpi = WIN_DPIForHWND(videodata, hwnd);
 
     window->driverdata = data;
 
@@ -159,34 +242,37 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
     }
 #endif
 
+    /* Move window to the correct monitor and size it */
+    WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOACTIVATE);
+
     /* Fill in the SDL window with the window data */
     {
         RECT rect;
         if (GetClientRect(hwnd, &rect)) {
             int w = rect.right;
             int h = rect.bottom;
+            WIN_PhysicalToVirtual_ClientPoint(window, &w, &h);
             if ((window->w && window->w != w) || (window->h && window->h != h)) {
                 /* We tried to create a window larger than the desktop and Windows didn't allow it.  Override! */
                 RECT rect;
-                DWORD style;
-                BOOL menu;
                 int x, y;
-                int w, h;
 
                 /* Figure out what the window area will be */
-                style = GetWindowLong(hwnd, GWL_STYLE);
-                rect.left = 0;
-                rect.top = 0;
-                rect.right = window->w;
-                rect.bottom = window->h;
-                menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
-                AdjustWindowRectEx(&rect, style, menu, 0);
-                w = (rect.right - rect.left);
-                h = (rect.bottom - rect.top);
-                x = window->x + rect.left;
-                y = window->y + rect.top;
-
-                SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
+                x = window->x;
+                y = window->y;
+                WIN_VirtualToPhysical_ScreenPoint(&x, &y, window->w, window->h);
+
+                w = window->w;
+                h = window->h;
+                WIN_VirtualToPhysical_ClientPoint(window, &w, &h);
+                
+                rect.left = x;
+                rect.top = y;
+                rect.right = x + w;
+                rect.bottom = y + h;
+                WIN_AdjustRect(window, &rect);
+
+                SetWindowPos(hwnd, HWND_NOTOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
             } else {
                 window->w = w;
                 window->h = h;
@@ -198,8 +284,11 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
         point.x = 0;
         point.y = 0;
         if (ClientToScreen(hwnd, &point)) {
-            window->x = point.x;
-            window->y = point.y;
+            int x = point.x;
+            int y = point.y;
+            WIN_PhysicalToVirtual_ScreenPoint(&x, &y, window->w, window->h);
+            window->x = x;
+            window->y = y;
         }
     }
     {
@@ -263,32 +352,19 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
     return 0;
 }
 
-
-
 int
 WIN_CreateWindow(_THIS, SDL_Window * window)
 {
     HWND hwnd;
-    RECT rect;
     DWORD style = STYLE_BASIC;
-    int x, y;
-    int w, h;
 
     style |= GetWindowStyle(window);
 
-    /* Figure out what the window area will be */
-    rect.left = window->x;
-    rect.top = window->y;
-    rect.right = window->x + window->w;
-    rect.bottom = window->y + window->h;
-    AdjustWindowRectEx(&rect, style, FALSE, 0);
-    x = rect.left;
-    y = rect.top;
-    w = (rect.right - rect.left);
-    h = (rect.bottom - rect.top);
-
+    /* For high-DPI support, it's easier / more robust to create the window
+       with a width/height of 0, then in SetupWindowData we will check the
+       DPI and adjust the position and size to match window->x,y,w,h */
     hwnd =
-        CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, NULL, NULL,
+        CreateWindow(SDL_Appname, TEXT(""), style, CW_USEDEFAULT, 0, 0, 0, NULL, NULL,
                      SDL_Instance, NULL);
     if (!hwnd) {
         return WIN_SetError("Couldn't create window");
@@ -556,7 +632,6 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
     SDL_Rect bounds;
     DWORD style;
     HWND top;
-    BOOL menu;
     int x, y;
     int w, h;
 
@@ -573,11 +648,19 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
     WIN_GetDisplayBounds(_this, display, &bounds);
 
     if (fullscreen) {
+		float xdpi, ydpi;
+
         x = bounds.x;
         y = bounds.y;
         w = bounds.w;
         h = bounds.h;
 
+		// convert from scaled to unscaled
+		if (0 == WIN_GetDisplayDPI(_this, display, NULL, &xdpi, &ydpi)) {
+			w = MulDiv(w, (int)xdpi, 96);
+			h = MulDiv(h, (int)ydpi, 96);
+		}
+
         /* Unset the maximized flag.  This fixes
            https://bugzilla.libsdl.org/show_bug.cgi?id=3215
         */
@@ -596,16 +679,24 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
             style |= WS_MAXIMIZE;
             data->windowed_mode_was_maximized = SDL_FALSE;
         }
-        rect.left = 0;
-        rect.top = 0;
-        rect.right = window->windowed.w;
-        rect.bottom = window->windowed.h;
-        menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
-        AdjustWindowRectEx(&rect, style, menu, 0);
+        w = window->windowed.w;
+        h = window->windowed.h;
+        WIN_VirtualToPhysical_ClientPoint(window, &w, &h);
+
+        x = window->windowed.x;
+        y = window->windowed.y;
+        WIN_VirtualToPhysical_ScreenPoint(&x, &y, window->windowed.w, window->windowed.h);
+
+        rect.left = x;
+        rect.top = y;
+        rect.right = x + w;
+        rect.bottom = y + h;
+        WIN_AdjustRectForStyle(window, style, &rect);
+
+        x = rect.left;
+        y = rect.top;
         w = (rect.right - rect.left);
         h = (rect.bottom - rect.top);
-        x = window->windowed.x + rect.left;
-        y = window->windowed.y + rect.top;
     }
     SetWindowLong(hwnd, GWL_STYLE, style);
     data->expected_resize = SDL_TRUE;
@@ -894,6 +985,156 @@ WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
     return 0;
 }
 
+void
+WIN_GetDrawableSize(const SDL_Window *window, int *w, int *h)
+{
+    const SDL_WindowData *data = ((SDL_WindowData *)window->driverdata);
+
+    *w = MulDiv(window->w, data->scaling_dpi, 96);
+    *h = MulDiv(window->h, data->scaling_dpi, 96);
+}
+
+void
+WIN_PhysicalToVirtual_ClientPoint(const SDL_Window *window, int *x, int *y)
+{
+    const SDL_WindowData *data = ((SDL_WindowData *)window->driverdata);
+
+    *x = MulDiv(*x, 96, data->scaling_dpi);
+    *y = MulDiv(*y, 96, data->scaling_dpi);
+}
+
+void
+WIN_VirtualToPhysical_ClientPoint(const SDL_Window *window, int *x, int *y)
+{
+    const SDL_WindowData *data = ((SDL_WindowData *)window->driverdata);
+
+    *x = MulDiv(*x, data->scaling_dpi, 96);
+    *y = MulDiv(*y, data->scaling_dpi, 96);
+}
+
+/* Given a point in screen coordinates (they're interpreted as Windows coordinates)
+   tries to guess what DPI and which monitor Windows would assign a window located there.
+
+   If the system has a uniform DPI value on all monitors (or DPI awareness is disabled),
+   sets `uniformDPI` to SDL_TRUE and returns the value in `dpi`.
+
+   Otherwise, `uniformDPI` is set to SDL_FALSE and the DPI and rects are returned.
+*/
+static void
+WIN_DPIAtScreenPoint(int x, int y, int widthHint, int heightHint, UINT *dpi, RECT *monRectScaled, RECT *monRectUnscaled, SDL_bool *uniformDPI)
+{
+    HMONITOR monitor = NULL;
+    HRESULT result;
+    MONITORINFO moninfo = { 0 };
+    const SDL_VideoData *videodata;
+    const SDL_VideoDevice *videodevice;
+    RECT clientRect;
+    UINT unused;
+    int w, h;
+
+    /* non-DPI-aware return values */
+    *uniformDPI = SDL_TRUE;
+    *dpi = 96;
+
+    videodevice = SDL_GetVideoDevice();
+    if (!videodevice || !videodevice->driverdata)
+        return;
+
+    videodata = (SDL_VideoData *)videodevice->driverdata;
+    if (!videodata->highdpi_enabled)
+        return;
+
+    /* Check for Windows < 8.1*/
+    if (!videodata->GetDpiForMonitor) {
+        HDC hdc = GetDC(NULL);
+        if (hdc) {
+            *dpi = GetDeviceCaps(hdc, LOGPIXELSX);
+            ReleaseDC(NULL, hdc);
+        }
+        return;
+    }
+    
+    /* General case: Windows 8.1+ */
+
+    clientRect.left = x;
+    clientRect.top = y;
+    clientRect.right = x + widthHint;
+    clientRect.bottom = y + heightHint;
+
+    monitor = MonitorFromRect(&clientRect, MONITOR_DEFAULTTONEAREST);
+
+    result = videodata->GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, dpi, &unused);
+    if (result != S_OK) {
+        /* Shouldn't happen? */
+        *dpi = 96;
+        return;
+    }
+
+    moninfo.cbSize = sizeof(MONITORINFO);
+    if (!GetMonitorInfo(monitor, &moninfo)) {
+        /* Shouldn't happen? */
+        *dpi = 96;
+        return;
+    }
+
+    *uniformDPI = SDL_FALSE;
+    *monRectUnscaled = moninfo.rcMonitor;
+    *monRectScaled = moninfo.rcMonitor;
+
+    /* fix up the right/bottom of the scaled rect */
+    w = moninfo.rcMonitor.right - moninfo.rcMonitor.left;
+    h = moninfo.rcMonitor.bottom - moninfo.rcMonitor.top;
+    w = MulDiv(w, 96, *dpi);
+    h = MulDiv(h, 96, *dpi);
+
+    monRectScaled->right = monRectScaled->left + w;
+    monRectScaled->bottom = monRectScaled->top + h;
+}
+
+/* Convert an SDL to a Windows screen coordinate. */
+void WIN_VirtualToPhysical_ScreenPoint(int *x, int *y, int widthHint, int heightHint)
+{
+    RECT monitorRectScaled, monitorRectUnscaled;
+    UINT dpi;
+    SDL_bool uniformDPI;
+
+    WIN_DPIAtScreenPoint(*x, *y, widthHint, heightHint, &dpi, &monitorRectScaled, &monitorRectUnscaled, &uniformDPI);
+
+    if (uniformDPI) {
+        *x = MulDiv(*x, dpi, 96);
+        *y = MulDiv(*y, dpi, 96);
+        return;
+    }
+
+    *x = monitorRectScaled.left + MulDiv(*x - monitorRectScaled.left, dpi, 96);
+    *y = monitorRectScaled.top + MulDiv(*y - monitorRectScaled.top, dpi, 96);
+
+    /* ensure the result is not past the right/bottom of the monitor rect */
+    if (*x >= monitorRectUnscaled.right) 
+        *x = monitorRectUnscaled.right - 1;
+    if (*y >= monitorRectUnscaled.bottom) 
+        *y = monitorRectUnscaled.bottom - 1;
+}
+
+/* Converts a Windows screen coordinate to an SDL one. */
+void WIN_PhysicalToVirtual_ScreenPoint(int *x, int *y, int widthHint, int heightHint)
+{
+    RECT monitorRectScaled, monitorRectUnscaled;
+    UINT dpi;
+    SDL_bool uniformDPI;
+
+    WIN_DPIAtScreenPoint(*x, *y, widthHint, heightHint, &dpi, &monitorRectScaled, &monitorRectUnscaled, &uniformDPI);
+
+    if (uniformDPI) {
+        *x = MulDiv(*x, 96, dpi);
+        *y = MulDiv(*y, 96, dpi);
+        return;
+    }
+
+    *x = monitorRectUnscaled.left + MulDiv(*x - monitorRectUnscaled.left, 96, dpi);
+    *y = monitorRectUnscaled.top + MulDiv(*y - monitorRectUnscaled.top, 96, dpi);
+}
+
 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
 
 /* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h
index 180cb8a..d2f9da7 100644
--- a/src/video/windows/SDL_windowswindow.h
+++ b/src/video/windows/SDL_windowswindow.h
@@ -49,6 +49,7 @@ typedef struct
 #if SDL_VIDEO_OPENGL_EGL  
     EGLSurface egl_surface;
 #endif
+    int scaling_dpi;
 } SDL_WindowData;
 
 extern int WIN_CreateWindow(_THIS, SDL_Window * window);
@@ -76,6 +77,12 @@ extern SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window * window,
 extern void WIN_OnWindowEnter(_THIS, SDL_Window * window);
 extern void WIN_UpdateClipCursor(SDL_Window *window);
 extern int WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
+extern void WIN_GetDrawableSize(const SDL_Window *window, int *w, int *h);
+extern void WIN_PhysicalToVirtual_ClientPoint(const SDL_Window *window, int *w, int *h);
+extern void WIN_VirtualToPhysical_ClientPoint(const SDL_Window *window, int *w, int *h);
+extern void WIN_VirtualToPhysical_ScreenPoint(int *x, int *y, int widthHint, int heightHint);
+extern void WIN_PhysicalToVirtual_ScreenPoint(int *x, int *y, int widthHint, int heightHint);
+extern void WIN_AdjustRect(const SDL_Window *window, LPRECT rect);
 
 #endif /* _SDL_windowswindow_h */
 
