Browse Source

[wip] Platform: respond to DPI change events in Sdl and GlfwApp.

TODO: docs
TODO: I don't like the extra flag in viewport event, should this be
  separate?
TODO: resizing directly from inside the event handler on GLFW causes a
  loop where the window switches between the DPIs several times and then
  gets resized to something extremely wide at the end, how to prevent
  this? Is that due to window borders being differently thick?
TODO: there's a GLFW_SCALE_TO_MONITOR that makes the resizing somehow
  automagic but it's too automagic for my taste, and should be under app
  control instead
TODO: SDL halts all event processing while the window is dragged,
  meaning the window only gets resized *after* it jumps to the other
  display, which is freaking bad
TODO: Windows supply a "desired window rectangle" in the WM_DPICHANGED
  event and it should probably get used, how to hammer it out of GLFW?
  Interesting is that GLFW actually calls this but it does nothing
  unless GLFW_SCALE_TO_MONITOR is enabled as well. Huh?
TODO: I guess because of the different window border sizes, even under
  SDL whers is no feedback loop going back and forth between two
  monitors several times causes the window to not be sized as expected
  anymore, being a bunch of pixels off (803x607 and such). Not good for
  my OCD. Solutions? GLFW is doing some calculations in its
  GLFW_SCALE_TO_MONITOR routine, maybe that could get used?
TODO: WM_DPICHANGED can be caught by enabling SDL_SYSWMEVENT that's
  disabled by default. Should this one be propagated to anyEvent() as
  well? It generates *a lot* of events, however not propagating it might
  be limiting for the user :/
dpi-change-events
Vladimír Vondruš 6 years ago
parent
commit
3ea97a242f
  1. 18
      src/Magnum/Platform/GlfwApplication.cpp
  2. 13
      src/Magnum/Platform/GlfwApplication.h
  3. 27
      src/Magnum/Platform/Sdl2Application.cpp
  4. 13
      src/Magnum/Platform/Sdl2Application.h
  5. 12
      src/Magnum/Platform/Test/GlfwApplicationTest.cpp
  6. 13
      src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp

18
src/Magnum/Platform/GlfwApplication.cpp

