Automatic DPI for all platforms, per monitor DPI for Windows.
authorWouter <waterflames>
Sat, 11 Mar 2017 02:27:08 +0000 (03:27 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Sat, 25 Mar 2017 10:22:16 +0000 (11:22 +0100)
For Windows 8.1 and X11 (Linux, BSD) now use the DPI specified by the operating
system, which previously only worked on macOS. For Windows this is handled per
monitor, for X11 this is based on Xft.dpi or xrandr --dpi. This should result
in appropriate font and button sizes by default in most cases.

The UI has been simplified to a single UI Scale factor relative to the automatic
DPI, instead of two DPI and Virtual Pixel Size settings. There is forward and
backwards compatibility for existing user preferences.

Reviewed By: brecht, LazyDodo

Differential Revision: https://developer.blender.org/D2539

18 files changed:
intern/ghost/GHOST_C-api.h
intern/ghost/GHOST_IWindow.h
intern/ghost/GHOST_Types.h
intern/ghost/intern/GHOST_C-api.cpp
intern/ghost/intern/GHOST_SystemWin32.cpp
intern/ghost/intern/GHOST_Window.h
intern/ghost/intern/GHOST_WindowSDL.cpp
intern/ghost/intern/GHOST_WindowSDL.h
intern/ghost/intern/GHOST_WindowWin32.cpp
intern/ghost/intern/GHOST_WindowWin32.h
intern/ghost/intern/GHOST_WindowX11.cpp
intern/ghost/intern/GHOST_WindowX11.h
release/scripts/startup/bl_ui/space_userpref.py
source/blender/blenloader/intern/versioning_defaults.c
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesrna/intern/rna_userdef.c
source/blender/windowmanager/intern/wm_window.c
source/blender/windowmanager/wm_window.h

index ff1922a..6887063 100644 (file)
@@ -907,6 +907,11 @@ extern int GHOST_UseNativePixels(void);
  */
 extern float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle);
 
