From fdd6de0d12ea17f713ec3e73e7968198339b7b6d Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 21 May 2022 21:28:08 -0400 Subject: Add puglGetScaleFactor() --- include/pugl/pugl.h | 16 ++++++++++++++++ src/mac.m | 12 ++++++++++-- src/win.c | 43 ++++++++++++++++++++++++++++++++++++++++++- src/win.h | 1 + src/x11.c | 37 ++++++++++++++++++++++++++++++++++++- src/x11.h | 1 + 6 files changed, 106 insertions(+), 4 deletions(-) diff --git a/include/pugl/pugl.h b/include/pugl/pugl.h index a7dd7eb..0d4642c 100644 --- a/include/pugl/pugl.h +++ b/include/pugl/pugl.h @@ -972,6 +972,22 @@ PUGL_API int puglGetViewHint(const PuglView* view, PuglViewHint hint); +/** + Return the scale factor of the view. + + This factor describe how large UI elements (especially text) should be + compared to "normal". For example, 2.0 means the UI should be drawn twice + as large. + + "Normal" is loosely defined, but means a good size on a "standard DPI" + display (around 96 DPI). In other words, the scale 1.0 should have text + that is reasonably sized on a 96 DPI display, and the scale 2.0 should have + text twice that large. +*/ +PUGL_API +double +puglGetScaleFactor(const PuglView* view); + /** @} @defgroup frame Frame diff --git a/src/mac.m b/src/mac.m index 67422a5..9cd3e1c 100644 --- a/src/mac.m +++ b/src/mac.m @@ -35,10 +35,12 @@ rectToScreen(NSScreen* screen, NSRect rect) } static NSScreen* -viewScreen(PuglView* view) +viewScreen(const PuglView* view) { return view->impl->window ? [view->impl->window screen] - : [NSScreen mainScreen]; + : [view->impl->wrapperView window] + ? [[view->impl->wrapperView window] screen] + : [NSScreen mainScreen]; } static NSRect @@ -1365,6 +1367,12 @@ puglSetWindowTitle(PuglView* view, const char* title) return PUGL_SUCCESS; } +double +puglGetScaleFactor(const PuglView* const view) +{ + return [viewScreen(view) backingScaleFactor]; +} + PuglStatus puglSetFrame(PuglView* view, const PuglRect frame) { diff --git a/src/win.c b/src/win.c index 8f2a26b..5e70b6f 100644 --- a/src/win.c +++ b/src/win.c @@ -35,6 +35,8 @@ #define PUGL_USER_TIMER_MIN 9470 typedef BOOL(WINAPI* PFN_SetProcessDPIAware)(void); +typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); +typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*); LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); @@ -112,6 +114,35 @@ puglWinGetWindowExFlags(const PuglView* const view) return WS_EX_NOINHERITLAYOUT | (view->parent ? 0u : WS_EX_APPWINDOW); } +static double +puglWinGetViewScaleFactor(const PuglView* const view) +{ + const HMODULE shcore = LoadLibrary("Shcore.dll"); + if (!shcore) { + return 1.0; + } + + const PFN_GetProcessDpiAwareness GetProcessDpiAwareness = + (PFN_GetProcessDpiAwareness)GetProcAddress(shcore, + "GetProcessDpiAwareness"); + + const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor = + (PFN_GetScaleFactorForMonitor)GetProcAddress(shcore, + "GetScaleFactorForMonitor"); + + DWORD dpiAware = 0; + DWORD scaleFactor = 100; + if (GetProcessDpiAwareness && GetScaleFactorForMonitor && + !GetProcessDpiAwareness(NULL, &dpiAware) && dpiAware) { + GetScaleFactorForMonitor( + MonitorFromWindow(view->impl->hwnd, MONITOR_DEFAULTTOPRIMARY), + &scaleFactor); + } + + FreeLibrary(shcore); + return (double)scaleFactor / 100.0; +} + PuglWorldInternals* puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags)) { @@ -214,7 +245,8 @@ puglRealize(PuglView* view) puglSetWindowTitle(view, view->title); } - view->impl->cursor = LoadCursor(NULL, IDC_ARROW); + view->impl->scaleFactor = puglWinGetViewScaleFactor(view); + view->impl->cursor = LoadCursor(NULL, IDC_ARROW); puglSetFrame(view, view->frame); SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); @@ -604,6 +636,9 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) InvalidateRect(view->impl->hwnd, NULL, false); } break; + case WM_DISPLAYCHANGE: + view->impl->scaleFactor = puglWinGetViewScaleFactor(view); + break; case WM_WINDOWPOSCHANGED: handleConfigure(view, &event); break; @@ -1002,6 +1037,12 @@ adjustedWindowRect(PuglView* const view, return rect; } +double +puglGetScaleFactor(const PuglView* const view) +{ + return view->impl->scaleFactor; +} + PuglStatus puglSetFrame(PuglView* view, const PuglRect frame) { diff --git a/src/win.h b/src/win.h index 5c70e1e..f71dcf8 100644 --- a/src/win.h +++ b/src/win.h @@ -25,6 +25,7 @@ struct PuglInternalsImpl { HCURSOR cursor; HDC hdc; PuglSurface* surface; + double scaleFactor; bool flashing; bool mouseTracked; }; diff --git a/src/x11.c b/src/x11.c index 5ae6b12..c2e9e96 100644 --- a/src/x11.c +++ b/src/x11.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -106,6 +107,33 @@ initXSync(PuglWorldInternals* const impl) return false; } +static double +puglX11GetDisplayScaleFactor(Display* const display) +{ + double dpi = 96.0; + const char* const rms = XResourceManagerString(display); + if (rms) { + XrmDatabase db = XrmGetStringDatabase(rms); + if (db) { + XrmValue value = {0u, NULL}; + char* type = NULL; + if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) { + if (!type || !strcmp(type, "String")) { + char* end = NULL; + const double xftDpi = strtod(value.addr, &end); + if (xftDpi > 0.0 && xftDpi < HUGE_VAL) { + dpi = xftDpi; + } + } + } + + XrmDestroyDatabase(db); + } + } + + return dpi / 96.0; +} + PuglWorldInternals* puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags) { @@ -121,7 +149,8 @@ puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags) PuglWorldInternals* impl = (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); - impl->display = display; + impl->display = display; + impl->scaleFactor = puglX11GetDisplayScaleFactor(display); // Intern the various atoms we will need impl->atoms.CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0); @@ -1367,6 +1396,12 @@ puglSetWindowTitle(PuglView* const view, const char* const title) return PUGL_SUCCESS; } +double +puglGetScaleFactor(const PuglView* const view) +{ + return view->world->impl->scaleFactor; +} + PuglStatus puglSetFrame(PuglView* const view, const PuglRect frame) { diff --git a/src/x11.h b/src/x11.h index 49a1d06..1be54ad 100644 --- a/src/x11.h +++ b/src/x11.h @@ -39,6 +39,7 @@ struct PuglWorldInternalsImpl { Display* display; PuglX11Atoms atoms; XIM xim; + double scaleFactor; PuglTimer* timers; size_t numTimers; XID serverTimeCounter; -- cgit v1.2.1