[gtk/master.win32.improve.hidpi] GDK-Win32: Use SetProcessDpiAwarenessContext() where available



commit 4a79484d2abc48fd8784ab62fa5cc40f8ad01024
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Wed Dec 4 18:41:05 2019 +0800

    GDK-Win32: Use SetProcessDpiAwarenessContext() where available
    
    This allows us to use DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 for the
    DPI awareness mode, which will help us to better support use cases with
    multiple monitors.  This is actualy a more advaned version of the
    current PROCESS_PER_MONITOR_DPI_AWARE via using SetProcessDpiAwareness().
    
    Note that this is not enabled by default, but also enabled via using
    GDK_WIN32_PER_MONITOR_HIDPI, as in the PROCESS_PER_MONITOR_DPI_AWARE
    case.
    
    Note also, that appliation compatibility settings and DPI-awareness
    manifests takes precedence over this API call, as before.

 gdk/win32/gdkdisplay-win32.c | 75 +++++++++++++++++++++++++++++++++++++++++---
 gdk/win32/gdkdisplay-win32.h | 32 ++++++++++++++++++-
 2 files changed, 101 insertions(+), 6 deletions(-)
---
diff --git a/gdk/win32/gdkdisplay-win32.c b/gdk/win32/gdkdisplay-win32.c
index 9cd080012c..4c0b4f9585 100644
--- a/gdk/win32/gdkdisplay-win32.c
+++ b/gdk/win32/gdkdisplay-win32.c
@@ -720,6 +720,9 @@ _gdk_win32_enable_hidpi (GdkWin32Display *display)
   gboolean check_for_dpi_awareness = FALSE;
   gboolean have_hpi_disable_envvar = FALSE;
 