+/**
+ * Returns the suggested DPI for this window.
+ */
+extern GHOST_TUns16 GHOST_GetDPIHint(GHOST_WindowHandle windowhandle);
+
 /**
  * Enable IME attached to the given window, i.e. allows user-input
  * events to be dispatched to the IME.
index 688ebec..4a4d6be 100644 (file)
@@ -332,6 +332,12 @@ public:
 
        virtual float getNativePixelSize(void) = 0;
 
+       /**
+        * Returns the recommended DPI for this window.
+        * \return The recommended DPI for this window.
+        */
+       virtual GHOST_TUns16 getDPIHint() = 0;
+
 #ifdef WITH_INPUT_IME
        /**
         * Enable IME attached to the given window, i.e. allows user-input
index 9ee4599..02b5063 100644 (file)
@@ -189,6 +189,7 @@ typedef enum {
        GHOST_kEventWindowUpdate,
        GHOST_kEventWindowSize,
        GHOST_kEventWindowMove,
+       GHOST_kEventWindowDPIHintChanged,
        
        GHOST_kEventDraggingEntered,
        GHOST_kEventDraggingUpdated,
index 41bc735..ce65318 100644 (file)
@@ -914,6 +914,12 @@ float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle)
        return 1.0f;
 }
 
+GHOST_TUns16 GHOST_GetDPIHint(GHOST_WindowHandle windowhandle)
+{
+       GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
+       return window->getDPIHint();
+}
+
 #ifdef WITH_INPUT_IME
 
 void GHOST_BeginIME(GHOST_WindowHandle windowhandle,
index 7d55a97..240d7cc 100644 (file)
 #define VK_MEDIA_PLAY_PAUSE 0xB3
 #endif // VK_MEDIA_PLAY_PAUSE
 
+// Window message newer than Windows 7
+#ifndef WM_DPICHANGED
+#define WM_DPICHANGED 0x02E0
+#endif // WM_DPICHANGED
+
 /* Workaround for some laptop touchpads, some of which seems to
  * have driver issues which makes it so window function receives
  * the message, but PeekMessage doesn't pick those messages for
@@ -152,6 +157,27 @@ static void initRawInput()
 #undef DEVICE_COUNT
 }
 
+#ifndef DPI_ENUMS_DECLARED
+typedef enum PROCESS_DPI_AWARENESS {
+       PROCESS_DPI_UNAWARE = 0,
+       PROCESS_SYSTEM_DPI_AWARE = 1,
+       PROCESS_PER_MONITOR_DPI_AWARE = 2
+} PROCESS_DPI_AWARENESS;
+
+typedef enum MONITOR_DPI_TYPE {
+       MDT_EFFECTIVE_DPI = 0,
+       MDT_ANGULAR_DPI = 1,
+       MDT_RAW_DPI = 2,
+       MDT_DEFAULT = MDT_EFFECTIVE_DPI
+} MONITOR_DPI_TYPE;
+
+#define USER_DEFAULT_SCREEN_DPI 96
+
+#define DPI_ENUMS_DECLARED
+#endif
+typedef HRESULT(API * GHOST_WIN32_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);
+typedef BOOL(API * GHOST_WIN32_EnableNonClientDpiScaling)(HWND);
+
 GHOST_SystemWin32::GHOST_SystemWin32()
        : m_hasPerformanceCounter(false), m_freq(0), m_start(0)
 {
@@ -161,6 +187,18 @@ GHOST_SystemWin32::GHOST_SystemWin32()
 
        m_consoleStatus = 1;
 
+       // Tell Windows we are per monitor DPI aware. This disables the default
+       // blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI.
+       HMODULE m_shcore = ::LoadLibrary("Shcore.dll");
+       if (m_shcore) {
+               GHOST_WIN32_SetProcessDpiAwareness fpSetProcessDpiAwareness =
+                       (GHOST_WIN32_SetProcessDpiAwareness) ::GetProcAddress(m_shcore, "SetProcessDpiAwareness");
+
+               if (fpSetProcessDpiAwareness) {
+                       fpSetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
+               }
+       }
+
        // Check if current keyboard layout uses AltGr and save keylayout ID for
        // specialized handling if keys like VK_OEM_*. I.e. french keylayout
        // generates VK_OEM_8 for their exclamation key (key left of right shift)
@@ -922,6 +960,20 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
        GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized");
 
        if (hwnd) {
+               if(msg == WM_NCCREATE) {
+                       // Tell Windows to automatically handle scaling of non-client areas
+                       // such as the caption bar. EnableNonClientDpiScaling was introduced in Windows 10
+                       HMODULE m_user32 = ::LoadLibrary("User32.dll");
+                       if (m_user32) {
+                               GHOST_WIN32_EnableNonClientDpiScaling fpEnableNonClientDpiScaling =
+                                       (GHOST_WIN32_EnableNonClientDpiScaling) ::GetProcAddress(m_user32, "EnableNonClientDpiScaling");
+
+                               if (fpEnableNonClientDpiScaling) {
+                                       fpEnableNonClientDpiScaling(hwnd);
+                               }
+                       }
+               }
+
                GHOST_WindowWin32 *window = (GHOST_WindowWin32 *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
                if (window) {
                        switch (msg) {
@@ -1293,6 +1345,32 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                                event = processWindowEvent(GHOST_kEventWindowMove, window);
                                        }
 
+                                       break;
+                               case WM_DPICHANGED:
+                                       /* The WM_DPICHANGED message is sent when the effective dots per inch (dpi) for a window has changed.
+                                       * The DPI is the scale factor for a window. There are multiple events that can cause the DPI to
+                                       * change such as when the window is moved to a monitor with a different DPI.
+                                       */
+                                       {
+                                               WORD newYAxisDPI = HIWORD(wParam);
+                                               WORD newXAxisDPI = LOWORD(wParam);
+                                               // The suggested new size and position of the window.
+                                               RECT* const suggestedWindowRect = (RECT*)lParam;
+
+                                               // Push DPI change event first
+                                               system->pushEvent(processWindowEvent(GHOST_kEventWindowDPIHintChanged, window));
+                                               system->dispatchEvents();
+                                               eventHandled = true;
+
+                                               // Then move and resize window
+                                               SetWindowPos(hwnd,
+                                                       NULL,
+                                                       suggestedWindowRect->left,
+                                                       suggestedWindowRect->top,
+                                                       suggestedWindowRect->right - suggestedWindowRect->left,
+                                                       suggestedWindowRect->bottom - suggestedWindowRect->top,
+                                                       SWP_NOZORDER | SWP_NOACTIVATE);
+                                       }
                                        break;
                                ////////////////////////////////////////////////////////////////////////
                                // Window events, ignored