@ -584,13 +584,27 @@ void GlfwApplication::setupCallbacks() {
#ifdef MAGNUM_TARGET_GL
glfwSetFramebufferSizeCallback(_window, [](GLFWwindow* const window, const int w, const int h) {
auto& app = *static_cast<GlfwApplication*>(glfwGetWindowUserPointer(window));
ViewportEvent e{app.windowSize(), {w, h}, app.dpiScaling()};
ViewportEvent e{ViewportEvent::Type::Resized, app.windowSize(), {w, h}, app.dpiScaling()};
app.viewportEvent(e);
});
#else
glfwSetWindowSizeCallback(_window, [](GLFWwindow* const window, const int w, const int h) {
auto& app = *static_cast<GlfwApplication*>(glfwGetWindowUserPointer(window));
ViewportEvent e{{w, h}, app.dpiScaling()};
ViewportEvent e{ViewportEvent::Type::Resized, {w, h}, app.dpiScaling()};
app.viewportEvent(e);
});
#endif
#if GLFW_VERSION_MAJOR*100 + GLFW_VERSION_MINOR >= 303
glfwSetWindowContentScaleCallback(_window, [](GLFWwindow* const window, float xScale, float yScale) {
auto& app = *static_cast<GlfwApplication*>(glfwGetWindowUserPointer(window));
ViewportEvent e{ViewportEvent::Type::DpiScalingChanged,
#ifdef MAGNUM_TARGET_GL
app.windowSize(), app.framebufferSize(),
#else
app.windowSize(),
#endif
/* Update the cached DPI scaling value as well */
app._dpiScaling = {xScale, yScale}};
app.viewportEvent(e);
});
#endif

13
src/Magnum/Platform/GlfwApplication.h

@ -1300,6 +1300,11 @@ class GlfwApplication::ExitEvent {
*/
class GlfwApplication::ViewportEvent {
public:
enum class Type: UnsignedByte {
Resized,
DpiScalingChanged
};
/** @brief Copying is not allowed */
ViewportEvent(const ViewportEvent&) = delete;
@ -1312,6 +1317,9 @@ class GlfwApplication::ViewportEvent {
/** @brief Moving is not allowed */
ViewportEvent& operator=(ViewportEvent&&) = delete;
/** @brief Event type */
Type type() const { return _type; }
/**
* @brief Window size
*
@ -1353,16 +1361,17 @@ class GlfwApplication::ViewportEvent {
private:
friend GlfwApplication;
explicit ViewportEvent(const Vector2i& windowSize,
explicit ViewportEvent(Type type, const Vector2i& windowSize,
#ifdef MAGNUM_TARGET_GL
const Vector2i& framebufferSize,
#endif
const Vector2& dpiScaling): _windowSize{windowSize},
const Vector2& dpiScaling): _type{type}, _windowSize{windowSize},
#ifdef MAGNUM_TARGET_GL
_framebufferSize{framebufferSize},
#endif
_dpiScaling{dpiScaling} {}
Type _type;
const Vector2i _windowSize;
#ifdef MAGNUM_TARGET_GL
const Vector2i _framebufferSize;

27
src/Magnum/Platform/Sdl2Application.cpp

@ -65,6 +65,8 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
/* For capturing the WM_DPICHANGED event */
#include <SDL_syswm.h>
#endif
namespace Magnum { namespace Platform {
@ -155,6 +157,11 @@ Sdl2Application::Sdl2Application(const Arguments& arguments, NoCreateT):
std::exit(1);
}
#ifdef CORRADE_TARGET_WINDOWS
/* Enable SysWM events to get the WM_DPICHANGED event on Windows */
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
#endif
/* Save command-line arguments */
if(args.value("log") == "verbose") _verboseLog = true;
const std::string dpiScaling = args.value("dpi-scaling");
@ -834,7 +841,8 @@ bool Sdl2Application::mainLoopIteration() {
_lastKnownCanvasSize = canvasSizei;
const Vector2i size = _dpiScaling*canvasSizei;
emscripten_set_canvas_element_size("#canvas", size.x(), size.y());
ViewportEvent e{
/** @todo dpi scaling changed? */
ViewportEvent e{ViewportEvent::Type::Resized,
#ifdef MAGNUM_TARGET_GL
size,
#endif
@ -864,7 +872,7 @@ bool Sdl2Application::mainLoopIteration() {
framebuffer size and not window size on macOS, which
is weird. Query the values directly instead to be
really sure. */
ViewportEvent e{event, windowSize(),
ViewportEvent e{ViewportEvent::Type::Resized, event, windowSize(),
#ifdef MAGNUM_TARGET_GL
framebufferSize(),
#endif
@ -942,6 +950,21 @@ bool Sdl2Application::mainLoopIteration() {
}
} break;
#ifdef CORRADE_TARGET_WINDOWS
case SDL_SYSWMEVENT: {
if(event.syswm.msg->msg.win.msg == WM_DPICHANGED) {
DWORD dpi = event.syswm.msg->msg.win.wParam;
ViewportEvent e{ViewportEvent::Type::DpiScalingChanged, event, windowSize(),
#ifdef MAGNUM_TARGET_GL
framebufferSize(),
#endif
/* Update the cached DPI scaling value as well */
_dpiScaling = Vector2{Vector2i{LOWORD(dpi), HIWORD(dpi)}}/96.0f};
viewportEvent(e);
}
} break;
#endif
/* Direct everything else to anyEvent(), so users can implement
event handling for things not present in the Application APIs */
default: if(!(_flags & Flag::NoAnyEvent)) anyEvent(event);

13
src/Magnum/Platform/Sdl2Application.h

@ -1829,6 +1829,11 @@ class Sdl2Application::ExitEvent {
*/
class Sdl2Application::ViewportEvent {
public:
enum class Type: UnsignedByte {
Resized,
DpiScalingChanged
};
/** @brief Copying is not allowed */
ViewportEvent(const ViewportEvent&) = delete;
@ -1841,6 +1846,9 @@ class Sdl2Application::ViewportEvent {
/** @brief Moving is not allowed */
ViewportEvent& operator=(ViewportEvent&&) = delete;
/** @brief Event type */
Type type() const { return _type; }
/**
* @brief Window size
*
@ -1893,7 +1901,7 @@ class Sdl2Application::ViewportEvent {
private:
friend Sdl2Application;
explicit ViewportEvent(
explicit ViewportEvent(Type type,
#ifndef CORRADE_TARGET_EMSCRIPTEN
const SDL_Event& event,
#endif
@ -1901,7 +1909,7 @@ class Sdl2Application::ViewportEvent {
#ifdef MAGNUM_TARGET_GL
const Vector2i& framebufferSize,
#endif
const Vector2& dpiScaling):
const Vector2& dpiScaling): _type{type},
#ifndef CORRADE_TARGET_EMSCRIPTEN
_event(event),
#endif
@ -1911,6 +1919,7 @@ class Sdl2Application::ViewportEvent {
#endif
_dpiScaling{dpiScaling} {}
Type _type;
#ifndef CORRADE_TARGET_EMSCRIPTEN
const SDL_Event& _event;
#endif

12
src/Magnum/Platform/Test/GlfwApplicationTest.cpp

@ -47,6 +47,11 @@ struct GlfwApplicationTest: Platform::Application {
<< event.framebufferSize()
#endif
<< event.dpiScaling();
if(event.type() == ViewportEvent::Type::DpiScalingChanged) {
Debug{} << "DPI scaling changed, resizing to" << _lastUnscaledWindowSize;
setWindowSize(_lastUnscaledWindowSize);
} else _lastUnscaledWindowSize = event.windowSize()/event.dpiScaling();
}
void keyPressEvent(KeyEvent& event) override {
@ -96,6 +101,9 @@ struct GlfwApplicationTest: Platform::Application {
}
void drawEvent() override {}
private:
Vector2i _lastUnscaledWindowSize;
};
GlfwApplicationTest::GlfwApplicationTest(const Arguments& arguments): Platform::Application{arguments, NoCreate} {
@ -116,6 +124,10 @@ GlfwApplicationTest::GlfwApplicationTest(const Arguments& arguments): Platform::
#endif
<< dpiScaling();
/* Save desired window size for resizing when going between differently
dense displays */
_lastUnscaledWindowSize = windowSize()/dpiScaling();
#if GLFW_VERSION_MAJOR*100 + GLFW_VERSION_MINOR >= 302
Utility::Resource rs{"icons"};
PluginManager::Manager<Trade::AbstractImporter> manager;

13
src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp

@ -66,6 +66,11 @@ struct Sdl2ApplicationTest: Platform::Application {
<< event.framebufferSize()
#endif
<< event.dpiScaling();
if(event.type() == ViewportEvent::Type::DpiScalingChanged) {
Debug{} << "DPI scaling changed, resizing to" << _lastUnscaledWindowSize;
setWindowSize(_lastUnscaledWindowSize);
} else _lastUnscaledWindowSize = event.windowSize()/event.dpiScaling();
}
/* For testing event coordinates */
@ -137,9 +142,11 @@ struct Sdl2ApplicationTest: Platform::Application {
if(event.type == SDL_WINDOWEVENT) d << event.window.event;
}
#ifdef CORRADE_TARGET_EMSCRIPTEN
private:
#ifdef CORRADE_TARGET_EMSCRIPTEN
bool _fullscreen = false;
#else
Vector2i _lastUnscaledWindowSize;
#endif
};
@ -162,6 +169,10 @@ Sdl2ApplicationTest::Sdl2ApplicationTest(const Arguments& arguments): Platform::
#endif
<< dpiScaling();
/* Save desired window size for resizing when going between differently
dense displays */
_lastUnscaledWindowSize = windowSize()/dpiScaling();
#ifndef CORRADE_TARGET_EMSCRIPTEN
#if SDL_MAJOR_VERSION*1000 + SDL_MINOR_VERSION*100 + SDL_PATCHLEVEL >= 2005
Utility::Resource rs{"icons"};

Loading…
Cancel
Save