[gtk+] GDK-Win32/4.0: Enable HiDPI support for Windows



commit 6abd65c83be6ba4656c5f014bc940c2eea21dfd0
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Mon Jun 27 13:16:43 2016 +0800

    GDK-Win32/4.0: Enable HiDPI support for Windows
    
    This enables HiDPI support for GTK+ on Windows, so that the
    fonts and window look better on HiDPI displays.  Notes for the current
    work:
    
    -The DPI awareness enabling can be disabled if and only if an application
     manifest is not embedded in the app to enable DPI awareness AND a user
     compatibility setting is not set to limit DPI awareness for the app, via
     the envvar GDK_WIN32_DISABLE_HIDPI.  The app manifest/user setting for
     DPI awareness will always win against the envvar, and so the HiDPI items
     will be always setup in such scenarios, unless DPI awareness is disabled.
    
    -Both automatic detection for the scaling factor and setting the scale
     factor using the GDK_SCALE envvar are supported, where the envvar takes
     precedence, which will therefore disable automatic scaling when
     resolution changes.
    
    -We now default to a per-system DPI awareness model, which means that we
     do not handle WM_DPICHANGED, unless one sets the
     GDK_WIN32_PER_MONITOR_HIDPI envvar, where notes for it are in the
     following point.
    
    -Automatic scaling during WM_DISPLAYCHANGE is handled (DPI setting change of
     current monitor) is now supported.  WM_DPICHANGED is handled as well,
     except that the window positioning during the change of scaling still
     needs to be refined, a change in GDK itself may be required for this.
    
    -I am unable to test the wintab items because I don't have such devices
     around.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=768081

 gdk/win32/gdkdevice-win32.c        |   26 +-
 gdk/win32/gdkdevice-wintab.c       |   10 +-
 gdk/win32/gdkdevicemanager-win32.c |   11 +-
 gdk/win32/gdkdisplay-win32.c       |  338 +++++++++++++++++++++
 gdk/win32/gdkdisplay-win32.h       |   47 +++
 gdk/win32/gdkevents-win32.c        |  191 +++++++++----
 gdk/win32/gdkgeometry-win32.c      |   33 ++-
 gdk/win32/gdkmain-win32.c          |    1 +
 gdk/win32/gdkmonitor-win32.c       |   18 +-
 gdk/win32/gdkprivate-win32.h       |   12 +-
 gdk/win32/gdkscreen-win32.c        |   72 +++--
 gdk/win32/gdkwindow-win32.c        |  575 +++++++++++++++++++++++-------------
 gdk/win32/gdkwindow-win32.h        |   15 +
 13 files changed, 1027 insertions(+), 322 deletions(-)
---
diff --git a/gdk/win32/gdkdevice-win32.c b/gdk/win32/gdkdevice-win32.c
index 94da520..190372d 100644
--- a/gdk/win32/gdkdevice-win32.c
+++ b/gdk/win32/gdkdevice-win32.c
@@ -111,25 +111,27 @@ gdk_device_win32_query_state (GdkDevice        *device,
   GdkScreen *screen;
   POINT point;
   HWND hwnd, hwndc;
+  GdkWindowImplWin32 *impl;
 
   screen = gdk_window_get_screen (window);
+  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   hwnd = GDK_WINDOW_HWND (window);
   GetCursorPos (&point);
 
   if (root_x)
-    *root_x = point.x;
+    *root_x = point.x / impl->window_scale;
 
   if (root_y)
-    *root_y = point.y;
+    *root_y = point.y / impl->window_scale;
 
   ScreenToClient (hwnd, &point);
 
   if (win_x)
-    *win_x = point.x;
+    *win_x = point.x / impl->window_scale;
 
   if (win_y)
-    *win_y = point.y;
+    *win_y = point.y / impl->window_scale;
 
   if (window == gdk_screen_get_root_window (screen))
     {
@@ -197,6 +199,7 @@ _gdk_device_win32_window_at_position (GdkDevice       *device,
                                       gboolean         get_toplevel)
 {
   GdkWindow *window = NULL;
+  GdkWindowImplWin32 *impl = NULL;
   POINT screen_pt, client_pt;
   HWND hwnd, hwndc;
   RECT rect;
@@ -249,12 +252,15 @@ _gdk_device_win32_window_at_position (GdkDevice       *device,
       /* If we didn't hit any window at that point, return the desktop */
       if (hwnd == NULL)
         {
+          window = gdk_get_default_root_window ();
+          impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
           if (win_x)
-            *win_x = screen_pt.x + _gdk_offset_x;
+            *win_x = (screen_pt.x + _gdk_offset_x) / impl->window_scale;
           if (win_y)
-            *win_y = screen_pt.y + _gdk_offset_y;
+            *win_y = (screen_pt.y + _gdk_offset_y) / impl->window_scale;
 
-          return gdk_get_default_root_window ();
+          return window;
         }
 
       window = gdk_win32_handle_table_lookup (hwnd);
@@ -262,10 +268,12 @@ _gdk_device_win32_window_at_position (GdkDevice       *device,
 
   if (window && (win_x || win_y))
     {
+      impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
       if (win_x)
-        *win_x = client_pt.x;
+        *win_x = client_pt.x / impl->window_scale;
       if (win_y)
-        *win_y = client_pt.y;
+        *win_y = client_pt.y / impl->window_scale;
     }
 
   return window;
diff --git a/gdk/win32/gdkdevice-wintab.c b/gdk/win32/gdkdevice-wintab.c
index 18279a8..06037d8 100644
--- a/gdk/win32/gdkdevice-wintab.c
+++ b/gdk/win32/gdkdevice-wintab.c
@@ -121,26 +121,28 @@ gdk_device_wintab_query_state (GdkDevice        *device,
   GdkScreen *screen;
   POINT point;
   HWND hwnd, hwndc;
+  GdkWindowImplWin32 *impl;
 
   device_wintab = GDK_DEVICE_WINTAB (device);
   screen = gdk_window_get_screen (window);
+  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   hwnd = GDK_WINDOW_HWND (window);
   GetCursorPos (&point);
 
   if (root_x)
-    *root_x = point.x;
+    *root_x = point.x / impl->window_scale;
 
   if (root_y)
-    *root_y = point.y;
+    *root_y = point.y / impl->window_scale;
 
   ScreenToClient (hwnd, &point);
 
   if (win_x)
-    *win_x = point.x;
+    *win_x = point.x / impl->window_scale;
 
   if (win_y)
-    *win_y = point.y;
+    *win_y = point.y / impl->window_scale;
 
   if (window == gdk_get_default_root_window ())
     {
diff --git a/gdk/win32/gdkdevicemanager-win32.c b/gdk/win32/gdkdevicemanager-win32.c
index e64c02d..62c164d 100644
--- a/gdk/win32/gdkdevicemanager-win32.c
+++ b/gdk/win32/gdkdevicemanager-win32.c
@@ -889,6 +889,7 @@ gdk_input_other_event (GdkDisplay *display,
   GdkEventMask masktest;
   guint key_state;
   POINT pt;
+  GdkWindowImplWin32 *impl;
 
   PACKET packet;
   gint root_x, root_y;
@@ -1034,15 +1035,17 @@ G_GNUC_END_IGNORE_DEPRECATIONS;
           if (window->parent == gdk_get_default_root_window () || window->parent == NULL)
             return FALSE;
 
-          pt.x = x;
-          pt.y = y;
+          impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+          pt.x = x * impl->window_scale;
+          pt.y = y * impl->window_scale;
           ClientToScreen (GDK_WINDOW_HWND (window), &pt);
           g_object_unref (window);
           window = window->parent;
+          impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
           g_object_ref (window);
           ScreenToClient (GDK_WINDOW_HWND (window), &pt);
-          x = pt.x;
-          y = pt.y;
+          x = pt.x / impl->window_scale;
+          y = pt.y / impl->window_scale;
           GDK_NOTE (EVENTS_OR_INPUT, g_print ("... propagating to %p %+d%+d\n",
                                               GDK_WINDOW_HWND (window), x, y));
         }
diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c
index 0d626c4..8cb0aa0 100644
--- a/gdk/win32/gdkdisplay-win32.c
+++ b/gdk/win32/gdkdisplay-win32.c
@@ -195,6 +195,41 @@ _gdk_win32_display_init_monitors (GdkWin32Display *win32_display)
       changed = TRUE;
     }
 
+  for (i = 0; i < win32_display->monitors->len; i++)
+    {
+      GdkMonitor *monitor;
+      GdkWin32Monitor *win32_monitor;
+
+      monitor = GDK_MONITOR (g_ptr_array_index (win32_display->monitors, i));
+
+      if (win32_display->has_fixed_scale)
+        gdk_monitor_set_scale_factor (monitor, win32_display->window_scale);
+      else
+        {
+          /* First acquire the scale using the current screen */
+          GdkRectangle workarea;
+          POINT pt;
+          guint scale = _gdk_win32_display_get_monitor_scale_factor (win32_display, NULL, NULL, NULL);
+
+          gdk_monitor_get_workarea (monitor, &workarea);
+          workarea.x -= _gdk_offset_x;
+          workarea.y -= _gdk_offset_y;
+          workarea.x += workarea.width / scale;
+          workarea.y += workarea.height / scale;
+          pt.x = workarea.x;
+          pt.y = workarea.y;
+
+          /* acquire the scale using the monitor which the window is nearest on Windows 8.1+ */
+          if (win32_display->have_at_least_win81)
+            {
+              HMONITOR hmonitor = MonitorFromPoint (pt, MONITOR_DEFAULTTONEAREST);
+              scale = _gdk_win32_display_get_monitor_scale_factor (win32_display, hmonitor, NULL, NULL);
+            }
+
+          gdk_monitor_set_scale_factor (monitor, scale);
+        }
+    }
+
   return changed;
 }
 
@@ -789,6 +824,15 @@ gdk_win32_display_dispose (GObject *object)
       _hwnd_next_viewer = NULL;
     }
 
+  if (display_win32->have_at_least_win81)
+    {
+      if (display_win32->shcore_funcs.hshcore != NULL)
+        {
+          FreeLibrary (display_win32->shcore_funcs.hshcore);
+          display_win32->shcore_funcs.hshcore = NULL;
+        }
+    }
+
   G_OBJECT_CLASS (gdk_win32_display_parent_class)->dispose (object);
 }
 
@@ -806,9 +850,220 @@ gdk_win32_display_finalize (GObject *object)
 }
 
 static void
+_gdk_win32_enable_hidpi (GdkWin32Display *display)
+{
+  gboolean check_for_dpi_awareness = FALSE;
+  gboolean have_hpi_disable_envvar = FALSE;
+
+  enum dpi_aware_status {
+    DPI_STATUS_PENDING,
+    DPI_STATUS_SUCCESS,
+    DPI_STATUS_DISABLED,
+    DPI_STATUS_FAILED
+  } status = DPI_STATUS_PENDING;
+
+  if (g_win32_check_windows_version (6, 3, 0, G_WIN32_OS_ANY))
+    {
+      /* If we are on Windows 8.1 or later, cache up functions from shcore.dll, by all means */
+      display->have_at_least_win81 = TRUE;
+      display->shcore_funcs.hshcore = LoadLibraryW (L"shcore.dll");
+
+      if (display->shcore_funcs.hshcore != NULL)
+        {
+          display->shcore_funcs.setDpiAwareFunc =
+            (funcSetProcessDpiAwareness) GetProcAddress (display->shcore_funcs.hshcore,
+                                                         "SetProcessDpiAwareness");
+          display->shcore_funcs.getDpiAwareFunc =
+            (funcGetProcessDpiAwareness) GetProcAddress (display->shcore_funcs.hshcore,
+                                                         "GetProcessDpiAwareness");
+
+          display->shcore_funcs.getDpiForMonitorFunc =
+            (funcGetDpiForMonitor) GetProcAddress (display->shcore_funcs.hshcore,
+                                                   "GetDpiForMonitor");
+        }
+    }
+  else
+    {
+      /* Windows Vista through 8: use functions from user32.dll directly */
+      HMODULE user32;
+
+      display->have_at_least_win81 = FALSE;
+      user32 = GetModuleHandleW (L"user32.dll");
+
+      if (user32 != NULL)
+        {
+          display->user32_dpi_funcs.setDpiAwareFunc =
+            (funcSetProcessDPIAware) GetProcAddress (user32, "SetProcessDPIAware");
+          display->user32_dpi_funcs.isDpiAwareFunc =
+            (funcIsProcessDPIAware) GetProcAddress (user32, "IsProcessDPIAware");
+        }
+    }
+
+  if (g_getenv ("GDK_WIN32_DISABLE_HIDPI") == NULL)
+    {
+      /* For Windows 8.1 and later, use SetProcessDPIAwareness() */
+      if (display->have_at_least_win81)
+        {
+          /* then make the GDK-using app DPI-aware */
+          if (display->shcore_funcs.setDpiAwareFunc != NULL)
+            {
+              GdkWin32ProcessDpiAwareness hidpi_mode;
+
+              /* TODO: See how per-monitor DPI awareness is done by the Wayland backend */
+              if (g_getenv ("GDK_WIN32_PER_MONITOR_HIDPI") != NULL)
+                hidpi_mode = PROCESS_PER_MONITOR_DPI_AWARE;
+              else
+                hidpi_mode = PROCESS_SYSTEM_DPI_AWARE;
+
+              switch (display->shcore_funcs.setDpiAwareFunc (hidpi_mode))
+                {
+                  case S_OK:
+                    display->dpi_aware_type = hidpi_mode;
+                    status = DPI_STATUS_SUCCESS;
+                    break;
+                  case E_ACCESSDENIED:
+                    /* This means the app used a manifest to set DPI awareness, or a
+                       DPI compatibility setting is used.
+                       The manifest is the trump card in this game of bridge here.  The
+                       same applies if one uses the control panel or program properties to
+                       force system DPI awareness */
+                    check_for_dpi_awareness = TRUE;
+                    break;
+                  default:
+                    display->dpi_aware_type = PROCESS_DPI_UNAWARE;
+                    status = DPI_STATUS_FAILED;
+                    break;
+                }
+            }
+
+          /* Should not get here! */
+          if (status == DPI_STATUS_PENDING)
+            {
+              g_assert_not_reached ();
+              display->dpi_aware_type = PROCESS_DPI_UNAWARE;
+              status = DPI_STATUS_FAILED;
+            }
+        }
+      else
+        {
+          /* For Windows Vista through 8, use SetProcessDPIAware() */
+          display->have_at_least_win81 = FALSE;
+          if (display->user32_dpi_funcs.setDpiAwareFunc != NULL)
+            {
+              if (display->user32_dpi_funcs.setDpiAwareFunc () != 0)
+                {
+                  display->dpi_aware_type = PROCESS_SYSTEM_DPI_AWARE;
+                  status = DPI_STATUS_SUCCESS;
+                }
+              else
+                {
+                  check_for_dpi_awareness = TRUE;
+                }
+            }
+          else
+            {
+              display->dpi_aware_type = PROCESS_DPI_UNAWARE;
+              status = DPI_STATUS_FAILED;
+            }
+        }
+    }
+  else
+    {
+      /* if GDK_WIN32_DISABLE_HIDPI is set, check for any DPI
+       * awareness settings done via manifests or user settings
+       */
+      check_for_dpi_awareness = TRUE;
+      have_hpi_disable_envvar = TRUE;
+    }
+
+  if (check_for_dpi_awareness)
+    {
+      if (display->have_at_least_win81)
+        {
+          if (display->shcore_funcs.getDpiAwareFunc != NULL)
+            {
+              display->shcore_funcs.getDpiAwareFunc (NULL, &display->dpi_aware_type);
+
+              if (display->dpi_aware_type != PROCESS_DPI_UNAWARE)
+                status = DPI_STATUS_SUCCESS;
+              else
+                /* This means the DPI awareness setting was forcefully disabled */
+                status = DPI_STATUS_DISABLED;
+            }
+          else
+            {
+              display->dpi_aware_type = PROCESS_DPI_UNAWARE;
+              status = DPI_STATUS_FAILED;
+            }
+        }
+      else
+        {
+          if (display->user32_dpi_funcs.isDpiAwareFunc != NULL)
+            {
+              /* This most probably means DPI awareness is set through
+                 the manifest, or a DPI compatibility setting is used. */
+              display->dpi_aware_type = display->user32_dpi_funcs.isDpiAwareFunc () ?
+                                        PROCESS_SYSTEM_DPI_AWARE :
+                                        PROCESS_DPI_UNAWARE;
+
+              if (display->dpi_aware_type == PROCESS_SYSTEM_DPI_AWARE)
+                status = DPI_STATUS_SUCCESS;
+              else
+                status = DPI_STATUS_DISABLED;
+            }
+          else
+            {
+              display->dpi_aware_type = PROCESS_DPI_UNAWARE;
+              status = DPI_STATUS_FAILED;
+            }
+        }
+      if (have_hpi_disable_envvar &&
+          status == DPI_STATUS_SUCCESS)
+        {
+          /* The user setting or application manifest trumps over GDK_WIN32_DISABLE_HIDPI */
+          g_print ("Note: GDK_WIN32_DISABLE_HIDPI is ignored due to preset\n"
+                   "      DPI awareness settings in user settings or application\n"
+                   "      manifest, DPI awareness is still enabled.");
+        }
+    }
+
+  switch (status)
+    {
+    case DPI_STATUS_SUCCESS:
+      GDK_NOTE (MISC, g_message ("HiDPI support enabled, type: %s",
+                                 display->dpi_aware_type == PROCESS_PER_MONITOR_DPI_AWARE ? "per-monitor" : 
"system"));
+      break;
+    case DPI_STATUS_DISABLED:
+      GDK_NOTE (MISC, g_message ("HiDPI support disabled via manifest"));
+      break;
+    case DPI_STATUS_FAILED:
+      g_warning ("Failed to enable HiDPI support.");
+    }
+}
+
+static void
 gdk_win32_display_init (GdkWin32Display *display)
 {
+  const gchar *scale_str = g_getenv ("GDK_SCALE");
+
   display->monitors = g_ptr_array_new_with_free_func (g_object_unref);
+
+  _gdk_win32_enable_hidpi (display);
+
+  /* if we have DPI awareness, set up fixed scale if set */
+  if (display->dpi_aware_type != PROCESS_DPI_UNAWARE &&
+      scale_str != NULL)
+    {
+      display->window_scale = atol (scale_str);
+
+      if (display->window_scale == 0)
+        display->window_scale = 1;
+
+      display->has_fixed_scale = TRUE;
+    }
+  else
+    display->window_scale = 1;
+
   _gdk_win32_display_init_cursors (display);
   gdk_win32_display_check_composited (display);
 }
@@ -896,6 +1151,89 @@ gdk_win32_display_get_primary_monitor (GdkDisplay *display)
   return NULL;
 }
 
+guint
+_gdk_win32_display_get_monitor_scale_factor (GdkWin32Display *win32_display,
+                                             HMONITOR         hmonitor,
+                                             HWND             hwnd,
+                                             gint            *dpi)
+{
+  gboolean is_scale_acquired = FALSE;
+  gboolean use_dpi_for_monitor = FALSE;
+  guint dpix, dpiy;
+
+  if (win32_display->have_at_least_win81)
+    {
+      if (hmonitor != NULL)
+        use_dpi_for_monitor = TRUE;
+
+      else
+        {
+          if (hwnd != NULL)
+            {
+              hmonitor = MonitorFromWindow (hwnd, MONITOR_DEFAULTTONEAREST);
+              use_dpi_for_monitor = TRUE;
+            }
+        }
+    }
+
+  if (use_dpi_for_monitor)
+    {
+      /* Use GetDpiForMonitor() for Windows 8.1+, when we have a HMONITOR */
+      if (win32_display->shcore_funcs.hshcore != NULL &&
+          win32_display->shcore_funcs.getDpiForMonitorFunc != NULL)
+        {
+          if (win32_display->shcore_funcs.getDpiForMonitorFunc (hmonitor,
+                                                                MDT_EFFECTIVE_DPI,
+                                                                &dpix,
+                                                                &dpiy) == S_OK)
+            {
+              is_scale_acquired = TRUE;
+            }
+        }
+    }
+  else
+    {
+      /* Go back to GetDeviceCaps() for Windows 8 and earler, or when we don't
+       * have a HMONITOR nor a HWND
+       */
+      HDC hdc = GetDC (hwnd);
+
+      /* in case we can't get the DC for the window, return 1 for the scale */
+      if (hdc == NULL)
+        {
+          if (dpi != NULL)
+            *dpi = USER_DEFAULT_SCREEN_DPI;
+
+          return 1;
+        }
+
+      dpix = GetDeviceCaps (hdc, LOGPIXELSX);
+      dpiy = GetDeviceCaps (hdc, LOGPIXELSY);
+      ReleaseDC (hwnd, hdc);
+
+      is_scale_acquired = TRUE;
+    }
+
+  if (is_scale_acquired)
+    /* USER_DEFAULT_SCREEN_DPI = 96, in winuser.h */
+    {
+      if (dpi != NULL)
+        *dpi = dpix;
+
+      if (win32_display->has_fixed_scale)
+        return win32_display->window_scale;
+      else
+        return dpix / USER_DEFAULT_SCREEN_DPI > 1 ? dpix / USER_DEFAULT_SCREEN_DPI : 1;
+    }
+  else
+    {
+      if (dpi != NULL)
+        *dpi = USER_DEFAULT_SCREEN_DPI;
+
+      return 1;
+  }
+}
+
 static void
 gdk_win32_display_class_init (GdkWin32DisplayClass *klass)
 {
diff --git a/gdk/win32/gdkdisplay-win32.h b/gdk/win32/gdkdisplay-win32.h
index e36d8c4..c468a0e 100644
--- a/gdk/win32/gdkdisplay-win32.h
+++ b/gdk/win32/gdkdisplay-win32.h
@@ -22,6 +22,39 @@
 #ifndef __GDK_DISPLAY__WIN32_H__
 #define __GDK_DISPLAY__WIN32_H__
 
+/* Define values used to set DPI-awareness */
+typedef enum _GdkWin32ProcessDpiAwareness {
+  PROCESS_DPI_UNAWARE = 0,
+  PROCESS_SYSTEM_DPI_AWARE = 1,
+  PROCESS_PER_MONITOR_DPI_AWARE = 2
+} GdkWin32ProcessDpiAwareness;
+
+/* APIs from shcore.dll */
+typedef HRESULT (WINAPI *funcSetProcessDpiAwareness) (GdkWin32ProcessDpiAwareness value);
+typedef HRESULT (WINAPI *funcGetProcessDpiAwareness) (HANDLE handle, GdkWin32ProcessDpiAwareness *awareness);
+typedef HRESULT (WINAPI *funcGetDpiForMonitor)       (HMONITOR                monitor,
+                                                      GdkWin32MonitorDpiType  dpi_type,
+                                                      UINT                   *dpi_x,
+                                                      UINT                   *dpi_y);
+
+typedef struct _GdkWin32ShcoreFuncs
+{
+  HMODULE hshcore;
+  funcSetProcessDpiAwareness setDpiAwareFunc;
+  funcGetProcessDpiAwareness getDpiAwareFunc;
+  funcGetDpiForMonitor getDpiForMonitorFunc;
+} GdkWin32ShcoreFuncs;
+
+/* DPI awareness APIs from user32.dll */
+typedef BOOL (WINAPI *funcSetProcessDPIAware) (void);
+typedef BOOL (WINAPI *funcIsProcessDPIAware)  (void);
+
+typedef struct _GdkWin32User32DPIFuncs
+{
+  funcSetProcessDPIAware setDpiAwareFunc;
+  funcIsProcessDPIAware isDpiAwareFunc;
+} GdkWin32User32DPIFuncs;
+
 struct _GdkWin32Display
 {
   GdkDisplay display;
@@ -49,6 +82,15 @@ struct _GdkWin32Display
   guint hasWglOMLSyncControl : 1;
   guint hasWglARBPixelFormat : 1;
   guint hasWglARBmultisample : 1;
+
+  /* HiDPI Items */
+  guint have_at_least_win81 : 1;
+  GdkWin32ProcessDpiAwareness dpi_aware_type;
+  guint has_fixed_scale : 1;
+  guint window_scale;
+
+  GdkWin32ShcoreFuncs shcore_funcs;
+  GdkWin32User32DPIFuncs user32_dpi_funcs;
 };
 
 struct _GdkWin32DisplayClass
@@ -62,4 +104,9 @@ GPtrArray *_gdk_win32_display_get_monitor_list (GdkWin32Display *display);
 
 void        gdk_win32_display_check_composited (GdkWin32Display *display);
 
+guint      _gdk_win32_display_get_monitor_scale_factor (GdkWin32Display *win32_display,
+                                                        HMONITOR         hmonitor,
+                                                        HWND             hwnd,
+                                                        gint             *dpi);
+
 #endif /* __GDK_DISPLAY__WIN32_H__ */
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 411bd0f..3a25348 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -44,9 +44,11 @@
 #include "gdkprivate-win32.h"
 
 #include <glib/gprintf.h>
+#include <cairo-win32.h>
 
 #include "gdk.h"
 #include "gdkdisplayprivate.h"
+#include "gdkmonitorprivate.h"
 #include "gdkwin32.h"
 #include "gdkkeysyms.h"
 #include "gdkdevicemanager-win32.h"
@@ -1059,17 +1061,17 @@ show_window_recurse (GdkWindow *window, gboolean hide_window)
                {
                  if (gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED)
                    {
-                     GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMAXIMIZED);
+                     GtkShowWindow (window, SW_SHOWMAXIMIZED);
                    }
                  else
                    {
-                     GtkShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
+                     GtkShowWindow (window, SW_RESTORE);
                    }
                }
            }
          else
            {
-             GtkShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
+             GtkShowWindow (window, SW_MINIMIZE);
            }
        }
 