index d778628..2798bdf 100644 (file)
@@ -295,6 +295,15 @@ public:
                return 1.0f;
        }
 
+       /**
+       * Returns the recommended DPI for this window.
+       * \return The recommended DPI for this window.
+       */
+       virtual inline GHOST_TUns16 getDPIHint()
+       {
+               return 96;
+       }
+
 #ifdef WITH_INPUT_IME
        virtual void beginIME(GHOST_TInt32 x,
                              GHOST_TInt32 y,
index 1335c38..aeb6188 100644 (file)
@@ -563,3 +563,19 @@ GHOST_WindowSDL::setWindowCursorVisibility(bool visible)
        SDL_ShowCursor(visible);
        return GHOST_kSuccess;
 }
+
+GHOST_TUns16
+GHOST_WindowSDL::getDPIHint()
+{
+       int displayIndex = SDL_GetWindowDisplayIndex(m_sdl_win);
+       if (displayIndex < 0) {
+               return 96;
+       }
+
+       float ddpi;
+       if (SDL_GetDisplayDPI(displayIndex, &ddpi, NULL, NULL) != 0) {
+               return 96;
+       }
+
+       return (int)ddpi;
+}
index 5f658e8..96104ec 100644 (file)
@@ -168,6 +168,8 @@ protected:
        GHOST_TSuccess beginFullScreen() const { return GHOST_kFailure; }
 
        GHOST_TSuccess endFullScreen() const { return GHOST_kFailure; }
+
+       GHOST_TUns16 getDPIHint();
 };
 
 
index 7d80aa4..fc46164 100644 (file)
@@ -92,6 +92,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
       m_tablet(0),
       m_maxPressure(0),
       m_normal_state(GHOST_kWindowStateNormal),
+         m_user32(NULL),
       m_parentWindowHwnd(parentwindowhwnd),
       m_debug_context(is_debug)
 {
@@ -965,6 +966,23 @@ void GHOST_WindowWin32::bringTabletContextToFront()
        }
 }
 
+GHOST_TUns16 GHOST_WindowWin32::getDPIHint()
+{
+       if (!m_user32) {
+               m_user32 = ::LoadLibrary("user32.dll");
+       }
+
+       if (m_user32) {
+               GHOST_WIN32_GetDpiForWindow fpGetDpiForWindow = (GHOST_WIN32_GetDpiForWindow) ::GetProcAddress(m_user32, "GetDpiForWindow");
+
+               if (fpGetDpiForWindow) {
+                       return fpGetDpiForWindow(this->m_hWnd);
+               }
+       }
+
+       return USER_DEFAULT_SCREEN_DPI;
+}
+
 /** Reverse the bits in a GHOST_TUns8 */
 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
 {
index a1cf58c..75a3395 100644 (file)
@@ -58,6 +58,12 @@ typedef BOOL (API * GHOST_WIN32_WTClose)(HCTX);
 typedef BOOL (API * GHOST_WIN32_WTPacket)(HCTX, UINT, LPVOID);
 typedef BOOL (API * GHOST_WIN32_WTOverlap)(HCTX, BOOL);
 
+// typedefs for user32 functions to allow dynamic loading of Windows 10 DPI scaling functions
+typedef UINT(API * GHOST_WIN32_GetDpiForWindow)(HWND);
+#ifndef USER_DEFAULT_SCREEN_DPI
+#define USER_DEFAULT_SCREEN_DPI 96
+#endif // USER_DEFAULT_SCREEN_DPI
+
 /**
  * GHOST window on M$ Windows OSs.
  * \author     Maarten Gribnau
@@ -251,6 +257,8 @@ public:
 
        GHOST_TSuccess endFullScreen() const {return GHOST_kFailure;}
 
+       GHOST_TUns16 getDPIHint() override;
+
        /** if the window currently resizing */
        bool m_inLiveResize;
 
@@ -351,6 +359,9 @@ private:
 
        GHOST_TWindowState m_normal_state;
 
+       /** user32 dll handle*/
+       HMODULE m_user32;
+
        /** Hwnd to parent window */
        GHOST_TEmbedderWindowID m_parentWindowHwnd;
 
index 47fbe12..429c9af 100644 (file)
@@ -56,6 +56,9 @@
 #  include <X11/extensions/XInput2.h>
 #endif
 
+//For DPI value
+#include <X11/Xresource.h>
+
 #if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX)
 #  include <strings.h>
 #endif
@@ -68,6 +71,7 @@
 
 #include <algorithm>
 #include <string>
+#include <math.h>
 
 /* For obscure full screen mode stuff
  * lifted verbatim from blut. */
@@ -1672,3 +1676,42 @@ endFullScreen() const
 
        return GHOST_kSuccess;
 }
