mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
7.1 KiB
177 lines
7.1 KiB
#ifndef Magnum_Platform_Implementation_dpiScaling_hpp |
|
#define Magnum_Platform_Implementation_dpiScaling_hpp |
|
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 |
|
Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a |
|
copy of this software and associated documentation files (the "Software"), |
|
to deal in the Software without restriction, including without limitation |
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
and/or sell copies of the Software, and to permit persons to whom the |
|
Software is furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included |
|
in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
#include "DpiScaling.h" |
|
|
|
#include <Corrade/Utility/Arguments.h> |
|
|
|
#include "Magnum/Magnum.h" |
|
|
|
#ifdef _MAGNUM_PLATFORM_USE_X11 |
|
#include <cstring> |
|
#include <dlfcn.h> |
|
#include <X11/Xresource.h> |
|
#include <Corrade/Containers/ScopeGuard.h> |
|
#include <Corrade/Utility/Assert.h> |
|
#include <Corrade/Utility/Debug.h> |
|
#undef None |
|
#endif |
|
|
|
#ifdef CORRADE_TARGET_EMSCRIPTEN |
|
#include <emscripten/emscripten.h> |
|
#endif |
|
|
|
#if defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT) |
|
#define WIN32_LEAN_AND_MEAN 1 |
|
#define VC_EXTRALEAN |
|
#include <windows.h> |
|
#ifdef __has_include |
|
#if __has_include(<shellscalingapi.h>) |
|
#include <shellscalingapi.h> |
|
#endif |
|
#endif |
|
#include <Corrade/Utility/Assert.h> |
|
#endif |
|
|
|
namespace Magnum { namespace Platform { namespace Implementation { |
|
|
|
Utility::Arguments windowScalingArguments() { |
|
Utility::Arguments args{"magnum"}; |
|
args.addOption("dpi-scaling", "default") |
|
.setFromEnvironment("dpi-scaling") |
|
#ifdef CORRADE_TARGET_APPLE |
|
.setHelp("dpi-scaling", "\n window DPI scaling", "default|framebuffer|<d>|\"<h> <v>\"") |
|
#elif !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_ANDROID) |
|
.setHelp("dpi-scaling", "\n window DPI scaling", "default|virtual|physical|<d>|\"<h> <v>\"") |
|
#else |
|
.setHelp("dpi-scaling", "\n window DPI scaling", "default|physical|<d>|\"<h> <v>\"") |
|
#endif |
|
; |
|
return args; |
|
} |
|
|
|
#ifdef _MAGNUM_PLATFORM_USE_X11 |
|
Float x11DpiScaling() { |
|
/* If the end app links to X11, these symbols will be available in a global |
|
scope and we can use that to query the DPI. If not, then those symbols |
|
won't be and that's okay -- it may be using Wayland or something else. */ |
|
void* xlib = dlopen(nullptr, RTLD_NOW|RTLD_GLOBAL); |
|
Containers::ScopeGuard closeXlib{xlib, dlclose}; |
|
#ifdef __GNUC__ /* http://www.mr-edd.co.uk/blog/supressing_gcc_warnings */ |
|
__extension__ |
|
#endif |
|
auto xOpenDisplay = reinterpret_cast<Display*(*)(char*)>(dlsym(xlib, "XOpenDisplay")); |
|
#ifdef __GNUC__ /* http://www.mr-edd.co.uk/blog/supressing_gcc_warnings */ |
|
__extension__ |
|
#endif |
|
auto xCloseDisplay = reinterpret_cast<int(*)(Display*)>(dlsym(xlib, "XCloseDisplay")); |
|
#ifdef __GNUC__ /* http://www.mr-edd.co.uk/blog/supressing_gcc_warnings */ |
|
__extension__ |
|
#endif |
|
auto xResourceManagerString = reinterpret_cast<char*(*)(Display*)>(dlsym(xlib, "XResourceManagerString")); |
|
#ifdef __GNUC__ /* http://www.mr-edd.co.uk/blog/supressing_gcc_warnings */ |
|
__extension__ |
|
#endif |
|
auto xrmGetStringDatabase = reinterpret_cast<XrmDatabase(*)(const char*)>(dlsym(xlib, "XrmGetStringDatabase")); |
|
#ifdef __GNUC__ /* http://www.mr-edd.co.uk/blog/supressing_gcc_warnings */ |
|
__extension__ |
|
#endif |
|
auto xrmGetResource = reinterpret_cast<int(*)(XrmDatabase, const char*, const char*, char**, XrmValue*)>(dlsym(xlib, "XrmGetResource")); |
|
#ifdef __GNUC__ /* http://www.mr-edd.co.uk/blog/supressing_gcc_warnings */ |
|
__extension__ |
|
#endif |
|
auto xrmDestroyDatabase = reinterpret_cast<void(*)(XrmDatabase)>(dlsym(xlib, "XrmDestroyDatabase")); |
|
if(!xOpenDisplay || !xCloseDisplay || !xResourceManagerString || !xrmGetStringDatabase || !xrmGetResource || !xrmDestroyDatabase) { |
|
Warning{} << "Platform: can't load X11 symbols for getting virtual DPI scaling, falling back to physical DPI"; |
|
return {}; |
|
} |
|
|
|
Display* display = xOpenDisplay(nullptr); |
|
Containers::ScopeGuard closeDisplay{display, xCloseDisplay}; |
|
|
|
const char* rms = xResourceManagerString(display); |
|
if(rms) { |
|
XrmDatabase db = xrmGetStringDatabase(rms); |
|
CORRADE_INTERNAL_ASSERT(db); |
|
Containers::ScopeGuard closeDb{db, xrmDestroyDatabase}; |
|
|
|
XrmValue value; |
|
char* type{}; |
|
if(xrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) { |
|
if(type && strcmp(type, "String") == 0) { |
|
const float scaling = std::stof(value.addr)/96.0f; |
|
CORRADE_INTERNAL_ASSERT(scaling); |
|
return scaling; |
|
} |
|
} |
|
} |
|
|
|
Warning{} << "Platform: can't get Xft.dpi property for virtual DPI scaling, falling back to physical DPI"; |
|
return {}; |
|
} |
|
#endif |
|
|
|
#ifdef CORRADE_TARGET_EMSCRIPTEN |
|
Float emscriptenDpiScaling() { |
|
return Float(emscripten_get_device_pixel_ratio()); |
|
} |
|
#endif |
|
|
|
#if defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT) |
|
bool isWindowsAppDpiAware() { |
|
/** @todo use GetWindowDpiAwarenessContext() (since Windows 10)? I think |
|
it's not needed for a simple boolean return value. */ |
|
|
|
#ifdef DPI_ENUMS_DECLARED |
|
/* The GetProcessDpiAwareness() function is available only since Windows |
|
8.1, so load it manually to avoid a link-time error when building for |
|
Windows 7. Also, the shellscalingapi.h include might not be available |
|
on older MinGW, so it's guarded by __has_include(). Here, if the |
|
DPI_ENUMS_DECLARED define is present, the header exists and has what we |
|
need. */ |
|
HMODULE const shcore = GetModuleHandleA("Shcore.dll"); |
|
if(shcore) { |
|
auto* const getProcessDpiAwareness = reinterpret_cast<HRESULT(WINAPI *)(HANDLE, PROCESS_DPI_AWARENESS*)>(GetProcAddress(shcore, "GetProcessDpiAwareness")); |
|
PROCESS_DPI_AWARENESS result{}; |
|
return getProcessDpiAwareness && getProcessDpiAwareness(nullptr, &result) == S_OK && result != PROCESS_DPI_UNAWARE; |
|
} |
|
#endif |
|
|
|
/* IsProcessDPIAware() is available since Windows Vista. At this point we |
|
can require it (XP support? haha no), so assert that everything works |
|
correctly. */ |
|
HMODULE const user32 = GetModuleHandleA("User32.dll"); |
|
CORRADE_INTERNAL_ASSERT(user32); |
|
auto const isProcessDPIAware = reinterpret_cast<BOOL(WINAPI *)()>(GetProcAddress(user32, "IsProcessDPIAware")); |
|
CORRADE_INTERNAL_ASSERT(isProcessDPIAware); |
|
return isProcessDPIAware(); |
|
} |
|
#endif |
|
|
|
}}} |
|
|
|
#endif
|
|
|