@@ -1121,6 +1123,7 @@ send_crossing_event (GdkDisplay                 *display,
   GdkDeviceGrabInfo *grab;
   GdkDeviceManagerWin32 *device_manager;
   POINT pt;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (display));
 
@@ -1142,10 +1145,10 @@ send_crossing_event (GdkDisplay                 *display,
   event->crossing.window = window;
   event->crossing.subwindow = subwindow;
   event->crossing.time = _gdk_win32_get_next_tick (time_);
-  event->crossing.x = pt.x;
-  event->crossing.y = pt.y;
-  event->crossing.x_root = screen_pt->x + _gdk_offset_x;
-  event->crossing.y_root = screen_pt->y + _gdk_offset_y;
+  event->crossing.x = pt.x / impl->window_scale;
+  event->crossing.y = pt.y / impl->window_scale;
+  event->crossing.x_root = (screen_pt->x + _gdk_offset_x) / impl->window_scale;
+  event->crossing.y_root = (screen_pt->y + _gdk_offset_y) / impl->window_scale;
   event->crossing.mode = mode;
   event->crossing.detail = notify_type;
   event->crossing.mode = mode;
@@ -1449,8 +1452,8 @@ _gdk_win32_get_window_rect (GdkWindow *window,
   if (gdk_window_get_parent (window) == gdk_get_default_root_window ())
     {
       ClientToScreen (hwnd, &point);
-      point.x += _gdk_offset_x;
-      point.y += _gdk_offset_y;
+      point.x += _gdk_offset_x * window_impl->window_scale;
+      point.y += _gdk_offset_y * window_impl->window_scale;
     }
 
   rect->left = point.x;
@@ -1465,9 +1468,12 @@ void
 _gdk_win32_do_emit_configure_event (GdkWindow *window,
                                     RECT       rect)
 {
-  window->width = rect.right - rect.left;
-  window->height = rect.bottom - rect.top;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
+  impl->unscaled_width = rect.right - rect.left;
+  impl->unscaled_height = rect.bottom - rect.top;
+  window->width = (impl->unscaled_width + impl->window_scale - 1) / impl->window_scale;
+  window->height = (impl->unscaled_height + impl->window_scale - 1) / impl->window_scale;
   window->x = rect.left;
   window->y = rect.top;
 
@@ -1479,11 +1485,11 @@ _gdk_win32_do_emit_configure_event (GdkWindow *window,
 
       event->configure.window = window;
 
-      event->configure.width = rect.right - rect.left;
-      event->configure.height = rect.bottom - rect.top;
+      event->configure.width = window->width;
+      event->configure.height = window->height;
 
-      event->configure.x = rect.left;
-      event->configure.y = rect.top;
+      event->configure.x = window->x;
+      event->configure.y = window->y;
 
       _gdk_win32_append_event (event);
     }
@@ -1501,7 +1507,8 @@ _gdk_win32_emit_configure_event (GdkWindow *window)
 }
 
 cairo_region_t *
-_gdk_win32_hrgn_to_region (HRGN hrgn)
+_gdk_win32_hrgn_to_region (HRGN  hrgn,
+                           guint scale)
 {
   RGNDATA *rgndata;
   RECT *rects;
@@ -1532,8 +1539,8 @@ _gdk_win32_hrgn_to_region (HRGN hrgn)
 
       r.x = rects[i].left;
       r.y = rects[i].top;
-      r.width = rects[i].right - r.x;
-      r.height = rects[i].bottom - r.y;
+      r.width = (rects[i].right - r.x) / scale;
+      r.height = (rects[i].bottom - r.y) / scale;
 
       cairo_region_union_rectangle (result, &r);
     }
@@ -1562,6 +1569,7 @@ handle_wm_paint (MSG        *msg,
   HDC hdc;
   PAINTSTRUCT paintstruct;
   cairo_region_t *update_region;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   if (GetUpdateRgn (msg->hwnd, hrgn, FALSE) == ERROR)
     {
@@ -1587,7 +1595,7 @@ handle_wm_paint (MSG        *msg,
       return;
     }
 
-  update_region = _gdk_win32_hrgn_to_region (hrgn);
+  update_region = _gdk_win32_hrgn_to_region (hrgn, impl->window_scale);
   if (!cairo_region_is_empty (update_region))
     _gdk_window_invalidate_for_expose (window, update_region);
   cairo_region_destroy (update_region);
@@ -1660,6 +1668,7 @@ handle_nchittest (HWND hwnd,
                   gint *ret_valp)
 {
   RECT rect;
+  GdkWindowImplWin32 *impl;
 
   if (window == NULL || window->input_shape == NULL)
     return FALSE;
@@ -1673,11 +1682,14 @@ handle_nchittest (HWND hwnd,
   if (!GetWindowRect (hwnd, &rect))
     return FALSE;
 
+  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
   rect.left = screen_x - rect.left;
   rect.top = screen_y - rect.top;
 
   /* If it's inside the rect, return FALSE and let DefWindowProc() handle it */
-  if (cairo_region_contains_point (window->input_shape, rect.left, rect.top))
+  if (cairo_region_contains_point (window->input_shape,
+                                   rect.left / impl->window_scale,
+                                   rect.top / impl->window_scale))
     return FALSE;
 
   /* Otherwise override DefWindowProc() and tell WM that the point is not
@@ -1688,6 +1700,67 @@ handle_nchittest (HWND hwnd,
 }
 
 static void
+handle_dpi_changed (GdkWindow *window,
+                    MSG       *msg)
+{
+  HWND hwnd = GDK_WINDOW_HWND (window);
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+  GdkDisplay *display = gdk_display_get_default ();
+  GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
+  GdkScreen *screen = gdk_window_get_screen (window);
+  GdkDevice *device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
+  RECT *rect = (RECT *)msg->lParam;
+  GdkEvent *event;
+  guint old_scale = impl->window_scale;
+
+  /* MSDN for WM_DPICHANGED: dpi_x == dpi_y here, so LOWORD (msg->wParam) == HIWORD (msg->wParam) */
+  guint dpi = LOWORD (msg->wParam);
+
+  /* Don't bother if we use a fixed scale */
+  if (win32_display->has_fixed_scale)
+    return;
+
+  impl->window_scale = dpi / USER_DEFAULT_SCREEN_DPI;
+
+  /* Don't bother if scales did not change in the end */
+  if (old_scale == impl->window_scale)
+    return;
+
+  _gdk_screen_set_resolution (screen,
+                              impl->window_scale >= 2 ? USER_DEFAULT_SCREEN_DPI : dpi);
+
+  if (!IsIconic (msg->hwnd) &&
+      !GDK_WINDOW_DESTROYED (window))
+    {
+      GdkMonitor *monitor;
+
+      monitor = gdk_display_get_monitor_at_window (display, window);
+      gdk_monitor_set_scale_factor (monitor, impl->window_scale);
+
+      if (impl->layered)
+        {
+          /* We only need to set the cairo surface device scale here ourselves for layered windows */
+          if (impl->cache_surface != NULL)
+            cairo_surface_set_device_scale (impl->cache_surface,
+                                            impl->window_scale,
+                                            impl->window_scale);
+
+          if (impl->cairo_surface != NULL)
+            cairo_surface_set_device_scale (impl->cairo_surface,
+                                            impl->window_scale,
+                                            impl->window_scale);
+        }
+    }
+
+  _gdk_win32_adjust_client_rect (window, rect);
+
+  if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
+    gdk_window_move_resize (window, window->x, window->y, window->width, window->height);
+  else
+    gdk_window_resize (window, window->width, window->height);
+}
+
+static void
 generate_button_event (GdkEventType      type,
                        gint              button,
                        GdkWindow        *window,
@@ -1695,6 +1768,7 @@ generate_button_event (GdkEventType      type,
 {
   GdkEvent *event = gdk_event_new (type);
   GdkDeviceManagerWin32 *device_manager;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   if (_gdk_input_ignore_core)
     return;
@@ -1703,10 +1777,10 @@ generate_button_event (GdkEventType      type,
 
   event->button.window = window;
   event->button.time = _gdk_win32_get_next_tick (msg->time);
-  event->button.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
-  event->button.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
-  event->button.x_root = msg->pt.x + _gdk_offset_x;
-  event->button.y_root = msg->pt.y + _gdk_offset_y;
+  event->button.x = current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->window_scale;
+  event->button.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->window_scale;
+  event->button.x_root = (msg->pt.x + _gdk_offset_x) / impl->window_scale;
+  event->button.y_root = (msg->pt.y + _gdk_offset_y) / impl->window_scale;
   event->button.axes = NULL;
   event->button.state = build_pointer_event_state (msg);
   event->button.button = button;
@@ -1999,8 +2073,8 @@ _gdk_win32_window_fill_min_max_info (GdkWindow  *window,
   if (impl->hint_flags & GDK_HINT_MIN_SIZE)
     {
       rect.left = rect.top = 0;
-      rect.right = impl->hints.min_width;
-      rect.bottom = impl->hints.min_height;
+      rect.right = impl->hints.min_width * impl->window_scale;
+      rect.bottom = impl->hints.min_height * impl->window_scale;
 
       _gdk_win32_adjust_client_rect (window, &rect);
 
@@ -2013,8 +2087,8 @@ _gdk_win32_window_fill_min_max_info (GdkWindow  *window,
       int maxw, maxh;
 
       rect.left = rect.top = 0;
-      rect.right = impl->hints.max_width;
-      rect.bottom = impl->hints.max_height;
+      rect.right = impl->hints.max_width * impl->window_scale;
+      rect.bottom = impl->hints.max_height * impl->window_scale;
 
       _gdk_win32_adjust_client_rect (window, &rect);
 
@@ -2047,8 +2121,8 @@ _gdk_win32_window_fill_min_max_info (GdkWindow  *window,
           mmi->ptMaxSize.y = nearest_info.rcWork.bottom - nearest_info.rcWork.top;
         }
 
-      mmi->ptMaxTrackSize.x = GetSystemMetrics (SM_CXVIRTUALSCREEN) + impl->margins_x;
-      mmi->ptMaxTrackSize.y = GetSystemMetrics (SM_CYVIRTUALSCREEN) + impl->margins_y;
+      mmi->ptMaxTrackSize.x = GetSystemMetrics (SM_CXVIRTUALSCREEN) + impl->margins_x * impl->window_scale;
+      mmi->ptMaxTrackSize.y = GetSystemMetrics (SM_CYVIRTUALSCREEN) + impl->margins_y * impl->window_scale;
     }
 
   return TRUE;
@@ -2737,19 +2811,19 @@ gdk_event_translate (MSG  *msg,
        }
 
       g_set_object (&window, find_window_for_mouse_event (window, msg));
+      impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
       /* If we haven't moved, don't create any GDK event. Windows
        * sends WM_MOUSEMOVE messages after a new window is shows under
        * the mouse, even if the mouse hasn't moved. This disturbs gtk.
        */
-      if (msg->pt.x + _gdk_offset_x == current_root_x &&
-         msg->pt.y + _gdk_offset_y == current_root_y)
+      if ((msg->pt.x + _gdk_offset_x) / impl->window_scale == current_root_x &&
+         (msg->pt.y + _gdk_offset_y) / impl->window_scale == current_root_y)
        break;
 
-      current_root_x = msg->pt.x + _gdk_offset_x;
-      current_root_y = msg->pt.y + _gdk_offset_y;
+      current_root_x = (msg->pt.x + _gdk_offset_x) / impl->window_scale;
+      current_root_y = (msg->pt.y + _gdk_offset_y) / impl->window_scale;
 
-      impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
       if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
         {
@@ -2760,8 +2834,8 @@ gdk_event_translate (MSG  *msg,
          event = gdk_event_new (GDK_MOTION_NOTIFY);
          event->motion.window = window;
          event->motion.time = _gdk_win32_get_next_tick (msg->time);
-         event->motion.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
-         event->motion.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
+         event->motion.x = current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->window_scale;
+         event->motion.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->window_scale;
          event->motion.x_root = current_root_x;
          event->motion.y_root = current_root_y;
          event->motion.axes = NULL;
@@ -2873,6 +2947,7 @@ gdk_event_translate (MSG  *msg,
          g_set_object (&window, new_window);
        }
 
+      impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
       ScreenToClient (msg->hwnd, &point);
 
       event = gdk_event_new (GDK_SCROLL);
@@ -2885,10 +2960,10 @@ gdk_event_translate (MSG  *msg,
          event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
            GDK_SCROLL_RIGHT : GDK_SCROLL_LEFT;
       event->scroll.time = _gdk_win32_get_next_tick (msg->time);
-      event->scroll.x = (gint16) point.x;
-      event->scroll.y = (gint16) point.y;
-      event->scroll.x_root = (gint16) GET_X_LPARAM (msg->lParam) + _gdk_offset_x;
-      event->scroll.y_root = (gint16) GET_Y_LPARAM (msg->lParam) + _gdk_offset_y;
+      event->scroll.x = (gint16) point.x / impl->window_scale;
+      event->scroll.y = (gint16) point.y / impl->window_scale;
+      event->scroll.x_root = ((gint16) GET_X_LPARAM (msg->lParam) + _gdk_offset_x) / impl->window_scale;
+      event->scroll.y_root = ((gint16) GET_Y_LPARAM (msg->lParam) + _gdk_offset_y) / impl->window_scale;
       event->scroll.state = build_pointer_event_state (msg);
       gdk_event_set_device (event, device_manager_win32->core_pointer);
       gdk_event_set_source_device (event, device_manager_win32->system_pointer);
@@ -3254,8 +3329,8 @@ gdk_event_translate (MSG  *msg,
            {
              /* Resize in increments relative to the base size */
              rect.left = rect.top = 0;
-             rect.right = impl->hints.base_width;
-             rect.bottom = impl->hints.base_height;
+             rect.right = impl->hints.base_width * impl->window_scale;
+             rect.bottom = impl->hints.base_height * impl->window_scale;
              _gdk_win32_adjust_client_rect (window, &rect);
              point.x = rect.left;
              point.y = rect.top;
@@ -3277,53 +3352,53 @@ gdk_event_translate (MSG  *msg,
            case WMSZ_BOTTOM:
              if (drag->bottom == rect.bottom)
                break;
-             adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
+        adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc * impl->window_scale);
              break;
 
            case WMSZ_BOTTOMLEFT:
              if (drag->bottom == rect.bottom && drag->left == rect.left)
                break;
-             adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
-             adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
+             adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc * impl->window_scale);
+             adjust_drag (&drag->left, rect.left, impl->hints.width_inc * impl->window_scale);
              break;
 
            case WMSZ_LEFT:
              if (drag->left == rect.left)
                break;
-             adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
+             adjust_drag (&drag->left, rect.left, impl->hints.width_inc * impl->window_scale);
              break;
 
            case WMSZ_TOPLEFT:
              if (drag->top == rect.top && drag->left == rect.left)
                break;
-             adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
-             adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
+             adjust_drag (&drag->top, rect.top, impl->hints.height_inc * impl->window_scale);
+             adjust_drag (&drag->left, rect.left, impl->hints.width_inc * impl->window_scale);
              break;
 
            case WMSZ_TOP:
              if (drag->top == rect.top)
                break;
-             adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
+             adjust_drag (&drag->top, rect.top, impl->hints.height_inc * impl->window_scale);
              break;
 
            case WMSZ_TOPRIGHT:
              if (drag->top == rect.top && drag->right == rect.right)
                break;
-             adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
-             adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
+             adjust_drag (&drag->top, rect.top, impl->hints.height_inc * impl->window_scale);
+             adjust_drag (&drag->right, rect.right, impl->hints.width_inc * impl->window_scale);
              break;
 
            case WMSZ_RIGHT:
              if (drag->right == rect.right)
                break;
-             adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
+             adjust_drag (&drag->right, rect.right, impl->hints.width_inc * impl->window_scale);
              break;
 
            case WMSZ_BOTTOMRIGHT:
              if (drag->bottom == rect.bottom && drag->right == rect.right)
                break;
-             adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
-             adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
+             adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc * impl->window_scale);
+             adjust_drag (&drag->right, rect.right, impl->hints.width_inc * impl->window_scale);
              break;
            }
 
@@ -3489,6 +3564,12 @@ gdk_event_translate (MSG  *msg,
       return_val = TRUE;
       break;
 
+    case WM_DPICHANGED:
+      handle_dpi_changed (window, msg);
+      return_val = FALSE;
+      *ret_valp = 0;
+      break;
+
     case WM_NCDESTROY:
       if ((pointer_grab != NULL && pointer_grab -> window == window) ||
           (keyboard_grab && keyboard_grab -> window == window))
diff --git a/gdk/win32/gdkgeometry-win32.c b/gdk/win32/gdkgeometry-win32.c
index 7d955f3..02d61ef 100644
--- a/gdk/win32/gdkgeometry-win32.c
+++ b/gdk/win32/gdkgeometry-win32.c
@@ -73,27 +73,32 @@ _gdk_window_move_resize_child (GdkWindow *window,
                               gint       width,
                               gint       height)
 {
+  GdkWindowImplWin32 *impl;
+
   g_return_if_fail (window != NULL);
   g_return_if_fail (GDK_IS_WINDOW (window));
 
+  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
   GDK_NOTE (MISC, g_print ("_gdk_window_move_resize_child: %s@%+d%+d %dx%d@%+d%+d\n",
                           _gdk_win32_window_description (window),
                           window->x, window->y, width, height, x, y));
 
-  if (width > 65535 || height > 65535)
-  {
-    g_warning ("Native children wider or taller than 65535 pixels are not supported.");
+  if (width * impl->window_scale > 65535 || height * impl->window_scale > 65535)
+    {
+      g_warning ("Native children wider or taller than 65535 pixels are not supported.");
 
-    if (width > 65535)
-      width = 65535;
-    if (height > 65535)
-      height = 65535;
-  }
+      if (width * impl->window_scale > 65535)
+        width = 65535 / impl->window_scale;
+      if (height * impl->window_scale > 65535)
+        height = 65535 /impl->window_scale;
+    }
 
   window->x = x;
   window->y = y;
   window->width = width;
   window->height = height;
+  impl->unscaled_width = width * impl->window_scale;
+  impl->unscaled_height = height * impl->window_scale;
 
   _gdk_win32_window_tmp_unset_parent_bg (window);
   _gdk_win32_window_tmp_unset_bg (window, TRUE);
@@ -101,12 +106,16 @@ _gdk_window_move_resize_child (GdkWindow *window,
   GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%d,%d,"
                           "NOACTIVATE|NOZORDER)\n",
                           GDK_WINDOW_HWND (window),
-                          window->x + window->parent->abs_x, window->y + window->parent->abs_y,
-                          width, height));
+                          (window->x + window->parent->abs_x) * impl->window_scale,
+                          (window->y + window->parent->abs_y) * impl->window_scale,
+                          impl->unscaled_width,
+                          impl->unscaled_height));
 
   API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), NULL,
-                          window->x + window->parent->abs_x, window->y + window->parent->abs_y,
-                          width, height,
+                          (window->x + window->parent->abs_x) * impl->window_scale,
+                          (window->y + window->parent->abs_y) * impl->window_scale,
+                          impl->unscaled_width,
+                          impl->unscaled_height,
                           SWP_NOACTIVATE | SWP_NOZORDER));
 
   _gdk_win32_window_tmp_reset_bg (window, TRUE);
diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c
index 79dc35f..2c45cb3 100644
--- a/gdk/win32/gdkmain-win32.c
+++ b/gdk/win32/gdkmain-win32.c
@@ -821,6 +821,7 @@ _gdk_win32_message_to_string (UINT msg)
       CASE (WT_PACKET);
       CASE (WT_CSRCHANGE);
       CASE (WT_PROXIMITY);
+      CASE (WM_DPICHANGED);
 #undef CASE
     default:
       if (msg >= WM_HANDHELDFIRST && msg <= WM_HANDHELDLAST)
diff --git a/gdk/win32/gdkmonitor-win32.c b/gdk/win32/gdkmonitor-win32.c
index b783098..1686eb5 100644
--- a/gdk/win32/gdkmonitor-win32.c
+++ b/gdk/win32/gdkmonitor-win32.c
@@ -591,6 +591,7 @@ enum_monitor (HMONITOR hmonitor,
           GdkWin32Monitor *w32mon;
           GdkMonitor *mon;
           GdkRectangle rect;
+          guint scale;
 
           memset (&dd_monitor, 0, sizeof (dd_monitor));
           dd_monitor.cb = sizeof (dd_monitor);
@@ -680,17 +681,18 @@ enum_monitor (HMONITOR hmonitor,
           /* This is the reason this function exists. This data is not available
            * via other functions.
            */
-          rect.x = monitor_info.rcMonitor.left;
-          rect.y = monitor_info.rcMonitor.top;
-          rect.width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left;
-          rect.height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top;
+          scale = gdk_monitor_get_scale_factor (mon);
+          rect.x = monitor_info.rcMonitor.left / scale;
+          rect.y = monitor_info.rcMonitor.top / scale;
+          rect.width = (monitor_info.rcMonitor.right - monitor_info.rcMonitor.left) / scale;
+          rect.height = (monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top) / scale;
           gdk_monitor_set_position (mon, rect.x, rect.y);
           gdk_monitor_set_size (mon, rect.width, rect.height);
 
-          rect.x = monitor_info.rcWork.left;
-          rect.y = monitor_info.rcWork.top;
-          rect.width = monitor_info.rcWork.right - monitor_info.rcWork.left;
-          rect.height = monitor_info.rcWork.bottom - monitor_info.rcWork.top;
+          rect.x = monitor_info.rcWork.left / scale;
+          rect.y = monitor_info.rcWork.top / scale;
+          rect.width = (monitor_info.rcWork.right - monitor_info.rcWork.left) / scale;
+          rect.height = (monitor_info.rcWork.bottom - monitor_info.rcWork.top) / scale;
           w32mon->work_rect = rect;
 
           if (monitor_info.dwFlags & MONITORINFOF_PRIMARY && i != 0)
diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h
index 2966074..27c0663 100644
--- a/gdk/win32/gdkprivate-win32.h
+++ b/gdk/win32/gdkprivate-win32.h
@@ -97,6 +97,9 @@
 #ifndef WM_MOUSEHWHEEL
 #define WM_MOUSEHWHEEL 0x20E
 #endif
+#ifndef WM_DPICHANGED
+#define WM_DPICHANGED 0x02E0
+#endif
 
 /* According to
  * http://blog.airesoft.co.uk/2009/11/wm_messages/
@@ -185,7 +188,8 @@ HRGN          _gdk_win32_cairo_region_to_hrgn (const cairo_region_t *region,
                                           gint                  x_origin,
                                           gint                  y_origin);
 
-cairo_region_t *_gdk_win32_hrgn_to_region    (HRGN hrgn);
+cairo_region_t *_gdk_win32_hrgn_to_region    (HRGN  hrgn,
+                                              guint scale);
 
 void   _gdk_win32_adjust_client_rect   (GdkWindow *window,
                                         RECT      *RECT);
@@ -544,8 +548,10 @@ gboolean _gdk_win32_window_fill_min_max_info    (GdkWindow  *window,
 
 gboolean _gdk_win32_window_lacks_wm_decorations (GdkWindow *window);
 
-BOOL WINAPI GtkShowWindow (HWND hwnd,
-                           int  cmd_show);
+BOOL WINAPI GtkShowWindow (GdkWindow *window,
+                           int        cmd_show);
+
+void     _gdk_win32_screen_set_font_resolution (GdkWin32Screen *win32_screen);
 
 /* Initialization */
 void _gdk_win32_windowing_init (void);
diff --git a/gdk/win32/gdkscreen-win32.c b/gdk/win32/gdkscreen-win32.c
index cd1c9ff..2039038 100644
--- a/gdk/win32/gdkscreen-win32.c
+++ b/gdk/win32/gdkscreen-win32.c
@@ -50,6 +50,7 @@ init_root_window_size (GdkWin32Screen *screen)
   int monitor_count;
   GdkMonitor *monitor;
   gboolean changed;
+  GdkWindowImplWin32 *root_impl;
 
   monitor_count = gdk_display_get_n_monitors (display);
   monitor = gdk_display_get_monitor (display, 0);
@@ -68,6 +69,10 @@ init_root_window_size (GdkWin32Screen *screen)
             screen->root_window->height != result.height;
   screen->root_window->width = result.width;
   screen->root_window->height = result.height;
+  root_impl = GDK_WINDOW_IMPL_WIN32 (screen->root_window->impl);
+
+  root_impl->unscaled_width = result.width * root_impl->window_scale;
+  root_impl->unscaled_height = result.height * root_impl->window_scale;
 
   return changed;
 }
@@ -79,6 +84,7 @@ init_root_window (GdkWin32Screen *screen_win32)
   GdkWindow *window;
   GdkWindowImplWin32 *impl_win32;
   gboolean changed;
+  GdkWin32Display *win32_display;
 
   screen = GDK_SCREEN (screen_win32);
 
@@ -103,6 +109,18 @@ init_root_window (GdkWin32Screen *screen_win32)
   window->abs_y = 0;
   /* width and height already initialised in init_root_window_size() */
   window->viewable = TRUE;
+  win32_display = GDK_WIN32_DISPLAY (_gdk_display);
+
+  if (win32_display->dpi_aware_type != PROCESS_DPI_UNAWARE)
+    impl_win32->window_scale = _gdk_win32_display_get_monitor_scale_factor (win32_display,
+                                                                            NULL,
+                                                                            impl_win32->handle,
+                                                                            NULL);
+  else
+    impl_win32->window_scale = 1;
+
+  impl_win32->unscaled_width = window->width * impl_win32->window_scale;
+  impl_win32->unscaled_height = window->height * impl_win32->window_scale;
 
   gdk_win32_handle_table_insert ((HANDLE *) &impl_win32->handle, window);
 
@@ -115,28 +133,7 @@ static void
 gdk_win32_screen_init (GdkWin32Screen *win32_screen)
 {
   GdkScreen *screen = GDK_SCREEN (win32_screen);
-  HDC screen_dc;
-  int logpixelsx = -1;
-  const gchar *font_resolution;
-
-  screen_dc = GetDC (NULL);
-
-  if (screen_dc)
-    {
-      logpixelsx = GetDeviceCaps(screen_dc, LOGPIXELSX);
-      ReleaseDC (NULL, screen_dc);
-    }
-
-  font_resolution = g_getenv ("GDK_WIN32_FONT_RESOLUTION");
-  if (font_resolution)
-    {
-      int env_logpixelsx = atol (font_resolution);
-      if (env_logpixelsx > 0)
-        logpixelsx = env_logpixelsx;
-    }
-
-  if (logpixelsx > 0)
-    _gdk_screen_set_resolution (screen, logpixelsx);
+  _gdk_win32_screen_set_font_resolution (win32_screen);
 
   _gdk_win32_display_init_monitors (GDK_WIN32_DISPLAY (_gdk_display));
   init_root_window (win32_screen);
@@ -156,6 +153,37 @@ _gdk_win32_screen_on_displaychange_event (GdkWin32Screen *screen)
     g_signal_emit_by_name (screen, "monitors-changed");
 }
 
+void
+_gdk_win32_screen_set_font_resolution (GdkWin32Screen *win32_screen)
+{
+  GdkScreen *screen = GDK_SCREEN (win32_screen);
+  int logpixelsx = -1;
+  const gchar *font_resolution;
+
+  font_resolution = g_getenv ("GDK_WIN32_FONT_RESOLUTION");
+  if (font_resolution)
+    {
+      int env_logpixelsx = atol (font_resolution);
+      if (env_logpixelsx > 0)
+        logpixelsx = env_logpixelsx;
+    }
+  else
+    {
+      gint dpi = -1;
+      GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (gdk_screen_get_display (screen));
+      guint scale = _gdk_win32_display_get_monitor_scale_factor (win32_display, NULL, NULL, &dpi);
+
+      /* If we have a scale that is at least 2, don't scale up the fonts */
+      if (scale >= 2)
+        logpixelsx = USER_DEFAULT_SCREEN_DPI;
+      else
+        logpixelsx = dpi;
+    }
+
+  if (logpixelsx > 0)
+    _gdk_screen_set_resolution (screen, logpixelsx);
+}
+
 static GdkDisplay *
 gdk_win32_screen_get_display (GdkScreen *screen)
 {
diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c
index a68e863..9069b4c 100644
--- a/gdk/win32/gdkwindow-win32.c
+++ b/gdk/win32/gdkwindow-win32.c
@@ -37,8 +37,10 @@
 #include "gdkwin32.h"
 #include "gdkdisplayprivate.h"
 #include "gdkvisualprivate.h"
+#include "gdkmonitorprivate.h"
 #include "gdkwin32window.h"
 #include "gdkglcontext-win32.h"
+#include "gdkdisplay-win32.h"
 
 #include <cairo-win32.h>
 #include <dwmapi.h>
@@ -206,6 +208,7 @@ gdk_window_impl_win32_init (GdkWindowImplWin32 *impl)
   impl->transient_children = NULL;
   impl->num_transients = 0;
   impl->changing_state = FALSE;
+  impl->window_scale = 1;
 
   if (display != NULL)
     /* Replace WM-defined default cursor with the default cursor
@@ -261,21 +264,22 @@ gdk_win32_window_get_queued_window_rect (GdkWindow *window,
 {
   gint x, y;
   RECT window_rect;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   gdk_window_get_position (window, &x, &y);
   window_rect.left = x;
   window_rect.top = y;
-  window_rect.right = window_rect.left + gdk_window_get_width (window);
-  window_rect.bottom = window_rect.top + gdk_window_get_height (window);
+  window_rect.right = window_rect.left + gdk_window_get_width (window) * impl->window_scale;
+  window_rect.bottom = window_rect.top + gdk_window_get_height (window) * impl->window_scale;
 
   /* Turn client area into window area */
   _gdk_win32_adjust_client_rect (window, &window_rect);
 
   /* Convert GDK screen coordinates to W32 desktop coordinates */
-  window_rect.left -= _gdk_offset_x;
-  window_rect.right -= _gdk_offset_x;
-  window_rect.top -= _gdk_offset_y;
-  window_rect.bottom -= _gdk_offset_y;
+  window_rect.left -= _gdk_offset_x * impl->window_scale;
+  window_rect.right -= _gdk_offset_x * impl->window_scale;
+  window_rect.top -= _gdk_offset_y * impl->window_scale;
+  window_rect.bottom -= _gdk_offset_y * impl->window_scale;
 
   *return_window_rect = window_rect;
 }
@@ -286,6 +290,7 @@ gdk_win32_window_apply_queued_move_resize (GdkWindow *window,
 {
   if (!IsIconic (GDK_WINDOW_HWND (window)))
     {
+      GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
       GDK_NOTE (EVENTS, g_print ("Setting window position ... "));
 
       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
@@ -389,6 +394,7 @@ gdk_win32_window_end_paint (GdkWindow *window)
 
   window_position.x = window_rect.left;
   window_position.y = window_rect.top;
+
   window_size.cx = window_rect.right - window_rect.left;
   window_size.cy = window_rect.bottom - window_rect.top;
 
@@ -693,6 +699,7 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
   DWORD dwStyle = 0, dwExStyle;
   RECT rect;
   GdkWindowImplWin32 *impl;
+  GdkWin32Display *display_win32;
   const gchar *title;
   wchar_t *wtitle;
   gboolean override_redirect;
@@ -746,6 +753,11 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
   impl->layered = FALSE;
   impl->layered_opacity = 1.0;
 
+  display_win32 = GDK_WIN32_DISPLAY (display);
+  impl->window_scale = _gdk_win32_display_get_monitor_scale_factor (display_win32, NULL, NULL, NULL);
+  impl->unscaled_width = window->width * impl->window_scale;
+  impl->unscaled_height = window->height * impl->window_scale;
+
   if (!window->input_only)
     {
       dwExStyle = 0;
@@ -805,15 +817,15 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
 
   if (window->window_type != GDK_WINDOW_CHILD)
     {
-      rect.left = window->x;
-      rect.top = window->y;
-      rect.right = window->width + window->x;
-      rect.bottom = window->height + window->y;
+      rect.left = window->x * impl->window_scale;
+      rect.top = window->y * impl->window_scale;
+      rect.right = rect.left + window->width * impl->window_scale;
+      rect.bottom = rect.top + window->height * impl->window_scale;
 
       AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
 
-      real_x = window->x - offset_x;
-      real_y = window->y - offset_y;
+      real_x = (window->x - offset_x) * impl->window_scale;
+      real_y = (window->y - offset_y) * impl->window_scale;
 
       if (window->window_type == GDK_WINDOW_TOPLEVEL)
        {
@@ -834,11 +846,11 @@ _gdk_win32_display_create_window_impl (GdkDisplay    *display,
   else
     {
       /* adjust position relative to real_parent */
-      window_width = window->width;
-      window_height = window->height;
+      window_width = impl->unscaled_width;
+      window_height = impl->unscaled_height;
       /* use given position for initial placement, native coordinates */
-      x = window->x + window->parent->abs_x - offset_x;
-      y = window->y + window->parent->abs_y - offset_y;
+      x = (window->x + window->parent->abs_x - offset_x) * impl->window_scale;
+      y = (window->y + window->parent->abs_y - offset_y) * impl->window_scale;
     }
 
   if (attributes_mask & GDK_WA_TITLE)
@@ -975,8 +987,10 @@ gdk_win32_window_foreign_new_for_display (GdkDisplay *display,
     ScreenToClient (parent, &point);
   window->x = point.x;
   window->y = point.y;
-  window->width = rect.right - rect.left;
-  window->height = rect.bottom - rect.top;
+  impl->unscaled_width = rect.right - rect.left;
+  impl->unscaled_height = rect.bottom - rect.top;
+  window->width = (impl->unscaled_width + impl->window_scale - 1) / impl->window_scale;
+  window->height = (impl->unscaled_height + impl->window_scale - 1) / impl->window_scale;
   window->window_type = GDK_WINDOW_FOREIGN;
   window->destroyed = FALSE;
   window->event_mask = GDK_ALL_EVENTS_MASK; /* XXX */
@@ -1089,9 +1103,11 @@ get_outer_rect (GdkWindow *window,
                gint       height,
                RECT      *rect)
 {
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
   rect->left = rect->top = 0;
-  rect->right = width;
-  rect->bottom = height;
+  rect->right = width * impl->window_scale;
+  rect->bottom = height * impl->window_scale;
 
   _gdk_win32_adjust_client_rect (window, rect);
 }
@@ -1102,9 +1118,7 @@ adjust_for_gravity_hints (GdkWindow *window,
                          gint          *x,
                          gint          *y)
 {
-  GdkWindowImplWin32 *impl;
-
-  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   if (impl->hint_flags & GDK_HINT_WIN_GRAVITY)
     {
@@ -1117,19 +1131,19 @@ adjust_for_gravity_hints (GdkWindow *window,
        case GDK_GRAVITY_NORTH:
        case GDK_GRAVITY_CENTER:
        case GDK_GRAVITY_SOUTH:
-         *x -= (outer_rect->right - outer_rect->left) / 2;
+         *x -= (outer_rect->right - outer_rect->left / 2) / impl->window_scale;
          *x += window->width / 2;
          break;
 
        case GDK_GRAVITY_SOUTH_EAST:
        case GDK_GRAVITY_EAST:
        case GDK_GRAVITY_NORTH_EAST:
-         *x -= outer_rect->right - outer_rect->left;
+         *x -= (outer_rect->right - outer_rect->left) / impl->window_scale;
          *x += window->width;
          break;
 
        case GDK_GRAVITY_STATIC:
-         *x += outer_rect->left;
+         *x += outer_rect->left / impl->window_scale;
          break;
 
        default:
@@ -1141,19 +1155,19 @@ adjust_for_gravity_hints (GdkWindow *window,
        case GDK_GRAVITY_WEST:
        case GDK_GRAVITY_CENTER:
        case GDK_GRAVITY_EAST:
-         *y -= (outer_rect->bottom - outer_rect->top) / 2;
+         *y -= ((outer_rect->bottom - outer_rect->top) / 2) / impl->window_scale;
          *y += window->height / 2;
          break;
 
        case GDK_GRAVITY_SOUTH_WEST:
        case GDK_GRAVITY_SOUTH:
        case GDK_GRAVITY_SOUTH_EAST:
-         *y -= outer_rect->bottom - outer_rect->top;
+         *y -= (outer_rect->bottom - outer_rect->top) / impl->window_scale;
          *y += window->height;
          break;
 
        case GDK_GRAVITY_STATIC:
-         *y += outer_rect->top;
+         *y += outer_rect->top * impl->window_scale;
          break;
 
        default:
@@ -1191,7 +1205,7 @@ show_window_internal (GdkWindow *window,
       !already_mapped &&
       (window->state & GDK_WINDOW_STATE_ICONIFIED))
     {
-      GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMINNOACTIVE);
+      GtkShowWindow (window, SW_SHOWMINNOACTIVE);
       return;
     }
 
@@ -1280,10 +1294,11 @@ show_window_internal (GdkWindow *window,
        {
          GdkWindow *owner = window_impl->transient_owner;
          /* Center on transient parent */
-         center_on_rect.left = owner->x - _gdk_offset_x;
-         center_on_rect.top = owner->y - _gdk_offset_y;
-         center_on_rect.right = center_on_rect.left + owner->width;
-         center_on_rect.bottom = center_on_rect.top + owner->height;
+         center_on_rect.left = (owner->x - _gdk_offset_x) * window_impl->window_scale;
+         center_on_rect.top = (owner->y - _gdk_offset_y) * window_impl->window_scale;
+         center_on_rect.right = center_on_rect.left + owner->width * window_impl->window_scale;
+         center_on_rect.bottom = center_on_rect.top + owner->height * window_impl->window_scale;
+
          _gdk_win32_adjust_client_rect (GDK_WINDOW (owner), &center_on_rect);
          center = TRUE;
        }
@@ -1292,8 +1307,8 @@ show_window_internal (GdkWindow *window,
        {
          window_rect.left = 0;
          window_rect.top = 0;
-         window_rect.right = window->width;
-         window_rect.bottom = window->height;
+         window_rect.right = window->width * window_impl->window_scale;
+         window_rect.bottom = window->height * window_impl->window_scale;
          _gdk_win32_adjust_client_rect (window, &window_rect);
 
          x = center_on_rect.left + ((center_on_rect.right - center_on_rect.left) - (window_rect.right - 
window_rect.left)) / 2;
@@ -1364,29 +1379,29 @@ show_window_internal (GdkWindow *window,
     }
   else if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
     {
-      GtkShowWindow (GDK_WINDOW_HWND (window), SW_MAXIMIZE);
+      GtkShowWindow (window, SW_MAXIMIZE);
     }
   else if (window->state & GDK_WINDOW_STATE_ICONIFIED)
     {
       if (focus_on_map)
-        GtkShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
+        GtkShowWindow (window, SW_RESTORE);
       else
-        GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNOACTIVATE);
+        GtkShowWindow (window, SW_SHOWNOACTIVATE);
     }
   else if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP || !focus_on_map)
     {
       if (!IsWindowVisible (GDK_WINDOW_HWND (window)))
-        GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNOACTIVATE);
+        GtkShowWindow (window, SW_SHOWNOACTIVATE);
       else
-        GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNA);
+        GtkShowWindow (window, SW_SHOWNA);
     }
   else if (!IsWindowVisible (GDK_WINDOW_HWND (window)))
     {
-      GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNORMAL);
+      GtkShowWindow (window, SW_SHOWNORMAL);
     }
   else
     {
-      GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOW);
+      GtkShowWindow (window, SW_SHOW);
     }
 
   /* Sync STATE_ABOVE to TOPMOST */
@@ -1441,7 +1456,7 @@ gdk_win32_window_hide (GdkWindow *window)
     }
   else
     {
-      GtkShowWindow (GDK_WINDOW_HWND (window), SW_HIDE);
+      GtkShowWindow (window, SW_HIDE);
     }
 }
 
@@ -1484,6 +1499,7 @@ gdk_win32_window_move (GdkWindow *window,
   else
     {
       RECT outer_rect;
+      GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
       get_outer_rect (window, window->width, window->height, &outer_rect);
 
@@ -1492,11 +1508,14 @@ gdk_win32_window_move (GdkWindow *window,
       GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,0,0,"
                                "NOACTIVATE|NOSIZE|NOZORDER)\n",
                                GDK_WINDOW_HWND (window),
-                               x - _gdk_offset_x, y - _gdk_offset_y));
+                               (x - _gdk_offset_x) * impl->window_scale,
+                               (y - _gdk_offset_y) * impl->window_scale));
 
       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
                               SWP_NOZORDER_SPECIFIED,
-                               x - _gdk_offset_x, y - _gdk_offset_y, 0, 0,
+                               (x - _gdk_offset_x) * impl->window_scale,
+                               (y - _gdk_offset_y) * impl->window_scale,
+                               0, 0,
                                SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
     }
 }
@@ -1528,6 +1547,7 @@ gdk_win32_window_resize (GdkWindow *window,
   else
     {
       RECT outer_rect;
+      GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
       get_outer_rect (window, width, height, &outer_rect);
 
@@ -1578,6 +1598,7 @@ gdk_win32_window_move_resize_internal (GdkWindow *window,
   else
     {
       RECT outer_rect;
+      GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
       get_outer_rect (window, width, height, &outer_rect);
 
@@ -1586,13 +1607,15 @@ gdk_win32_window_move_resize_internal (GdkWindow *window,
       GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%ld,%ld,"
                                "NOACTIVATE|NOZORDER)\n",
                                GDK_WINDOW_HWND (window),
-                               x - _gdk_offset_x, y - _gdk_offset_y,
+                               (x - _gdk_offset_x) * impl->window_scale,
+                               (y - _gdk_offset_y) * impl->window_scale,
                                outer_rect.right - outer_rect.left,
                                outer_rect.bottom - outer_rect.top));
 
       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window),
                               SWP_NOZORDER_SPECIFIED,
-                               x - _gdk_offset_x, y - _gdk_offset_y,
+                               (x - _gdk_offset_x) * impl->window_scale,
+                               (y - _gdk_offset_y) * impl->window_scale,
                                outer_rect.right - outer_rect.left,
                                outer_rect.bottom - outer_rect.top,
                                SWP_NOACTIVATE | SWP_NOZORDER));
@@ -2220,6 +2243,7 @@ gdk_win32_window_get_geometry (GdkWindow *window,
   if (!GDK_WINDOW_DESTROYED (window))
     {
       RECT rect;
+      GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
       API_CALL (GetClientRect, (GDK_WINDOW_HWND (window), &rect));
 
@@ -2244,25 +2268,26 @@ gdk_win32_window_get_geometry (GdkWindow *window,
 
          if (gdk_screen_get_root_window (screen) == parent)
            {
-             rect.left += _gdk_offset_x;
-             rect.top += _gdk_offset_y;
-             rect.right += _gdk_offset_x;
-             rect.bottom += _gdk_offset_y;
+             rect.left += _gdk_offset_x * impl->window_scale;
+             rect.top += _gdk_offset_y * impl->window_scale;
+             rect.right += _gdk_offset_x * impl->window_scale;
+             rect.bottom += _gdk_offset_y * impl->window_scale;
            }
        }
 
       if (x)
-       *x = rect.left;
+       *x = rect.left / impl->window_scale;
       if (y)
-       *y = rect.top;
+       *y = rect.top / impl->window_scale;
       if (width)
-       *width = rect.right - rect.left;
+       *width = (rect.right - rect.left) / impl->window_scale;
       if (height)
-       *height = rect.bottom - rect.top;
+       *height = (rect.bottom - rect.top) / impl->window_scale;
 
-      GDK_NOTE (MISC, g_print ("gdk_win32_window_get_geometry: %p: %ldx%ld@%+ld%+ld\n",
+      GDK_NOTE (MISC, g_print ("gdk_win32_window_get_geometry: %p: %ldx%ld@%+ld%\n",
                               GDK_WINDOW_HWND (window),
-                              rect.right - rect.left, rect.bottom - rect.top,
+                              (rect.right - rect.left) / impl->window_scale,
+                              (rect.bottom - rect.top) / impl->window_scale,
                               rect.left, rect.top));
     }
 }
@@ -2277,22 +2302,25 @@ gdk_win32_window_get_root_coords (GdkWindow *window,
   gint tx;
   gint ty;
   POINT pt;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
-  pt.x = x;
-  pt.y = y;
+  pt.x = x * impl->window_scale;
+  pt.y = y * impl->window_scale;
   ClientToScreen (GDK_WINDOW_HWND (window), &pt);
   tx = pt.x;
   ty = pt.y;
 
   if (root_x)
-    *root_x = tx + _gdk_offset_x;
+    *root_x = (tx + _gdk_offset_x) / impl->window_scale;
   if (root_y)
-    *root_y = ty + _gdk_offset_y;
+    *root_y = (ty + _gdk_offset_y) / impl->window_scale;
 
   GDK_NOTE (MISC, g_print ("gdk_win32_window_get_root_coords: %p: %+d%+d %+d%+d\n",
                           GDK_WINDOW_HWND (window),
-                          x, y,
-                          tx + _gdk_offset_x, ty + _gdk_offset_y));
+                          x * impl->window_scale,
+                          y * impl->window_scale,
+                          (tx + _gdk_offset_x) / impl->window_scale,
+                          (ty + _gdk_offset_y) / impl->window_scale));
 }
 
 static void
@@ -2316,6 +2344,7 @@ gdk_win32_window_get_frame_extents (GdkWindow    *window,
 {
   HWND hwnd;
   RECT r;
+  GdkWindowImplWin32 *impl;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
   g_return_if_fail (rect != NULL);
@@ -2334,17 +2363,19 @@ gdk_win32_window_get_frame_extents (GdkWindow    *window,
   while (window->parent && window->parent->parent)
     window = window->parent;
 
+  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
   hwnd = GDK_WINDOW_HWND (window);
   API_CALL (GetWindowRect, (hwnd, &r));
 
   rect->x = r.left + _gdk_offset_x;
   rect->y = r.top + _gdk_offset_y;
-  rect->width = r.right - r.left;
-  rect->height = r.bottom - r.top;
+  rect->width = (r.right - r.left) / impl->window_scale;
+  rect->height = (r.bottom - r.top) / impl->window_scale;
 
   GDK_NOTE (MISC, g_print ("gdk_window_get_frame_extents: %p: %ldx%ld@%+ld%+ld\n",
                           GDK_WINDOW_HWND (window),
-                          r.right - r.left, r.bottom - r.top,
+                          (r.right - r.left) / impl->window_scale,
+         (r.bottom - r.top) / impl->window_scale,
                           r.left, r.top));
 }
 
@@ -2415,8 +2446,10 @@ do_shape_combine_region (GdkWindow *window,
                         gint       x, gint y)
 {
   RECT rect;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   GetClientRect (GDK_WINDOW_HWND (window), &rect);
+
   _gdk_win32_adjust_client_rect (window, &rect);
 
   OffsetRgn (hrgn, -rect.left, -rect.top);
@@ -2973,6 +3006,7 @@ calculate_aerosnap_regions (GdkW32DragMoveResizeContext *context)
 {
   GdkDisplay *display;
   gint n_monitors, monitor_idx, other_monitor_idx;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (context->window->impl);
 #if defined(MORE_AEROSNAP_DEBUGGING)
   gint i;
 #endif
@@ -3041,10 +3075,8 @@ calculate_aerosnap_regions (GdkW32DragMoveResizeContext *context)
             }
         }
 
-      /* TODO: scale it for Hi-DPI displays? */
-      thickness = AEROSNAP_REGION_THICKNESS;
-      /* TODO: scale it for Hi-DPI displays? */
-      trigger_thickness = AEROSNAP_REGION_TRIGGER_THICKNESS;
+      thickness = AEROSNAP_REGION_THICKNESS * impl->window_scale;
+      trigger_thickness = AEROSNAP_REGION_TRIGGER_THICKNESS * impl->window_scale;
 
       snap_region.edge = wa;
       snap_region.trigger = wa;
@@ -3257,18 +3289,18 @@ stash_window (GdkWindow          *window,
     impl->snap_stash_int = g_new0 (GdkRectangle, 1);
 
   GDK_NOTE (MISC, g_print ("monitor work area  %ld x %ld @ %ld : %ld\n",
-                           hmonitor_info.rcWork.right - hmonitor_info.rcWork.left,
-                           hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top,
+                           (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left) / impl->window_scale,
+                           (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top) / impl->window_scale,
                            hmonitor_info.rcWork.left,
                            hmonitor_info.rcWork.top));
   GDK_NOTE (MISC, g_print ("monitor      area  %ld x %ld @ %ld : %ld\n",
-                           hmonitor_info.rcMonitor.right - hmonitor_info.rcMonitor.left,
-                           hmonitor_info.rcMonitor.bottom - hmonitor_info.rcMonitor.top,
+                           (hmonitor_info.rcMonitor.right - hmonitor_info.rcMonitor.left) / 
impl->window_scale,
+                           (hmonitor_info.rcMonitor.bottom - hmonitor_info.rcMonitor.top) / 
impl->window_scale,
                            hmonitor_info.rcMonitor.left,
                            hmonitor_info.rcMonitor.top));
   GDK_NOTE (MISC, g_print ("window  work place %ld x %ld @ %ld : %ld\n",
-                           placement.rcNormalPosition.right - placement.rcNormalPosition.left,
-                           placement.rcNormalPosition.bottom - placement.rcNormalPosition.top,
+                           (placement.rcNormalPosition.right - placement.rcNormalPosition.left) / 
impl->window_scale,
+                           (placement.rcNormalPosition.bottom - placement.rcNormalPosition.top) / 
impl->window_scale,
                            placement.rcNormalPosition.left,
                            placement.rcNormalPosition.top));
 
@@ -3277,15 +3309,15 @@ stash_window (GdkWindow          *window,
   x = placement.rcNormalPosition.left - hmonitor_info.rcMonitor.left;
   y = placement.rcNormalPosition.top - hmonitor_info.rcMonitor.top;
 
-  impl->snap_stash->x = (gdouble) (x) / (gdouble) (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left);
-  impl->snap_stash->y = (gdouble) (y) / (gdouble) (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top);
-  impl->snap_stash->width = (gdouble) width / (gdouble) (hmonitor_info.rcWork.right - 
hmonitor_info.rcWork.left);
-  impl->snap_stash->height = (gdouble) height / (gdouble) (hmonitor_info.rcWork.bottom - 
hmonitor_info.rcWork.top);
+  impl->snap_stash->x = ((gdouble) (x) / (gdouble) (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left)) 
/ impl->window_scale;
+  impl->snap_stash->y = ((gdouble) (y) / (gdouble) (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top)) 
/ impl->window_scale;
+  impl->snap_stash->width = ((gdouble) width / (gdouble) (hmonitor_info.rcWork.right - 
hmonitor_info.rcWork.left)) / impl->window_scale;
+  impl->snap_stash->height = ((gdouble) height / (gdouble) (hmonitor_info.rcWork.bottom - 
hmonitor_info.rcWork.top)) / impl->window_scale;
 
-  impl->snap_stash_int->x = x;
-  impl->snap_stash_int->y = y;
-  impl->snap_stash_int->width = width;
-  impl->snap_stash_int->height = height;
+  impl->snap_stash_int->x = x / impl->window_scale;
+  impl->snap_stash_int->y = y / impl->window_scale;
+  impl->snap_stash_int->width = width / impl->window_scale;
+  impl->snap_stash_int->height = height / impl->window_scale;
 
   GDK_NOTE (MISC, g_print ("Stashed window %d x %d @ %d : %d as %f x %f @ %f : %f\n",
                            width, height, x, y,
@@ -3306,15 +3338,15 @@ snap_up (GdkWindow *window)
 
   stash_window (window, impl);
 
-  maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+  maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN) / impl->window_scale;
   gdk_window_get_position (window, &x, &y);
   width = gdk_window_get_width (window);
 
   y = 0;
   height = maxysize;
 
-  x -= impl->margins.left;
-  y -= impl->margins.top;
+  x = (x - impl->margins.left) / impl->window_scale;
+  y = (y - impl->margins.top) / impl->window_scale;
   width += impl->margins_x;
   height += impl->margins_y;
 
@@ -3337,12 +3369,12 @@ snap_left (GdkWindow  *window,
 
   stash_window (window, impl);
 
-  rect.width = rect.width / 2;
+  rect.width = rect.width / 2 / impl->window_scale;
 
-  rect.x -= impl->margins.left;
-  rect.y -= impl->margins.top;
-  rect.width += impl->margins_x;
-  rect.height += impl->margins_y;
+  rect.x = rect.x - impl->margins.left / impl->window_scale;
+  rect.y = rect.y - impl->margins.top / impl->window_scale;
+  rect.width = rect.width + impl->margins_x;
+  rect.height = rect.height + impl->margins_y;
 
   gdk_window_move_resize (window, rect.x, rect.y, rect.width, rect.height);
 }
@@ -3363,13 +3395,13 @@ snap_right (GdkWindow  *window,
 
   stash_window (window, impl);
 
-  rect.width /= 2;
+  rect.width = rect.width / 2 / impl->window_scale;;
   rect.x += rect.width;
 
-  rect.x -= impl->margins.left;
-  rect.y -= impl->margins.top;
-  rect.width += impl->margins_x;
-  rect.height += impl->margins_y;
+  rect.x = rect.x - impl->margins.left / impl->window_scale;
+  rect.y = rect.y - impl->margins.top / impl->window_scale;
+  rect.width = rect.width + impl->margins_x / impl->window_scale;
+  rect.height = rect.height + impl->margins_y / impl->window_scale;
 
   gdk_window_move_resize (window, rect.x, rect.y, rect.width, rect.height);
 }
@@ -3598,7 +3630,8 @@ ensure_snap_indicator_exists (GdkW32DragMoveResizeContext *context)
 static gboolean
 ensure_snap_indicator_surface (GdkW32DragMoveResizeContext *context,
                           gint                         width,
-                          gint                         height)
+                          gint                         height,
+                          guint                        scale)
 {
   if (context->indicator_surface != NULL &&
       (context->indicator_surface_width < width ||
@@ -3609,7 +3642,9 @@ ensure_snap_indicator_surface (GdkW32DragMoveResizeContext *context,
     }
 
   if (context->indicator_surface == NULL)
-    context->indicator_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
+    context->indicator_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
+                                                                      width * scale,
+                                                                      height * scale);
 
   if (cairo_surface_status (context->indicator_surface) != CAIRO_STATUS_SUCCESS)
     {
@@ -3627,10 +3662,11 @@ ensure_snap_indicator_surface (GdkW32DragMoveResizeContext *context,
  */
 static void
 adjust_indicator_rectangle (GdkRectangle *rect,
-                            gboolean      inward)
+                            gboolean      inward,
+                            guint         scale)
 {
   gdouble inverter;
-  gint gap;
+  const gint gap = AEROSNAP_INDICATOR_EDGE_GAP;
 #if defined(MORE_AEROSNAP_DEBUGGING)
   GdkRectangle cache = *rect;
 #endif
@@ -3640,13 +3676,10 @@ adjust_indicator_rectangle (GdkRectangle *rect,
   else
     inverter = -1.0;
 
-  /* TODO: Adjust for HiDPI? */
-  gap = AEROSNAP_INDICATOR_EDGE_GAP;
-
-  rect->x += gap * inverter;
-  rect->y += gap * inverter;
-  rect->width -= gap * 2 * inverter;
-  rect->height -= gap * 2 * inverter;
+  rect->x += (gap * inverter);
+  rect->y += (gap * inverter);
+  rect->width -= (gap * 2 * inverter) * scale;
+  rect->height -= (gap * 2 * inverter) * scale;
 
 #if defined(MORE_AEROSNAP_DEBUGGING)
   GDK_NOTE (MISC, g_print ("Adjusted %d x %d @ %d : %d -> %d x %d @ %d : %d\n",
@@ -3664,7 +3697,8 @@ rounded_rectangle (cairo_t  *cr,
                    gdouble   radius,
                    gdouble   line_width,
                    GdkRGBA  *fill,
-                   GdkRGBA  *outline)
+                   GdkRGBA  *outline,
+                   guint     scale)
 {
   gdouble degrees = M_PI / 180.0;
 
@@ -3673,10 +3707,10 @@ rounded_rectangle (cairo_t  *cr,
 
   cairo_save (cr);
   cairo_new_sub_path (cr);
-  cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
-  cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
-  cairo_arc (cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
-  cairo_arc (cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
+  cairo_arc (cr, x * scale + width - radius * scale, y * scale + radius * scale, radius * scale, -90 * 
degrees, 0 * degrees);
+  cairo_arc (cr, x * scale + width - radius * scale, y * scale + height - radius * scale, radius * scale, 0 
* degrees, 90 * degrees);
+  cairo_arc (cr, (x + radius) * scale, y * scale + height - radius * scale, radius * scale, 90 * degrees, 
180 * degrees);
+  cairo_arc (cr, (x + radius) * scale, (y + radius) * scale, radius * scale, 180 * degrees, 270 * degrees);
   cairo_close_path (cr);
 
   if (fill)
@@ -3721,10 +3755,9 @@ draw_indicator (GdkW32DragMoveResizeContext *context,
   gdouble line_width;
   gdouble corner_radius;
   gint64 animation_duration;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (context->window->impl);
 
-  /* TODO: Adjust for HiDPI? */
   line_width = AEROSNAP_INDICATOR_LINE_WIDTH;
-  /* TODO: Adjust for HiDPI? */
   corner_radius = AEROSNAP_INDICATOR_CORNER_RADIUS;
   animation_duration = AEROSNAP_INDICATOR_ANIMATION_DURATION;
   last_draw = FALSE;
@@ -3794,10 +3827,11 @@ draw_indicator (GdkW32DragMoveResizeContext *context,
   rounded_rectangle (cr,
                      current_rect.x - context->indicator_window_rect.x,
                      current_rect.y - context->indicator_window_rect.y,
-                     current_rect.width, current_rect.height,
+                     current_rect.width,
+                     current_rect.height,
                      corner_radius,
                      line_width,
-                     &fill, &outline);
+                     &fill, &outline, impl->window_scale);
   cairo_destroy (cr);
 
 #if defined(MORE_AEROSNAP_DEBUGGING)
@@ -3822,14 +3856,28 @@ redraw_indicator (gpointer user_data)
   POINT source_point = { 0, 0 };
   gboolean last_draw;
   gdouble indicator_opacity;
+  GdkWindowImplWin32 *impl;
+  gboolean do_source_remove = FALSE;
 
   indicator_opacity = AEROSNAP_INDICATOR_OPACITY;
 
   if (GDK_WINDOW_DESTROYED (context->window) ||
-      !ensure_snap_indicator_exists (context) ||
-      !ensure_snap_indicator_surface (context,
-                                 context->indicator_window_rect.width,
-                                 context->indicator_window_rect.height))
+      !ensure_snap_indicator_exists (context))
+    {
+      do_source_remove = TRUE;
+    }
+
+  impl = GDK_WINDOW_IMPL_WIN32 (context->window->impl);
+
+  if (!ensure_snap_indicator_surface (context,
+                                      context->indicator_window_rect.width,
+                                      context->indicator_window_rect.height,
+                                      impl->window_scale))
+    {
+      do_source_remove = TRUE;
+    }
+
+  if (do_source_remove)
     {
       context->timer = 0;
       return G_SOURCE_REMOVE;
@@ -3837,10 +3885,10 @@ redraw_indicator (gpointer user_data)
 
   last_draw = draw_indicator (context, context->draw_timestamp);
 
-  window_position.x = context->indicator_window_rect.x - _gdk_offset_x;
-  window_position.y = context->indicator_window_rect.y - _gdk_offset_y;
-  window_size.cx = context->indicator_window_rect.width;
-  window_size.cy = context->indicator_window_rect.height;
+  window_position.x = (context->indicator_window_rect.x - _gdk_offset_x) * impl->window_scale;
+  window_position.y = (context->indicator_window_rect.y - _gdk_offset_y) * impl->window_scale;
+  window_size.cx = context->indicator_window_rect.width * impl->window_scale;
+  window_size.cy = context->indicator_window_rect.height * impl->window_scale;
 
   blender.BlendOp = AC_SRC_OVER;
   blender.BlendFlags = 0;
@@ -3906,13 +3954,14 @@ unity_of_rects (GdkRectangle a,
 static void
 start_indicator_drawing (GdkW32DragMoveResizeContext *context,
                          GdkRectangle                 from,
-                         GdkRectangle                 to)
+                         GdkRectangle                 to,
+                         guint                        scale)
 {
   GdkRectangle to_adjusted, from_adjusted, from_or_to;
   gint64 indicator_animation_tick = AEROSNAP_INDICATOR_ANIMATION_TICK;
 
   GDK_NOTE (MISC, g_print ("Start drawing snap indicator %d x %d @ %d : %d -> %d x %d @ %d : %d\n",
-                           from.width, from.height, from.x, from.y, to.width, to.height, to.x, to.y));
+                           from.width * scale, from.height * scale, from.x, from.y, to.width * scale, 
to.height * scale, to.x, to.y));
 
   if (GDK_WINDOW_DESTROYED (context->window))
     return;
@@ -3922,13 +3971,14 @@ start_indicator_drawing (GdkW32DragMoveResizeContext *context,
 
   from_or_to = unity_of_rects (from, to);
 
-  if (!ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height))
+  if (!ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height, scale))
     return;
 
   to_adjusted = to;
-  adjust_indicator_rectangle (&to_adjusted, TRUE);
+  adjust_indicator_rectangle (&to_adjusted, TRUE, scale);
+
   from_adjusted = from;
-  adjust_indicator_rectangle (&from_adjusted, TRUE);
+  adjust_indicator_rectangle (&from_adjusted, TRUE, scale);
 
   context->draw_timestamp = 0;
   context->indicator_start = from_adjusted;
@@ -3956,6 +4006,7 @@ update_fullup_indicator (GdkWindow                   *window,
   SHORT maxysize;
   GdkRectangle from, to;
   GdkRectangle to_adjusted, from_adjusted, from_or_to;
+  GdkWindowImplWin32 *impl;
 
   GDK_NOTE (MISC, g_print ("Update fullup indicator\n"));
 
@@ -3965,10 +4016,13 @@ update_fullup_indicator (GdkWindow                   *window,
   if (context->shape_indicator == NULL)
     return;
 
+  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
   maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN);
   gdk_window_get_position (window, &to.x, &to.y);
-  to.width = gdk_window_get_width (window);
-  to.height = gdk_window_get_height (window);
+  to.x /= impl->window_scale;
+  to.y /= impl->window_scale;
+  to.width = gdk_window_get_width (window) * impl->window_scale;
+  to.height = gdk_window_get_height (window) * impl->window_scale;
 
   to.y = 0;
   to.height = maxysize;
@@ -3977,13 +4031,13 @@ update_fullup_indicator (GdkWindow                   *window,
   if (context->timer == 0)
     {
       from_adjusted = from;
-      adjust_indicator_rectangle (&from_adjusted, FALSE);
+      adjust_indicator_rectangle (&from_adjusted, FALSE, impl->window_scale);
 
       GDK_NOTE (MISC, g_print ("Restart fullup animation from %d x %d @ %d : %d -> %d x %d @ %d x %d\n",
                                context->indicator_target.width, context->indicator_target.height,
                                context->indicator_target.x, context->indicator_target.y,
                                to.width, to.height, to.x, to.y));
-      start_indicator_drawing (context, from_adjusted, to);
+      start_indicator_drawing (context, from_adjusted, to, impl->window_scale);
 
       return;
     }
@@ -3991,7 +4045,7 @@ update_fullup_indicator (GdkWindow                   *window,
   from_or_to = unity_of_rects (from, to);
 
   to_adjusted = to;
-  adjust_indicator_rectangle (&to_adjusted, TRUE);
+  adjust_indicator_rectangle (&to_adjusted, TRUE, impl->window_scale);
 
   GDK_NOTE (MISC, g_print ("Retarget fullup animation %d x %d @ %d : %d -> %d x %d @ %d x %d\n",
                            context->indicator_target.width, context->indicator_target.height,
@@ -4001,7 +4055,7 @@ update_fullup_indicator (GdkWindow                   *window,
   context->indicator_target = to_adjusted;
   context->indicator_window_rect = from_or_to;
 
-  ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height);
+  ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height, impl->window_scale);
 }
 
 static void
@@ -4016,12 +4070,13 @@ start_indicator (GdkWindow                   *window,
   SHORT maxysize;
   GdkRectangle start_size, end_size;
   GdkDisplay *display;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   display = gdk_window_get_display (window);
   monitor = gdk_display_get_monitor_at_point (display, x, y);
   gdk_monitor_get_workarea (monitor, &workarea);
 
-  maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+  maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN) / impl->window_scale;
   gdk_window_get_position (window, &start_size.x, &start_size.y);
   start_size.width = gdk_window_get_width (window);
   start_size.height = gdk_window_get_height (window);
@@ -4045,7 +4100,7 @@ start_indicator (GdkWindow                   *window,
       end_size.height = workarea.height;
       break;
     case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
-      end_size.x = workarea.x + workarea.width / 2;
+      end_size.x = (workarea.x + workarea.width / 2) / impl->window_scale;
       end_size.y = workarea.y;
       end_size.width = workarea.width / 2;
       end_size.height = workarea.height;
@@ -4056,7 +4111,7 @@ start_indicator (GdkWindow                   *window,
       break;
     }
 
-  start_indicator_drawing (context, start_size, end_size);
+  start_indicator_drawing (context, start_size, end_size, impl->window_scale);
 }
 
 static void
@@ -4079,18 +4134,23 @@ stop_indicator (GdkWindow                   *window,
 }
 
 static gint
-point_in_aerosnap_region (gint x, gint y, AeroSnapEdgeRegion *region)
+point_in_aerosnap_region (gint                x,
+                          gint                y,
+                          AeroSnapEdgeRegion *region,
+                          guint               scale)
 {
   gint edge, trigger;
-
-  edge = (x >= region->edge.x &&
-          y >= region->edge.y &&
-          x <= region->edge.x + region->edge.width &&
-          y <= region->edge.y + region->edge.height) ? 1 : 0;
-  trigger = (x >= region->trigger.x &&
-             y >= region->trigger.y &&
-             x <= region->trigger.x + region->trigger.width &&
-             y <= region->trigger.y + region->trigger.height) ? 1 : 0;
+  gint x_scaled = x * scale;
+  gint y_scaled = y * scale;
+
+  edge = (x_scaled >= region->edge.x &&
+          y_scaled >= region->edge.y &&
+          x_scaled <= region->edge.x + region->edge.width &&
+          y_scaled <= region->edge.y + region->edge.height) ? 1 : 0;
+  trigger = (x_scaled >= region->trigger.x &&
+             y_scaled >= region->trigger.y &&
+             x_scaled <= region->trigger.x + region->trigger.width &&
+             y_scaled <= region->trigger.y + region->trigger.height) ? 1 : 0;
   return edge + trigger;
 }
 
@@ -4107,6 +4167,7 @@ handle_aerosnap_move_resize (GdkWindow                   *window,
   gint halfright = 0;
   gint fullup = 0;
   gboolean fullup_edge = FALSE;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   if (context->op == GDK_WIN32_DRAGOP_RESIZE)
     switch (context->edge)
@@ -4127,25 +4188,25 @@ handle_aerosnap_move_resize (GdkWindow                   *window,
   for (i = 0; i < context->maximize_regions->len && maximize == 0; i++)
     {
       reg = &g_array_index (context->maximize_regions, AeroSnapEdgeRegion, i);
-      maximize = point_in_aerosnap_region (x, y, reg);
+      maximize = point_in_aerosnap_region (x, y, reg, impl->window_scale);
     }
 
   for (i = 0; i < context->halfleft_regions->len && halfleft == 0; i++)
     {
       reg = &g_array_index (context->halfleft_regions, AeroSnapEdgeRegion, i);
-      halfleft = point_in_aerosnap_region (x, y, reg);
+      halfleft = point_in_aerosnap_region (x, y, reg, impl->window_scale);
     }
 
   for (i = 0; i < context->halfright_regions->len && halfright == 0; i++)
     {
       reg = &g_array_index (context->halfright_regions, AeroSnapEdgeRegion, i);
-      halfright = point_in_aerosnap_region (x, y, reg);
+      halfright = point_in_aerosnap_region (x, y, reg, impl->window_scale);
     }
 
   for (i = 0; i < context->fullup_regions->len && fullup == 0; i++)
     {
       reg = &g_array_index (context->fullup_regions, AeroSnapEdgeRegion, i);
-      fullup = point_in_aerosnap_region (x, y, reg);
+      fullup = point_in_aerosnap_region (x, y, reg, impl->window_scale);
     }
 
 #if defined(MORE_AEROSNAP_DEBUGGING)
@@ -4442,8 +4503,8 @@ setup_drag_move_resize_context (GdkWindow                   *window,
        */
       if (op == GDK_WIN32_DRAGOP_MOVE && !maximized)
         {
-          swx += impl->margins.left;
-          swy += impl->margins.top;
+          swx += impl->margins.left / impl->window_scale;
+          swy += impl->margins.top / impl->window_scale;
           swwidth -= impl->margins_x;
           swheight -= impl->margins_y;
         }
@@ -4489,47 +4550,52 @@ setup_drag_move_resize_context (GdkWindow                   *window,
           GDK_NOTE (MISC, g_print ("W32 WM unmaximized window placement is %ld x %ld @ %ld : %ld\n",
                                    placement.rcNormalPosition.right - placement.rcNormalPosition.left,
                                    placement.rcNormalPosition.bottom - placement.rcNormalPosition.top,
-                                   placement.rcNormalPosition.left + _gdk_offset_x,
-                                   placement.rcNormalPosition.top + _gdk_offset_y));
+                                   placement.rcNormalPosition.left + _gdk_offset_x * impl->window_scale,
+                                   placement.rcNormalPosition.top + _gdk_offset_y * impl->window_scale));
 
           unmax_width = placement.rcNormalPosition.right - placement.rcNormalPosition.left;
           unmax_height = placement.rcNormalPosition.bottom - placement.rcNormalPosition.top;
 
-          shadow_unmax_width = unmax_width - impl->margins_x;
-          shadow_unmax_height = unmax_height - impl->margins_y;
+          shadow_unmax_width = unmax_width - impl->margins_x * impl->window_scale;
+          shadow_unmax_height = unmax_height - impl->margins_y * impl->window_scale;
 
-          if (offsetx < (shadow_unmax_width / 2) && offsety < (shadow_unmax_height / 2))
+          if (offsetx * impl->window_scale < (shadow_unmax_width / 2) &&
+              offsety * impl->window_scale < (shadow_unmax_height / 2))
             {
-              placement.rcNormalPosition.top = root_y - (offsety + impl->margins.top) - _gdk_offset_y;
+              placement.rcNormalPosition.top = (root_y - offsety + impl->margins.top - _gdk_offset_y) * 
impl->window_scale;
               placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
 
               if (left_half)
                 {
-                  placement.rcNormalPosition.left = root_x - (offsetx + impl->margins.left) - _gdk_offset_x;
+                  placement.rcNormalPosition.left = (root_x - offsetx + impl->margins.left - _gdk_offset_x) 
* impl->window_scale;
                   placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
                 }
               else
                 {
-                  placement.rcNormalPosition.right = root_x + (offsetx + impl->margins.right) - 
_gdk_offset_x;
+                  placement.rcNormalPosition.right = (root_x + offsetx + impl->margins.right - 
_gdk_offset_x) * impl->window_scale;
                   placement.rcNormalPosition.left = placement.rcNormalPosition.right - unmax_width;
                 }
             }
           else
             {
-              placement.rcNormalPosition.left = root_x - unmax_width / 2 - _gdk_offset_x;
+              placement.rcNormalPosition.left = (root_x * impl->window_scale) -
+                                                (unmax_width / 2) -
+                                                (_gdk_offset_x * impl->window_scale);
 
-              if (offsety < shadow_unmax_height / 2)
-                placement.rcNormalPosition.top = root_y - (offsety + impl->margins.top) - _gdk_offset_y;
+              if (offsety * impl->window_scale < shadow_unmax_height / 2)
+                placement.rcNormalPosition.top = (root_y - offsety + impl->margins.top - _gdk_offset_y) * 
impl->window_scale;
               else
-                placement.rcNormalPosition.top = root_y - unmax_height / 2 - _gdk_offset_y;
+                placement.rcNormalPosition.top = (root_y * impl->window_scale) -
+                                                 (unmax_height / 2) -
+                                                 (_gdk_offset_y * impl->window_scale);
 
               placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
               placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
             }
 
           GDK_NOTE (MISC, g_print ("Unmaximized window will be at %ld : %ld\n",
-                                   placement.rcNormalPosition.left + _gdk_offset_x,
-                                   placement.rcNormalPosition.top + _gdk_offset_y));
+                                   placement.rcNormalPosition.left + _gdk_offset_x * impl->window_scale,
+                                   placement.rcNormalPosition.top + _gdk_offset_y * impl->window_scale));
 
           API_CALL (SetWindowPlacement, (GDK_WINDOW_HWND (window), &placement));
         }
@@ -4550,12 +4616,12 @@ setup_drag_move_resize_context (GdkWindow                   *window,
 
           if (offsetx < snew_pos.width / 2 && offsety < snew_pos.height / 2)
             {
-              new_pos.y = root_y - (offsety + impl->margins.top);
+              new_pos.y = root_y - offsety + impl->margins.top / impl->window_scale;
 
               if (left_half)
-                new_pos.x = root_x - (offsetx + impl->margins.left);
+                new_pos.x = root_x - offsetx + impl->margins.left / impl->window_scale;
               else
-                new_pos.x = root_x + (offsetx + impl->margins.left) - new_pos.width;
+                new_pos.x = root_x + offsetx + impl->margins.left / impl->window_scale - new_pos.width;
             }
           else
             {
@@ -4716,12 +4782,13 @@ gdk_win32_window_do_move_resize_drag (GdkWindow *window,
     return;
 
   new_rect = context->start_rect;
-  diffx = x - context->start_root_x;
-  diffy = y - context->start_root_y;
+  diffx = (x - context->start_root_x) * impl->window_scale;
+  diffy = (y - context->start_root_y) * impl->window_scale;
 
   switch (context->op)
     {
     case GDK_WIN32_DRAGOP_RESIZE:
+
       switch (context->edge)
         {
         case GDK_WINDOW_EDGE_NORTH_WEST:
@@ -4886,10 +4953,10 @@ gdk_win32_window_do_move_resize_drag (GdkWindow *window,
       _gdk_win32_adjust_client_rect (window, &new_rect);
 
       /* Convert GDK screen coordinates to W32 desktop coordinates */
-      new_rect.left -= _gdk_offset_x;
-      new_rect.right -= _gdk_offset_x;
-      new_rect.top -= _gdk_offset_y;
-      new_rect.bottom -= _gdk_offset_y;
+      new_rect.left -= _gdk_offset_x * impl->window_scale;
+      new_rect.right -= _gdk_offset_x * impl->window_scale;
+      new_rect.top -= _gdk_offset_y * impl->window_scale;
+      new_rect.bottom -= _gdk_offset_y * impl->window_scale;
 
       window_position.x = new_rect.left;
       window_position.y = new_rect.top;
@@ -4968,6 +5035,7 @@ gdk_win32_window_begin_resize_drag (GdkWindow     *window,
    * will only work with button 1 (left), since Windows only allows window
    * dragging using the left mouse button.
    */
+
   if (button != 1)
     return;
 
@@ -5038,7 +5106,7 @@ gdk_win32_window_iconify (GdkWindow *window)
   if (GDK_WINDOW_IS_MAPPED (window))
     {
       old_active_window = GetActiveWindow ();
-      GtkShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
+      GtkShowWindow (window, SW_MINIMIZE);
       if (old_active_window != GDK_WINDOW_HWND (window))
        SetActiveWindow (old_active_window);
     }
@@ -5099,6 +5167,7 @@ gdk_win32_window_unstick (GdkWindow *window)
 static void
 gdk_win32_window_maximize (GdkWindow *window)
 {
+
   g_return_if_fail (GDK_IS_WINDOW (window));
 
   if (GDK_WINDOW_DESTROYED (window))
@@ -5109,7 +5178,7 @@ gdk_win32_window_maximize (GdkWindow *window)
                           _gdk_win32_window_state_to_string (window->state)));
 
   if (GDK_WINDOW_IS_MAPPED (window))
-    GtkShowWindow (GDK_WINDOW_HWND (window), SW_MAXIMIZE);
+    GtkShowWindow (window, SW_MAXIMIZE);
   else
     gdk_synthesize_window_state (window,
                                 0,
@@ -5129,7 +5198,7 @@ gdk_win32_window_unmaximize (GdkWindow *window)
                           _gdk_win32_window_state_to_string (window->state)));
 
   if (GDK_WINDOW_IS_MAPPED (window))
-    GtkShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
+    GtkShowWindow (window, SW_RESTORE);
   else
     gdk_synthesize_window_state (window,
                                 GDK_WINDOW_STATE_MAXIMIZED,
@@ -5183,8 +5252,8 @@ gdk_win32_window_fullscreen (GdkWindow *window)
                      (fi->style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP);
 
       API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), HWND_TOP,
-                              x, y, width, height,
-                              SWP_NOCOPYBITS | SWP_SHOWWINDOW));
+                x, y, width, height,
+                SWP_NOCOPYBITS | SWP_SHOWWINDOW));
     }
 }
 
@@ -5281,13 +5350,13 @@ gdk_win32_window_focus (GdkWindow *window,
                           _gdk_win32_window_state_to_string (window->state)));
 
   if (window->state & GDK_WINDOW_STATE_MAXIMIZED)
-    GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMAXIMIZED);
+    GtkShowWindow (window, SW_SHOWMAXIMIZED);
   else if (window->state & GDK_WINDOW_STATE_ICONIFIED)
-    GtkShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
+    GtkShowWindow (window, SW_RESTORE);
   else if (!IsWindowVisible (GDK_WINDOW_HWND (window)))
-    GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNORMAL);
+    GtkShowWindow (window, SW_SHOWNORMAL);
   else
-    GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOW);
+    GtkShowWindow (window, SW_SHOW);
 
   SetFocus (GDK_WINDOW_HWND (window));
 }
@@ -5428,7 +5497,8 @@ gdk_win32_window_get_type_hint (GdkWindow *window)
 static HRGN
 cairo_region_to_hrgn (const cairo_region_t *region,
                      gint                  x_origin,
-                     gint                  y_origin)
+                     gint                  y_origin,
+                     guint                 scale)
 {
   HRGN hrgn;
   RGNDATA *rgndata;
@@ -5451,10 +5521,10 @@ cairo_region_to_hrgn (const cairo_region_t *region,
       rect = ((RECT *) rgndata->Buffer) + rgndata->rdh.nCount++;
 
       cairo_region_get_rectangle (region, i, &r);
-      rect->left = r.x + x_origin;
-      rect->right = rect->left + r.width;
-      rect->top = r.y + y_origin;
-      rect->bottom = rect->top + r.height;
+      rect->left = (r.x + x_origin) * scale;
+      rect->right = (rect->left + r.width) * scale;
+      rect->top = (r.y + y_origin) * scale;
+      rect->bottom = (rect->top + r.height) * scale;
 
       if (rect->left < rgndata->rdh.rcBound.left)
        rgndata->rdh.rcBound.left = rect->left;
@@ -5479,6 +5549,8 @@ gdk_win32_window_shape_combine_region (GdkWindow       *window,
                                       gint             offset_x,
                                       gint             offset_y)
 {
+  GdkWindowImplWin32 *impl;
+
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
@@ -5491,8 +5563,9 @@ gdk_win32_window_shape_combine_region (GdkWindow       *window,
   else
     {
       HRGN hrgn;
+      impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
-      hrgn = cairo_region_to_hrgn (shape_region, 0, 0);
+      hrgn = cairo_region_to_hrgn (shape_region, 0, 0, impl->window_scale);
 
       GDK_NOTE (MISC, g_print ("gdk_win32_window_shape_combine_region: %p: %p\n",
                               GDK_WINDOW_HWND (window),
@@ -5562,10 +5635,11 @@ gdk_win32_window_get_shape (GdkWindow *window)
 {
   HRGN hrgn = CreateRectRgn (0, 0, 0, 0);
   int  type = GetWindowRgn (GDK_WINDOW_HWND (window), hrgn);
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   if (type == SIMPLEREGION || type == COMPLEXREGION)
     {
-      cairo_region_t *region = _gdk_win32_hrgn_to_region (hrgn);
+      cairo_region_t *region = _gdk_win32_hrgn_to_region (hrgn, impl->window_scale);
 
       DeleteObject (hrgn);
       return region;
@@ -5597,6 +5671,7 @@ gdk_win32_window_show_window_menu (GdkWindow *window,
 {
   double event_x, event_y;
   gint x, y;
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
 
   switch (event->type)
     {
@@ -5613,7 +5688,10 @@ gdk_win32_window_show_window_menu (GdkWindow *window,
   x = event_x - _gdk_offset_x;
   y = event_y - _gdk_offset_y;
 
-  SendMessage (GDK_WINDOW_HWND (window), WM_SYSMENU, 0, MAKELPARAM (x, y));
+  SendMessage (GDK_WINDOW_HWND (window),
+               WM_SYSMENU,
+               0,
+               MAKELPARAM (x * impl->window_scale, y * impl->window_scale));
 
   return TRUE;
 }
@@ -5719,8 +5797,8 @@ gdk_win32_ref_cairo_surface_layered (GdkWindow          *window,
   gdk_window_get_position (window, &x, &y);
   window_rect.left = x;
   window_rect.top = y;
-  window_rect.right = window_rect.left + gdk_window_get_width (window);
-  window_rect.bottom = window_rect.top + gdk_window_get_height (window);
+  window_rect.right = window_rect.left + gdk_window_get_width (window) * impl->window_scale;
+  window_rect.bottom = window_rect.top + gdk_window_get_height (window) * impl->window_scale;
 
   /* Turn client area into window area */
   _gdk_win32_adjust_client_rect (window, &window_rect);
@@ -5735,7 +5813,9 @@ gdk_win32_ref_cairo_surface_layered (GdkWindow          *window,
       cairo_t *cr;
 
       /* Create larger cache surface, copy old cache surface over it */
-      new_cache = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
+      new_cache = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
+                                                       width,
+                                                       height);
 
       if (impl->cache_surface)
         {
@@ -5751,6 +5831,10 @@ gdk_win32_ref_cairo_surface_layered (GdkWindow          *window,
 
       impl->cache_surface = new_cache;
 
+      cairo_surface_set_device_scale (impl->cache_surface,
+                                      impl->window_scale,
+                                      impl->window_scale);
+
       if (impl->cairo_surface)
         cairo_surface_destroy (impl->cairo_surface);
 
@@ -5763,10 +5847,16 @@ gdk_win32_ref_cairo_surface_layered (GdkWindow          *window,
    */
   if (!impl->cairo_surface)
     {
-      impl->cairo_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
+      impl->cairo_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
+                                                                 width,
+                                                                 height);
       impl->dib_width = width;
       impl->dib_height = height;
 
+      cairo_surface_set_device_scale (impl->cairo_surface,
+                                      impl->window_scale,
+                                      impl->window_scale);
+
       cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
                                   impl, gdk_win32_cairo_surface_destroy);
     }
@@ -5797,6 +5887,9 @@ gdk_win32_ref_cairo_surface (GdkWindow *window)
        return NULL;
 
       impl->cairo_surface = cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_ARGB32);
+      cairo_surface_set_device_scale (impl->cairo_surface,
+                                      impl->window_scale,
+                                      impl->window_scale);
 
       cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
                                   impl, gdk_win32_cairo_surface_destroy);
@@ -5808,8 +5901,8 @@ gdk_win32_ref_cairo_surface (GdkWindow *window)
 }
 
 BOOL WINAPI
-GtkShowWindow (HWND hwnd,
-               int  cmd_show)
+GtkShowWindow (GdkWindow *window,
+               int        cmd_show)
 {
   cairo_t *cr;
   cairo_surface_t *surface;
@@ -5820,6 +5913,9 @@ GtkShowWindow (HWND hwnd,
   POINT source_point;
   BLENDFUNCTION blender;
 
+  HWND hwnd = GDK_WINDOW_HWND (window);
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
   switch (cmd_show)
     {
     case SW_FORCEMINIMIZE:
@@ -5859,7 +5955,10 @@ GtkShowWindow (HWND hwnd,
       blender.SourceConstantAlpha = 255;
 
       /* Create a surface of appropriate size and clear it */
-      surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, window_size.cx, window_size.cy);
+      surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
+                                                     window_size.cx,
+                                                     window_size.cy);
+      cairo_surface_set_device_scale (surface, impl->window_scale, impl->window_scale);
       cr = cairo_create (surface);
       cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
       cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
@@ -5904,13 +6003,77 @@ gdk_win32_window_set_shadow_width (GdkWindow *window,
     return;
 
   impl->margins.left = left;
-  impl->margins.right = right;
+  impl->margins.right = right * impl->window_scale;
   impl->margins.top = top;
-  impl->margins.bottom = bottom;
+  impl->margins.bottom = bottom * impl->window_scale;
   impl->margins_x = left + right;
   impl->margins_y = top + bottom;
 }
 
+
+gint
+_gdk_win32_window_get_scale_factor (GdkWindow *window)
+{
+  GdkDisplay *display;
+  GdkWindowImplWin32 *impl;
+
+  GdkWin32Display *win32_display;
+  UINT dpix, dpiy;
+  gboolean is_scale_acquired;
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return 1;
+
+  g_return_val_if_fail (window != NULL, 1);
+
+  display = gdk_window_get_display (window);
+  impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+  win32_display = GDK_WIN32_DISPLAY (display);
+
+  if (win32_display->dpi_aware_type != PROCESS_DPI_UNAWARE)
+    {
+      if (win32_display->has_fixed_scale)
+        impl->window_scale = win32_display->window_scale;
+      else
+        impl->window_scale = _gdk_win32_display_get_monitor_scale_factor (win32_display,
+                                                                          NULL,
+                                                                          GDK_WINDOW_HWND (window),
+                                                                          NULL);
+
+      return impl->window_scale;
+    }
+  else
+    {
+      if (win32_display->has_fixed_scale)
+        {
+          static gsize hidpi_msg_displayed = 0;
+
+          if (g_once_init_enter (&hidpi_msg_displayed))
+            {
+              g_message ("Note: GDK_SCALE is ignored as HiDPI awareness is disabled.");
+              g_once_init_leave (&hidpi_msg_displayed, 1);
+            }
+        }
+
+      /* Application is not DPI aware, don't bother */
+      return 1;
+    }
+}
+
+void
+_gdk_win32_window_get_unscaled_size (GdkWindow *window,
+                                    gint      *unscaled_width,
+                                    gint      *unscaled_height)
+{
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
+
+  if (unscaled_width)
+    *unscaled_width = impl->unscaled_width;
+  if (unscaled_height)
+    *unscaled_height = impl->unscaled_height;
+}
+
 static void
 gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
 {
@@ -6002,6 +6165,8 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
   impl_class->delete_property = _gdk_win32_window_delete_property;
   impl_class->create_gl_context = _gdk_win32_window_create_gl_context;
   impl_class->invalidate_for_new_frame = _gdk_win32_window_invalidate_for_new_frame;
+  impl_class->get_scale_factor = _gdk_win32_window_get_scale_factor;
+  impl_class->get_unscaled_size = _gdk_win32_window_get_unscaled_size;
 }
 
 HGDIOBJ
diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h
index 508087b..de18c45 100644
--- a/gdk/win32/gdkwindow-win32.h
+++ b/gdk/win32/gdkwindow-win32.h
@@ -96,6 +96,14 @@ enum _GdkW32WindowDragOp
 
 typedef enum _GdkW32WindowDragOp GdkW32WindowDragOp;
 
+typedef enum _GdkWin32MonitorDpiType
+{
+  MDT_EFFECTIVE_DPI  = 0,
+  MDT_ANGULAR_DPI    = 1,
+  MDT_RAW_DPI        = 2,
+  MDT_DEFAULT        = MDT_EFFECTIVE_DPI
+} GdkWin32MonitorDpiType;
+
 struct _GdkW32DragMoveResizeContext
 {
   /* The window that is being moved/resized */
@@ -333,6 +341,11 @@ struct _GdkWindowImplWin32
    * They are removed at the first opportunity (usually WM_INITMENU).
    */
   LONG_PTR temp_styles;
+
+  /* scale of window on HiDPI */
+  gint window_scale;
+  gint unscaled_width;
+  gint unscaled_height;
 };
 
 struct _GdkWindowImplWin32Class
@@ -352,6 +365,8 @@ void  _gdk_win32_window_tmp_reset_parent_bg (GdkWindow *window);
 
 void  _gdk_win32_window_update_style_bits   (GdkWindow *window);
 
+gint  _gdk_win32_window_get_scale_factor    (GdkWindow *window);
+
 G_END_DECLS
 
 #endif /* __GDK_WINDOW_WIN32_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]