+
+GHOST_TUns16
+GHOST_WindowX11::
+getDPIHint()
+{
+       /* Try to read DPI setting set using xrdb */
+       char* resMan = XResourceManagerString(m_display);
+       XrmDatabase xrdb = XrmGetStringDatabase(resMan);
+       if (xrdb) {
+               char* type = NULL;
+               XrmValue val;
+
+               int success = XrmGetResource(xrdb, "Xft.dpi", "Xft.Dpi", &type, &val);
+               if (success && type) {
+                       if (strcmp(type, "String") == 0) {
+                               return atoi((char*)val.addr);
+                       }
+               }
+       }
+
+       /* Fallback to calculating DPI using X reported DPI, set using xrandr --dpi */
+       XWindowAttributes attr;
+       if (!XGetWindowAttributes(m_display, m_window, &attr)) {
+               /* Failed to get window attributes, return X11 default DPI */
+               return 96;
+       }
+
+       Screen* screen = attr.screen;
+       int pixelWidth = WidthOfScreen(screen);
+       int pixelHeight = HeightOfScreen(screen);
+       int mmWidth = WidthMMOfScreen(screen);
+       int mmHeight = HeightMMOfScreen(screen);
+
+       double pixelDiagonal = sqrt((pixelWidth * pixelWidth) + (pixelHeight * pixelHeight));
+       double mmDiagonal = sqrt((mmWidth * mmWidth) + (mmHeight * mmHeight));
+       float inchDiagonal = mmDiagonal * 0.039f;
+       int dpi = pixelDiagonal / inchDiagonal;
+       return dpi;
+}
index 9380aa9..5c54c1e 100644 (file)
@@ -235,6 +235,8 @@ public:
 
        GHOST_TSuccess endFullScreen() const;
 
+       GHOST_TUns16 getDPIHint();
+
 protected:
        /**
         * \param type  The type of rendering context create.
index f4e2cf0..e50beba 100644 (file)
@@ -217,6 +217,7 @@ class USERPREF_PT_interface(Panel):
 
         col = row.column()
         col.label(text="Display:")
+        col.prop(view, "ui_scale", text="Scale")
         col.prop(view, "show_tooltips")
         col.prop(view, "show_tooltips_python")
         col.prop(view, "show_object_info", text="Object Info")
@@ -467,11 +468,6 @@ class USERPREF_PT_system(Panel):
 
         col = colsplit.column()
         col.label(text="General:")
-        col.prop(system, "dpi")
-        col.label("Virtual Pixel Mode:")
-        col.prop(system, "virtual_pixel_mode", text="")
-
-        col.separator()
 
         col.prop(system, "frame_server_port")
         col.prop(system, "scrollback", text="Console Scrollback")
index 99d9e14..6145b90 100644 (file)
@@ -68,6 +68,10 @@ void BLO_update_defaults_userpref_blend(void)
         * but take care since some hardware has driver bugs here (T46962).
         * Further hardware workarounds should be made in gpu_extensions.c */
        U.glalphaclip = (1.0f / 255);
+
+       /* default so DPI is detected automatically */
+       U.dpi = 0;
+       U.ui_scale = 1.0f;
 }
 
 /**
index d76452e..5e7e736 100644 (file)
@@ -467,9 +467,11 @@ typedef struct UserDef {
        int audioformat;
        int audiochannels;
 
-       int scrollback; /* console scrollback limit */
-       int dpi;                /* range 48-128? */
-       char node_margin; /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */
+       int scrollback;     /* console scrollback limit */
+       int dpi;            /* range 48-128? */
+       float ui_scale;     /* interface scale */
+       int pad1;
+       char node_margin;   /* node insert offset (aka auto-offset) margin, but might be useful for later stuff as well */
        char pad2;
        short transopts;
        short menuthreshold1, menuthreshold2;
