GDK W32: Apply HiDPI scale properly to monitors
authorРуслан Ижбулатов <lrn1986@gmail.com>
Fri, 17 Feb 2017 15:59:32 +0000 (15:59 +0000)
committerРуслан Ижбулатов <lrn1986@gmail.com>
Sun, 19 Feb 2017 07:00:17 +0000 (07:00 +0000)
Previously HiDPI scale was retrieved and applied too late in the initialization
process to affect monitor size and monitor workarea size, but the code that
initializes these sizes *did* try to use the scale, even though it was always
getting scale=1.

To fix this, move the too-late code into monitor enumeration routine.
This also fixes a probable semantic bug where width and height were divided
by scale, again.

Now monitor and workarea should be in application pixels (i.e. divided by scale),
as intended.

https://bugzilla.gnome.org/show_bug.cgi?id=778835

gdk/win32/gdkdisplay-win32.c
gdk/win32/gdkmonitor-win32.c

index 521963654744f1362eb5134946f6260285b2dea3..b72b1c7dc1dc7bf0b9a7f110706a8f757419957c 100644 (file)
@@ -195,42 +195,6 @@ _gdk_win32_display_init_monitors (GdkWin32Display *win32_display)
       g_ptr_array_insert (win32_display->monitors, 0, primary_to_move);
       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;
 }
 
index ea58cb5fc58cf07ce2af876ef0485fe2a64e0387..56b4a843eb8a796ff3bb6c7b12a9510aa2e8dfb2 100644 (file)
@@ -33,6 +33,8 @@
 
 #include "config.h"
 
+#include "gdkprivate-win32.h"
+#include "gdkdisplay-win32.h"
 #include "gdkmonitor-win32.h"
 
 #include <glib.h>
@@ -681,7 +683,43 @@ enum_monitor (HMONITOR hmonitor,
           /* This is the reason this function exists. This data is not available
            * via other functions.
            */
-          scale = gdk_monitor_get_scale_factor (mon);
+          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);
+          /* This is temporary, scale will be applied below */
+          w32mon->work_rect = rect;
+
+          if (data->display->has_fixed_scale)
+            scale = data->display->window_scale;
+          else
+            {
+              /* First acquire the scale using the current screen */
+              scale = _gdk_win32_display_get_monitor_scale_factor (data->display, NULL, NULL, NULL);
+
+              /* acquire the scale using the monitor which the window is nearest on Windows 8.1+ */
+              if (data->display->have_at_least_win81)
+                {
+                  HMONITOR hmonitor;
+                  POINT pt;
+
+                  /* Not subtracting _gdk_offset_x and _gdk_offset_y because they will only
+                   * be added later on, in _gdk_win32_display_get_monitor_list().
+                   */
+                  pt.x = w32mon->work_rect.x + w32mon->work_rect.width / 2;
+                  pt.y = w32mon->work_rect.y + w32mon->work_rect.height / 2;
+                  hmonitor = MonitorFromPoint (pt, MONITOR_DEFAULTTONEAREST);
+                  scale = _gdk_win32_display_get_monitor_scale_factor (data->display, hmonitor, NULL, NULL);
+                }
+            }
+
+          gdk_monitor_set_scale_factor (mon, scale);
+          /* Now apply the scale to the work rectangle */
+          w32mon->work_rect.x /= scale;
+          w32mon->work_rect.y /= scale;
+          w32mon->work_rect.width /= scale;
+          w32mon->work_rect.height /= scale;
+
           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;
@@ -689,12 +727,6 @@ enum_monitor (HMONITOR hmonitor,
           gdk_monitor_set_position (mon, rect.x, rect.y);
           gdk_monitor_set_size (mon, rect.width, rect.height);
 
-          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)
             {
               /* Put primary monitor at index 0, just in case somebody needs