diff options
-rw-r--r-- | include/pugl/pugl.h | 16 | ||||
-rw-r--r-- | src/mac.m | 12 | ||||
-rw-r--r-- | src/win.c | 43 | ||||
-rw-r--r-- | src/win.h | 1 | ||||
-rw-r--r-- | src/x11.c | 37 | ||||
-rw-r--r-- | 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 @@ -973,6 +973,22 @@ 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 Functions for working with the position and size of a view. @@ -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) { @@ -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) { @@ -25,6 +25,7 @@ struct PuglInternalsImpl { HCURSOR cursor; HDC hdc; PuglSurface* surface; + double scaleFactor; bool flashing; bool mouseTracked; }; @@ -14,6 +14,7 @@ #include <X11/X.h> #include <X11/Xatom.h> #include <X11/Xlib.h> +#include <X11/Xresource.h> #include <X11/Xutil.h> #include <X11/keysym.h> @@ -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) { @@ -39,6 +39,7 @@ struct PuglWorldInternalsImpl { Display* display; PuglX11Atoms atoms; XIM xim; + double scaleFactor; PuglTimer* timers; size_t numTimers; XID serverTimeCounter; |