+  HMODULE user32;
+  user32 = GetModuleHandleW (L"user32.dll");
+
   enum dpi_aware_status {
     DPI_STATUS_PENDING,
     DPI_STATUS_SUCCESS,
@@ -731,6 +734,17 @@ _gdk_win32_enable_hidpi (GdkWin32Display *display)
     {
       /* If we are on Windows 8.1 or later, cache up functions from shcore.dll, by all means */
       display->have_at_least_win81 = TRUE;
+
+      if (user32 != NULL)
+        {
+          display->user32_dpi_funcs.setPDAC =
+            (funcSPDAC) GetProcAddress (user32, "SetProcessDpiAwarenessContext");
+          display->user32_dpi_funcs.getTDAC =
+            (funcGTDAC) GetProcAddress (user32, "GetThreadDpiAwarenessContext");
+          display->user32_dpi_funcs.areDACEqual =
+            (funcADACE) GetProcAddress (user32, "AreDpiAwarenessContextsEqual");
+        }
+
       display->shcore_funcs.hshcore = LoadLibraryW (L"shcore.dll");
 
       if (display->shcore_funcs.hshcore != NULL)
@@ -750,10 +764,8 @@ _gdk_win32_enable_hidpi (GdkWin32Display *display)
   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)
         {
@@ -770,7 +782,42 @@ _gdk_win32_enable_hidpi (GdkWin32Display *display)
       if (display->have_at_least_win81)
         {
           /* then make the GDK-using app DPI-aware */
-          if (display->shcore_funcs.setDpiAwareFunc != NULL)
+          if (display->user32_dpi_funcs.setPDAC != NULL)
+            {
+              HANDLE hidpi_mode_ctx;
+              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_ctx = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
+                  hidpi_mode = PROCESS_PER_MONITOR_DPI_AWARE;
+                }
+              else
+                {
+                  hidpi_mode_ctx = DPI_AWARENESS_CONTEXT_SYSTEM_AWARE;
+                  hidpi_mode = PROCESS_SYSTEM_DPI_AWARE;
+                }
+
+              if (display->user32_dpi_funcs.setPDAC (hidpi_mode_ctx))
+                {
+                  display->dpi_aware_type = hidpi_mode;
+                  status = DPI_STATUS_SUCCESS;
+                }
+              else
+                {
+                  DWORD err = GetLastError ();
+
+                  if (err == ERROR_ACCESS_DENIED)
+                    check_for_dpi_awareness = TRUE;
+                  else
+                    {
+                      display->dpi_aware_type = PROCESS_DPI_UNAWARE;
+                      status = DPI_STATUS_FAILED;
+                    }
+                }
+            }
+          else if (display->shcore_funcs.setDpiAwareFunc != NULL)
             {
               GdkWin32ProcessDpiAwareness hidpi_mode;
 
@@ -841,7 +888,25 @@ _gdk_win32_enable_hidpi (GdkWin32Display *display)
     {
       if (display->have_at_least_win81)
         {
-          if (display->shcore_funcs.getDpiAwareFunc != NULL)
+          if (display->user32_dpi_funcs.getTDAC != NULL &&
+              display->user32_dpi_funcs.areDACEqual != NULL)
+            {
+              HANDLE dpi_aware_ctx = display->user32_dpi_funcs.getTDAC ();
+              if (display->user32_dpi_funcs.areDACEqual (dpi_aware_ctx,
+                                                         DPI_AWARENESS_CONTEXT_UNAWARE))
+                /* This means the DPI awareness setting was forcefully disabled */
+                status = DPI_STATUS_DISABLED;
+              else
+                {
+                  status = DPI_STATUS_SUCCESS;
+                  if (display->user32_dpi_funcs.areDACEqual (dpi_aware_ctx,
+                                                             DPI_AWARENESS_CONTEXT_SYSTEM_AWARE))
+                    display->dpi_aware_type = PROCESS_SYSTEM_DPI_AWARE;
+                  else
+                    display->dpi_aware_type = PROCESS_PER_MONITOR_DPI_AWARE_V2;
+                }
+            }
+          else if (display->shcore_funcs.getDpiAwareFunc != NULL)
             {
               display->shcore_funcs.getDpiAwareFunc (NULL, &display->dpi_aware_type);
 
@@ -884,7 +949,7 @@ _gdk_win32_enable_hidpi (GdkWin32Display *display)
           /* 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.");
+                   "      manifest, DPI awareness is still enabled.\n");
         }
     }
 
diff --git a/gdk/win32/gdkdisplay-win32.h b/gdk/win32/gdkdisplay-win32.h
index a4d9cc7378..91ce0db238 100644
--- a/gdk/win32/gdkdisplay-win32.h
+++ b/gdk/win32/gdkdisplay-win32.h
@@ -29,9 +29,24 @@
 typedef enum _GdkWin32ProcessDpiAwareness {
   PROCESS_DPI_UNAWARE = 0,
   PROCESS_SYSTEM_DPI_AWARE = 1,
-  PROCESS_PER_MONITOR_DPI_AWARE = 2
+  PROCESS_PER_MONITOR_DPI_AWARE = 2,
+  PROCESS_PER_MONITOR_DPI_AWARE_V2 = 3, /* Newer HiDPI type for Windows 10 1607+ */
 } GdkWin32ProcessDpiAwareness;
 
+/* From https://docs.microsoft.com/en-US/windows/win32/hidpi/dpi-awareness-context */
+/* DPI_AWARENESS_CONTEXT is declared by DEFINE_HANDLE */
+#ifndef DPI_AWARENESS_CONTEXT_UNAWARE
+#define DPI_AWARENESS_CONTEXT_UNAWARE (HANDLE)-1
+#endif
+
+#ifndef DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
+#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE (HANDLE)-2
+#endif
+
+#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
+#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (HANDLE)-4
+#endif
+
 typedef enum _GdkWin32MonitorDpiType { 
   MDT_EFFECTIVE_DPI  = 0,
   MDT_ANGULAR_DPI    = 1,
@@ -59,10 +74,25 @@ typedef struct _GdkWin32ShcoreFuncs
 typedef BOOL (WINAPI *funcSetProcessDPIAware) (void);
 typedef BOOL (WINAPI *funcIsProcessDPIAware)  (void);
 
+/*
+ * funcSPDAC is SetProcessDpiAwarenessContext() and
+ * funcGTDAC is GetThreadDpiAwarenessContext() and
+ * funcADACE is AreDpiAwarenessContextsEqual() provided by user32.dll, on
+ * Windows 10 Creator Edition and later.
+ * Treat HANDLE as void*, for convenience, since DPI_AWARENESS_CONTEXT is
+ * declared using DEFINE_HANDLE.
+ */
+typedef BOOL (WINAPI *funcSPDAC)  (void *);
+typedef HANDLE (WINAPI *funcGTDAC)  (void);
+typedef BOOL (WINAPI *funcADACE) (void *, void *);
+
 typedef struct _GdkWin32User32DPIFuncs
 {
   funcSetProcessDPIAware setDpiAwareFunc;
   funcIsProcessDPIAware isDpiAwareFunc;
+  funcSPDAC setPDAC;
+  funcGTDAC getTDAC;
+  funcADACE areDACEqual;
 } GdkWin32User32DPIFuncs;
 
 struct _GdkWin32Display


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