index 7b6eb5f..4d70b87 100644 (file)
@@ -138,23 +138,11 @@ static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
 }
 
 /* also used by buffer swap switching */
-static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_userdef_dpi_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
 {
        /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
        BLF_cache_clear();
 
-       BKE_blender_userdef_refresh();
-       WM_main_add_notifier(NC_WINDOW, NULL);      /* full redraw */
-       WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);    /* refresh region sizes */
-}
-
-static void rna_userdef_virtual_pixel_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
-{
-       /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
-       BLF_cache_clear();
-       
-       BKE_blender_userdef_refresh();
-
        /* force setting drawable again */
        wmWindowManager *wm = bmain->wm.first;
        if (wm) {
@@ -3325,6 +3313,12 @@ static void rna_def_userdef_view(BlenderRNA *brna)
        RNA_def_struct_ui_text(srna, "View & Controls", "Preferences related to viewing data");
 
        /* View  */
+       prop = RNA_def_property(srna, "ui_scale", PROP_FLOAT, PROP_FACTOR);
+       RNA_def_property_ui_text(prop, "UI Scale", "Changes the size of the fonts and buttons in the interface");
+       RNA_def_property_range(prop, 0.25f, 4.0f);
+       RNA_def_property_ui_range(prop, 0.5f, 2.0f, 1, 1);
+       RNA_def_property_float_default(prop, 1.0f);
+       RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
 
        /* display */
        prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE);
@@ -3916,12 +3910,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
            {0, NULL, 0, NULL, NULL}
        };
 
-       static EnumPropertyItem virtual_pixel_mode_items[] = {
-               {VIRTUAL_PIXEL_NATIVE, "NATIVE", 0, "Native", "Use native pixel size of the display"},
-               {VIRTUAL_PIXEL_DOUBLE, "DOUBLE", 0, "Double", "Use double the native pixel size of the display"},
-               {0, NULL, 0, NULL, NULL}
-       };
-
        srna = RNA_def_struct(brna, "UserPreferencesSystem", NULL);
        RNA_def_struct_sdna(srna, "UserDef");
        RNA_def_struct_nested(brna, srna, "UserPreferences");
@@ -3936,16 +3924,8 @@ static void rna_def_userdef_system(BlenderRNA *brna)
        RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
 
        prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE);
-       RNA_def_property_int_sdna(prop, NULL, "dpi");
-       RNA_def_property_range(prop, 48, 144);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
        RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display");
-       RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-
-       prop = RNA_def_property(srna, "virtual_pixel_mode", PROP_ENUM, PROP_NONE);
-       RNA_def_property_enum_sdna(prop, NULL, "virtual_pixel");
-       RNA_def_property_enum_items(prop, virtual_pixel_mode_items);
-       RNA_def_property_ui_text(prop, "Virtual Pixel Mode", "Modify the pixel size for hi-res devices");
-       RNA_def_property_update(prop, 0, "rna_userdef_virtual_pixel_update");
 
        prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE);
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
index 2d43c47..40baab8 100644 (file)
@@ -77,6 +77,7 @@
 #include "GPU_extensions.h"
 #include "GPU_init_exit.h"
 #include "GPU_glew.h"
+#include "BLF_api.h"
 
 /* for assert */
 #ifndef NDEBUG
@@ -374,14 +375,39 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
        }
 }
 
-static float wm_window_get_virtual_pixelsize(void)
+static void wm_window_set_dpi(wmWindow *win)
 {
-       return ((U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1.0f : 2.0f);
-}
+       int auto_dpi = GHOST_GetDPIHint(win->ghostwin);
 
-float wm_window_pixelsize(wmWindow *win)
-{
-       return (GHOST_GetNativePixelSize(win->ghostwin) * wm_window_get_virtual_pixelsize());
+       /* Lazily init UI scale size, preserving backwards compatibility by
+        * computing UI scale from ratio of previous DPI and auto DPI */
+       if (U.ui_scale == 0) {
+               int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2;
+
+               if (U.dpi == 0) {
+                       U.ui_scale = virtual_pixel;
+               }
+               else {
+                       U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f);
+               }
+
+               CLAMP(U.ui_scale, 0.25f, 4.0f);
+       }
+
+       /* Blender's UI drawing assumes DPI 72 as a good default following macOS
+        * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
+        * remap the DPI to Blender's convention. */
+       int dpi = auto_dpi * U.ui_scale * (72.0/96.0f);
+
+       /* Automatically set larger pixel size for high DPI. */
+       int pixelsize = MAX2(1, dpi / 54);
+
+       /* Set user preferences globals for drawing, and for forward compatibility. */
+       U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin) * pixelsize;
+       U.dpi = dpi / pixelsize;
+       U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
+
+       BKE_blender_userdef_refresh();
 }
 
 /* belongs to below */
@@ -456,10 +482,8 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
                        glClear(GL_COLOR_BUFFER_BIT);
                }
                
-               /* displays with larger native pixels, like Macbook. Used to scale dpi with */
                /* needed here, because it's used before it reads userdef */
-               U.pixelsize = wm_window_pixelsize(win);
-               BKE_blender_userdef_refresh();
+               wm_window_set_dpi(win);
                
                wm_window_swap_buffers(win);
                
@@ -626,7 +650,6 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
        Scene *scene = CTX_data_scene(C);
        const char *title;
        rcti rect = *rect_init;
-       const short px_virtual = (short)wm_window_get_virtual_pixelsize();
 
        /* changes rect to fit within desktop */
        wm_window_check_position(&rect);
@@ -644,9 +667,8 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
                win->posy = rect.ymin;
        }
 
-       /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */
-       win->sizex = BLI_rcti_size_x(&rect) * px_virtual;
-       win->sizey = BLI_rcti_size_y(&rect) * px_virtual;
+       win->sizex = BLI_rcti_size_x(&rect);
+       win->sizey = BLI_rcti_size_y(&rect);
 
        if (win->ghostwin) {
                wm_window_set_size(win, win->sizex, win->sizey);
@@ -835,8 +857,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
                GHOST_ActivateWindowDrawingContext(win->ghostwin);
                
                /* this can change per window */
-               U.pixelsize = wm_window_pixelsize(win);
-               BKE_blender_userdef_refresh();
+               wm_window_set_dpi(win);
        }
 }
 
@@ -1035,6 +1056,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
                                if (type == GHOST_kEventWindowSize) {
                                        WM_jobs_stop(wm, win->screen, NULL);
                                }
+
+                               wm_window_set_dpi(win);
                                
                                /* win32: gives undefined window size when minimized */
                                if (state != GHOST_kWindowStateMinimized) {
@@ -1118,7 +1141,19 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
                                }
                                break;
                        }
-                               
+
+                       case GHOST_kEventWindowDPIHintChanged:
+                       {
+                               wm_window_set_dpi(win);
+                               /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
+                               BLF_cache_clear();
+
+                               BKE_blender_userdef_refresh();
+                               WM_main_add_notifier(NC_WINDOW, NULL);      /* full redraw */
+                               WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);    /* refresh region sizes */
+                               break;
+                       }
+
                        case GHOST_kEventOpenMainFile:
                        {
                                PointerRNA props_ptr;
@@ -1199,11 +1234,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
                        {
                                // only update if the actual pixel size changes
                                float prev_pixelsize = U.pixelsize;
-                               U.pixelsize = wm_window_pixelsize(win);
+                               wm_window_set_dpi(win);
 
                                if (U.pixelsize != prev_pixelsize) {
-                                       BKE_blender_userdef_refresh();
-
                                        // close all popups since they are positioned with the pixel
                                        // size baked in and it's difficult to correct them
                                        wmWindow *oldWindow = CTX_wm_window(C);
index c106f9d..f70ec6b 100644 (file)
@@ -63,8 +63,6 @@ void          wm_window_swap_buffers  (wmWindow *win);
 void           wm_window_set_swap_interval(wmWindow *win, int interval);
 bool           wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
 
-float          wm_window_pixelsize(wmWindow *win);
-
 void           wm_get_cursor_position                  (wmWindow *win, int *x, int *y);
 void           wm_cursor_position_from_ghost   (wmWindow *win, int *x, int *y);
 void           wm_cursor_position_to_ghost             (wmWindow *win, int *x, int *y);