From 309193895a333ed3ea8daedfacee6d57343d5ead Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 17 Jan 2014 21:11:20 -0400 Subject: [PATCH] Added opt-in support for high-dpi mode in OS X when on a retina display (resolves issue #761). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a ‘highdpi’ boolean flag to t.window/love.window.setMode (defaults to false.) When the window is actually in high-dpi mode on a supported display, the graphics width and height and the mouse position are in pixels, rather than ‘window coordinates’. Added love.window.getPixelScale. Returns the scale factor of the window from user-space points to pixels (e.g. it will be 1 normally, and 2 on a retina display in OS X with high-dpi mode enabled.) --- src/modules/event/sdl/Event.cpp | 54 ++++++++++-- src/modules/mouse/sdl/Mouse.cpp | 51 ++++++++++- src/modules/window/Window.cpp | 40 +++++---- src/modules/window/Window.h | 52 ++++++----- src/modules/window/sdl/Window.cpp | 135 ++++++++++++++++++++--------- src/modules/window/sdl/Window.h | 12 +-- src/modules/window/wrap_Window.cpp | 106 ++++++++++++---------- src/modules/window/wrap_Window.h | 1 + src/scripts/boot.lua | 1 + src/scripts/boot.lua.h | 4 +- 10 files changed, 308 insertions(+), 148 deletions(-) diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index ece1f7bfd..e50ce357d 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -37,6 +37,24 @@ namespace event namespace sdl { +// SDL reports mouse coordinates in the window coordinate system in OS X, but +// we want them in pixel coordinates (may be different with high-DPI enabled.) +static void windowToPixelCoords(int *x, int *y) +{ + double scale = 1.0; + + window::Window *window = (window::Window *) Module::findInstance("love.window."); + if (window != nullptr) + scale = window->getPixelScale(); + + if (x != nullptr) + *x = int(double(*x) * scale); + + if (y != nullptr) + *y = int(double(*x) * scale); +} + + const char *Event::getName() const { return "love.event.sdl"; @@ -162,8 +180,11 @@ Message *Event::convert(const SDL_Event &e) const case SDL_MOUSEBUTTONUP: if (buttons.find(e.button.button, button) && mouse::Mouse::getConstant(button, txt)) { - arg1 = new Variant((double) e.button.x); - arg2 = new Variant((double) e.button.y); + int x = e.button.x; + int y = e.button.y; + windowToPixelCoords(&x, &y); + arg1 = new Variant((double) x); + arg2 = new Variant((double) y); arg3 = new Variant(txt, strlen(txt)); msg = new Message((e.type == SDL_MOUSEBUTTONDOWN) ? "mousepressed" : "mousereleased", @@ -182,6 +203,7 @@ Message *Event::convert(const SDL_Event &e) const int mx, my; SDL_GetMouseState(&mx, &my); + windowToPixelCoords(&mx, &my); arg1 = new Variant((double) mx); arg2 = new Variant((double) my); @@ -366,7 +388,7 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const Message *Event::convertWindowEvent(const SDL_Event &e) const { Message *msg = 0; - Variant *arg1, *arg2; + Variant *arg1, *arg2, *arg3, *arg4; window::Window *win = 0; if (e.type != SDL_WINDOWEVENT) @@ -402,17 +424,31 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const win = (window::Window *) Module::findInstance("love.window."); if (win) { + int px_w = e.window.data1; + int px_h = e.window.data2; + +#if SDL_VERSION_ATLEAST(2,0,1) + SDL_Window *sdlwin = SDL_GetWindowFromID(e.window.windowID); + if (sdlwin) + SDL_GL_GetDrawableSize(sdlwin, &px_w, &px_h); +#endif + win->onWindowResize(e.window.data1, e.window.data2); graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics."); if (gfx) - gfx->setViewportSize(e.window.data1, e.window.data2); + gfx->setViewportSize(px_w, px_h); + + arg1 = new Variant((double) px_w); + arg2 = new Variant((double) px_h); + arg3 = new Variant((double) e.window.data1); + arg4 = new Variant((double) e.window.data2); + msg = new Message("resize", arg1, arg2, arg3, arg4); + arg1->release(); + arg2->release(); + arg3->release(); + arg4->release(); } - arg1 = new Variant((double) e.window.data1); - arg2 = new Variant((double) e.window.data2); - msg = new Message("resize", arg1, arg2); - arg1->release(); - arg2->release(); break; } diff --git a/src/modules/mouse/sdl/Mouse.cpp b/src/modules/mouse/sdl/Mouse.cpp index 94b187a7a..200e3e203 100644 --- a/src/modules/mouse/sdl/Mouse.cpp +++ b/src/modules/mouse/sdl/Mouse.cpp @@ -32,6 +32,39 @@ namespace mouse namespace sdl { +// SDL reports mouse coordinates in the window coordinate system in OS X, but +// we want them in pixel coordinates (may be different with high-DPI enabled.) +static void windowToPixelCoords(int *x, int *y) +{ + double scale = 1.0; + + love::window::Window *window = love::window::sdl::Window::getSingleton(); + if (window != nullptr) + scale = window->getPixelScale(); + + if (x != nullptr) + *x = int(double(*x) * scale); + + if (y != nullptr) + *y = int(double(*x) * scale); +} + +// And vice versa for setting mouse coordinates. +static void pixelToWindowCoords(int *x, int *y) +{ + double scale = 1.0; + + love::window::Window *window = love::window::sdl::Window::getSingleton(); + if (window != nullptr) + scale = window->getPixelScale(); + + if (x != nullptr) + *x = int(double(*x) / scale); + + if (y != nullptr) + *y = int(double(*x) / scale); +} + const char *Mouse::getName() const { return "love.mouse.sdl"; @@ -98,30 +131,40 @@ love::mouse::Cursor *Mouse::getCursor() const int Mouse::getX() const { int x; - SDL_GetMouseState(&x, 0); + SDL_GetMouseState(&x, nullptr); + windowToPixelCoords(&x, nullptr); + return x; } int Mouse::getY() const { int y; - SDL_GetMouseState(0, &y); + SDL_GetMouseState(nullptr, &y); + windowToPixelCoords(nullptr, &y); + return y; } void Mouse::getPosition(int &x, int &y) const { - SDL_GetMouseState(&x, &y); + int mx, my; + SDL_GetMouseState(&mx, &my); + windowToPixelCoords(&mx, &my); + + x = mx; + y = my; } void Mouse::setPosition(int x, int y) { love::window::Window *window = love::window::sdl::Window::getSingleton(); - SDL_Window *handle = NULL; + SDL_Window *handle = nullptr; if (window) handle = (SDL_Window *) window->getHandle(); + pixelToWindowCoords(&x, &y); SDL_WarpMouseInWindow(handle, x, y); } diff --git a/src/modules/window/Window.cpp b/src/modules/window/Window.cpp index ac9c45a4e..6243830aa 100644 --- a/src/modules/window/Window.cpp +++ b/src/modules/window/Window.cpp @@ -26,19 +26,19 @@ namespace love namespace window { -Window *Window::singleton = NULL; +Window *Window::singleton = nullptr; Window::~Window() { if (singleton == this) - singleton = NULL; + singleton = nullptr; } void Window::swapBuffers() { } -WindowAttributes::WindowAttributes() +WindowSettings::WindowSettings() : fullscreen(false) , fstype(Window::FULLSCREEN_TYPE_NORMAL) , vsync(true) @@ -49,6 +49,7 @@ WindowAttributes::WindowAttributes() , borderless(false) , centered(true) , display(0) + , highdpi(false) { } @@ -62,31 +63,32 @@ bool Window::getConstant(Window::FullscreenType in, const char *&out) return fullscreenTypes.find(in, out); } -bool Window::getConstant(const char *in, Window::Attribute &out) +bool Window::getConstant(const char *in, Window::Setting &out) { - return attributes.find(in, out); + return settings.find(in, out); } -bool Window::getConstant(Window::Attribute in, const char *&out) +bool Window::getConstant(Window::Setting in, const char *&out) { - return attributes.find(in, out); + return settings.find(in, out); } -StringMap::Entry Window::attributeEntries[] = +StringMap::Entry Window::settingEntries[] = { - {"fullscreen", ATTRIB_FULLSCREEN}, - {"fullscreentype", ATTRIB_FULLSCREEN_TYPE}, - {"vsync", ATTRIB_VSYNC}, - {"fsaa", ATTRIB_FSAA}, - {"resizable", ATTRIB_RESIZABLE}, - {"minwidth", ATTRIB_MIN_WIDTH}, - {"minheight", ATTRIB_MIN_HEIGHT}, - {"borderless", ATTRIB_BORDERLESS}, - {"centered", ATTRIB_CENTERED}, - {"display", ATTRIB_DISPLAY} + {"fullscreen", SETTING_FULLSCREEN}, + {"fullscreentype", SETTING_FULLSCREEN_TYPE}, + {"vsync", SETTING_VSYNC}, + {"fsaa", SETTING_FSAA}, + {"resizable", SETTING_RESIZABLE}, + {"minwidth", SETTING_MIN_WIDTH}, + {"minheight", SETTING_MIN_HEIGHT}, + {"borderless", SETTING_BORDERLESS}, + {"centered", SETTING_CENTERED}, + {"display", SETTING_DISPLAY}, + {"highdpi", SETTING_HIGHDPI}, }; -StringMap Window::attributes(Window::attributeEntries, sizeof(Window::attributeEntries)); +StringMap Window::settings(Window::settingEntries, sizeof(Window::settingEntries)); StringMap::Entry Window::fullscreenTypeEntries[] = { diff --git a/src/modules/window/Window.h b/src/modules/window/Window.h index 0f84c7c51..ad247fd0b 100644 --- a/src/modules/window/Window.h +++ b/src/modules/window/Window.h @@ -37,26 +37,27 @@ namespace window // Forward-declared so it can be used in the class methods. We can't define the // whole thing here because it uses the Window::Type enum. -struct WindowAttributes; +struct WindowSettings; class Window : public Module { public: - // Types of window attributes. - enum Attribute + // Different window settings. + enum Setting { - ATTRIB_FULLSCREEN, - ATTRIB_FULLSCREEN_TYPE, - ATTRIB_VSYNC, - ATTRIB_FSAA, - ATTRIB_RESIZABLE, - ATTRIB_MIN_WIDTH, - ATTRIB_MIN_HEIGHT, - ATTRIB_BORDERLESS, - ATTRIB_CENTERED, - ATTRIB_DISPLAY, - ATTRIB_MAX_ENUM + SETTING_FULLSCREEN, + SETTING_FULLSCREEN_TYPE, + SETTING_VSYNC, + SETTING_FSAA, + SETTING_RESIZABLE, + SETTING_MIN_WIDTH, + SETTING_MIN_HEIGHT, + SETTING_BORDERLESS, + SETTING_CENTERED, + SETTING_DISPLAY, + SETTING_HIGHDPI, + SETTING_MAX_ENUM }; enum FullscreenType @@ -74,8 +75,8 @@ public: virtual ~Window(); - virtual bool setWindow(int width = 800, int height = 600, WindowAttributes *attribs = 0) = 0; - virtual void getWindow(int &width, int &height, WindowAttributes &attribs) = 0; + virtual bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr) = 0; + virtual void getWindow(int &width, int &height, WindowSettings &settings) = 0; virtual bool setFullscreen(bool fullscreen, FullscreenType fstype) = 0; virtual bool setFullscreen(bool fullscreen) = 0; @@ -113,14 +114,16 @@ public: virtual void setMouseGrab(bool grab) = 0; virtual bool isMouseGrabbed() const = 0; + virtual double getPixelScale() const = 0; + virtual const void *getHandle() const = 0; //virtual static Window *createSingleton() = 0; //virtual static Window *getSingleton() = 0; // No virtual statics, of course, but you are supposed to implement these statics. - static bool getConstant(const char *in, Attribute &out); - static bool getConstant(Attribute in, const char *&out); + static bool getConstant(const char *in, Setting &out); + static bool getConstant(Setting in, const char *&out); static bool getConstant(const char *in, FullscreenType &out); static bool getConstant(FullscreenType in, const char *&out); @@ -131,17 +134,18 @@ protected: private: - static StringMap::Entry attributeEntries[]; - static StringMap attributes; + static StringMap::Entry settingEntries[]; + static StringMap settings; static StringMap::Entry fullscreenTypeEntries[]; static StringMap fullscreenTypes; }; // Window -struct WindowAttributes +struct WindowSettings { - WindowAttributes(); + WindowSettings(); + bool fullscreen; // = false Window::FullscreenType fstype; // = FULLSCREEN_TYPE_NORMAL bool vsync; // = true @@ -152,7 +156,9 @@ struct WindowAttributes bool borderless; // = false bool centered; // = true int display; // = 0 -}; // WindowFlags + bool highdpi; // false + +}; // WindowSettings } // window } // love diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 400706687..0c94c8624 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -63,21 +63,21 @@ Window::~Window() Window::_currentMode::_currentMode() : width(800) , height(600) - , attribs() + , settings() , icon(0) { } -bool Window::setWindow(int width, int height, WindowAttributes *attribs) +bool Window::setWindow(int width, int height, WindowSettings *settings) { graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics."); - if (gfx) + if (gfx != nullptr) gfx->unSetMode(); - WindowAttributes f; + WindowSettings f; - if (attribs) - f = *attribs; + if (settings) + f = *settings; f.minwidth = std::max(f.minwidth, 1); f.minheight = std::max(f.minheight, 1); @@ -116,15 +116,28 @@ bool Window::setWindow(int width, int height, WindowAttributes *attribs) if (f.borderless) sdlflags |= SDL_WINDOW_BORDERLESS; +#if SDL_VERSION_ATLEAST(2,0,1) + if (f.highdpi) + sdlflags |= SDL_WINDOW_ALLOW_HIGHDPI; +#endif + // Destroy and recreate the window if the dimensions or flags have changed. if (window) { int curdisplay = SDL_GetWindowDisplayIndex(window); Uint32 wflags = SDL_GetWindowFlags(window); - wflags &= (SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS); + + Uint32 testflags = SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP + | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS; + +#if SDL_VERSION_ATLEAST(2,0,1) + testflags |= SDL_WINDOW_ALLOW_HIGHDPI; +#endif + + wflags &= testflags; if (sdlflags != wflags || width != curMode.width || height != curMode.height - || f.display != curdisplay || f.fsaa != curMode.attribs.fsaa) + || f.display != curdisplay || f.fsaa != curMode.settings.fsaa) { SDL_DestroyWindow(window); window = 0; @@ -182,10 +195,19 @@ bool Window::setWindow(int width, int height, WindowAttributes *attribs) created = true; - updateAttributes(f); + updateSettings(f); - if (gfx) - gfx->setMode(curMode.width, curMode.height); + if (gfx != nullptr) + { + int width = curMode.width; + int height = curMode.height; + +#if SDL_VERSION_ATLEAST(2,0,1) + SDL_GL_GetDrawableSize(window, &width, &height); +#endif + + gfx->setMode(width, height); + } // Make sure the mouse keeps its previous grab setting. setMouseGrab(mouseGrabbed); @@ -250,8 +272,8 @@ bool Window::setContext(int fsaa, bool vsync) fsaa = (buffers > 0) ? samples : 0; } - curMode.attribs.fsaa = fsaa; - curMode.attribs.vsync = SDL_GL_GetSwapInterval() != 0; + curMode.settings.fsaa = fsaa; + curMode.settings.vsync = SDL_GL_GetSwapInterval() != 0; return true; } @@ -271,7 +293,7 @@ void Window::setWindowGLAttributes(int fsaa) const SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0); } -void Window::updateAttributes(const WindowAttributes &newattribs) +void Window::updateSettings(const WindowSettings &newsettings) { Uint32 wflags = SDL_GetWindowFlags(window); @@ -280,54 +302,60 @@ void Window::updateAttributes(const WindowAttributes &newattribs) if ((wflags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { - curMode.attribs.fullscreen = true; - curMode.attribs.fstype = FULLSCREEN_TYPE_DESKTOP; + curMode.settings.fullscreen = true; + curMode.settings.fstype = FULLSCREEN_TYPE_DESKTOP; } else if ((wflags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN) { - curMode.attribs.fullscreen = true; - curMode.attribs.fstype = FULLSCREEN_TYPE_NORMAL; + curMode.settings.fullscreen = true; + curMode.settings.fstype = FULLSCREEN_TYPE_NORMAL; } else { - curMode.attribs.fullscreen = false; - curMode.attribs.fstype = newattribs.fstype; + curMode.settings.fullscreen = false; + curMode.settings.fstype = newsettings.fstype; } // The min width/height is set to 0 internally in SDL when in fullscreen. - if (curMode.attribs.fullscreen) + if (curMode.settings.fullscreen) { - curMode.attribs.minwidth = newattribs.minwidth; - curMode.attribs.minheight = newattribs.minheight; + curMode.settings.minwidth = newsettings.minwidth; + curMode.settings.minheight = newsettings.minheight; } else - SDL_GetWindowMinimumSize(window, &curMode.attribs.minwidth, &curMode.attribs.minheight); + SDL_GetWindowMinimumSize(window, &curMode.settings.minwidth, &curMode.settings.minheight); - curMode.attribs.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0; - curMode.attribs.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0; - curMode.attribs.centered = newattribs.centered; - curMode.attribs.display = std::max(SDL_GetWindowDisplayIndex(window), 0); + curMode.settings.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0; + curMode.settings.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0; + curMode.settings.centered = newsettings.centered; + curMode.settings.display = std::max(SDL_GetWindowDisplayIndex(window), 0); + +#if SDL_VERSION_ATLEAST(2,0,1) + curMode.settings.highdpi = (wflags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; +#else + curMode.settings.highdpi = false; +#endif // Only minimize on focus loss if the window is in exclusive-fullscreen // mode (mimics behaviour of SDL 2.0.2+). // In OS X we always disable this to prevent dock minimization weirdness. #ifndef LOVE_MACOSX - if (curMode.attribs.fullscreen && curMode.attribs.fstype == FULLSCREEN_TYPE_NORMAL) + if (curMode.settings.fullscreen && curMode.settings.fstype == FULLSCREEN_TYPE_NORMAL) SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1"); else #endif SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); } -void Window::getWindow(int &width, int &height, WindowAttributes &attribs) +void Window::getWindow(int &width, int &height, WindowSettings &settings) { // Window position may be different from creation - update display index. if (window) - curMode.attribs.display = std::max(SDL_GetWindowDisplayIndex(window), 0); + curMode.settings.display = std::max(SDL_GetWindowDisplayIndex(window), 0); width = curMode.width; height = curMode.height; - attribs = curMode.attribs; + settings = curMode.settings; } bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) @@ -335,9 +363,9 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) if (!window) return false; - WindowAttributes newattribs = curMode.attribs; - newattribs.fullscreen = fullscreen; - newattribs.fstype = fstype; + WindowSettings newsettings = curMode.settings; + newsettings.fullscreen = fullscreen; + newsettings.fstype = fstype; Uint32 sdlflags = 0; @@ -361,12 +389,21 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) if (SDL_SetWindowFullscreen(window, sdlflags) == 0) { SDL_GL_MakeCurrent(window, context); - updateAttributes(newattribs); + updateSettings(newsettings); // Update the viewport size now instead of waiting for event polling. graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics."); - if (gfx) - gfx->setViewportSize(curMode.width, curMode.height); + if (gfx != nullptr) + { + int width = curMode.width; + int height = curMode.height; + +#if SDL_VERSION_ATLEAST(2,0,1) + SDL_GL_GetDrawableSize(window, &width, &height); +#endif + + gfx->setViewportSize(width, height); + } return true; } @@ -376,7 +413,7 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) bool Window::setFullscreen(bool fullscreen) { - return setFullscreen(fullscreen, curMode.attribs.fstype); + return setFullscreen(fullscreen, curMode.settings.fstype); } int Window::getDisplayCount() const @@ -559,6 +596,26 @@ bool Window::isMouseGrabbed() const return mouseGrabbed; } +double Window::getPixelScale() const +{ + double scale = 1.0; + +#if SDL_VERSION_ATLEAST(2,0,1) + if (window) + { + int wheight; + SDL_GetWindowSize(window, nullptr, &wheight); + + int dheight = wheight; + SDL_GL_GetDrawableSize(window, nullptr, &dheight); + + scale = (double) dheight / wheight; + } +#endif + + return scale; +} + const void *Window::getHandle() const { return window; diff --git a/src/modules/window/sdl/Window.h b/src/modules/window/sdl/Window.h index b6e7ca953..81796663a 100644 --- a/src/modules/window/sdl/Window.h +++ b/src/modules/window/sdl/Window.h @@ -41,8 +41,8 @@ public: Window(); ~Window(); - bool setWindow(int width = 800, int height = 600, WindowAttributes *attribs = 0); - void getWindow(int &width, int &height, WindowAttributes &attribs); + bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr); + void getWindow(int &width, int &height, WindowSettings &settings); bool setFullscreen(bool fullscreen, FullscreenType fstype); bool setFullscreen(bool fullscreen); @@ -79,6 +79,8 @@ public: void setMouseGrab(bool grab); bool isMouseGrabbed() const; + double getPixelScale() const; + const void *getHandle() const; static love::window::Window *createSingleton(); @@ -91,8 +93,8 @@ private: bool setContext(int fsaa, bool vsync); void setWindowGLAttributes(int fsaa) const; - // Update the saved window attribs based on the window's actual state. - void updateAttributes(const WindowAttributes &newattribs); + // Update the saved window settings based on the window's actual state. + void updateSettings(const WindowSettings &newsettings); std::string windowTitle; @@ -102,7 +104,7 @@ private: int width; int height; - WindowAttributes attribs; + WindowSettings settings; love::image::ImageData *icon; } curMode; diff --git a/src/modules/window/wrap_Window.cpp b/src/modules/window/wrap_Window.cpp index 799c5e93d..395875111 100644 --- a/src/modules/window/wrap_Window.cpp +++ b/src/modules/window/wrap_Window.cpp @@ -26,7 +26,7 @@ namespace love namespace window { -static Window *instance = 0; +static Window *instance = nullptr; int w_getDisplayCount(lua_State *L) { @@ -34,10 +34,10 @@ int w_getDisplayCount(lua_State *L) return 1; } -static const char *attribName(Window::Attribute attrib) +static const char *settingName(Window::Setting setting) { const char *name = nullptr; - Window::getConstant(attrib, name); + Window::getConstant(setting, name); return name; } @@ -62,91 +62,94 @@ int w_setMode(lua_State *L) return luax_typerror(L, -2, "string"); const char *key = luaL_checkstring(L, -2); - Window::Attribute attrib; + Window::Setting setting; - if (!Window::getConstant(key, attrib)) - return luaL_error(L, "Invalid window attribute: %s", key); + if (!Window::getConstant(key, setting)) + return luaL_error(L, "Invalid window setting: %s", key); lua_pop(L, 1); } - WindowAttributes attribs; + WindowSettings settings; - lua_getfield(L, 3, attribName(Window::ATTRIB_FULLSCREEN_TYPE)); + lua_getfield(L, 3, settingName(Window::SETTING_FULLSCREEN_TYPE)); if (!lua_isnoneornil(L, -1)) { const char *typestr = luaL_checkstring(L, -1); - - if (!Window::getConstant(typestr, attribs.fstype)) + if (!Window::getConstant(typestr, settings.fstype)) return luaL_error(L, "Invalid fullscreen type: %s", typestr); } else { // Default to "normal" fullscreen. - attribs.fstype = Window::FULLSCREEN_TYPE_NORMAL; + settings.fstype = Window::FULLSCREEN_TYPE_NORMAL; } lua_pop(L, 1); - attribs.fullscreen = luax_boolflag(L, 3, attribName(Window::ATTRIB_FULLSCREEN), false); - attribs.vsync = luax_boolflag(L, 3, attribName(Window::ATTRIB_VSYNC), true); - attribs.fsaa = luax_intflag(L, 3, attribName(Window::ATTRIB_FSAA), 0); - attribs.resizable = luax_boolflag(L, 3, attribName(Window::ATTRIB_RESIZABLE), false); - attribs.minwidth = luax_intflag(L, 3, attribName(Window::ATTRIB_MIN_WIDTH), 1); - attribs.minheight = luax_intflag(L, 3, attribName(Window::ATTRIB_MIN_HEIGHT), 1); - attribs.borderless = luax_boolflag(L, 3, attribName(Window::ATTRIB_BORDERLESS), false); - attribs.centered = luax_boolflag(L, 3, attribName(Window::ATTRIB_CENTERED), true); - attribs.display = luax_intflag(L, 3, attribName(Window::ATTRIB_DISPLAY), 1); + settings.fullscreen = luax_boolflag(L, 3, settingName(Window::SETTING_FULLSCREEN), false); + settings.vsync = luax_boolflag(L, 3, settingName(Window::SETTING_VSYNC), true); + settings.fsaa = luax_intflag(L, 3, settingName(Window::SETTING_FSAA), 0); + settings.resizable = luax_boolflag(L, 3, settingName(Window::SETTING_RESIZABLE), false); + settings.minwidth = luax_intflag(L, 3, settingName(Window::SETTING_MIN_WIDTH), 1); + settings.minheight = luax_intflag(L, 3, settingName(Window::SETTING_MIN_HEIGHT), 1); + settings.borderless = luax_boolflag(L, 3, settingName(Window::SETTING_BORDERLESS), false); + settings.centered = luax_boolflag(L, 3, settingName(Window::SETTING_CENTERED), true); + settings.display = luax_intflag(L, 3, settingName(Window::SETTING_DISPLAY), 1); + settings.highdpi = luax_boolflag(L, 3, settingName(Window::SETTING_HIGHDPI), false); // Display index is 1-based in Lua and 0-based internally. - attribs.display--; + settings.display--; - EXCEPT_GUARD(luax_pushboolean(L, instance->setWindow(w, h, &attribs));) + EXCEPT_GUARD(luax_pushboolean(L, instance->setWindow(w, h, &settings));) return 1; } int w_getMode(lua_State *L) { int w, h; - WindowAttributes attribs; - instance->getWindow(w, h, attribs); + WindowSettings settings; + instance->getWindow(w, h, settings); lua_pushnumber(L, w); lua_pushnumber(L, h); lua_newtable(L); const char *fstypestr = "normal"; - Window::getConstant(attribs.fstype, fstypestr); + Window::getConstant(settings.fstype, fstypestr); lua_pushstring(L, fstypestr); - lua_setfield(L, -2, attribName(Window::ATTRIB_FULLSCREEN_TYPE)); + lua_setfield(L, -2, settingName(Window::SETTING_FULLSCREEN_TYPE)); - luax_pushboolean(L, attribs.fullscreen); - lua_setfield(L, -2, attribName(Window::ATTRIB_FULLSCREEN)); + luax_pushboolean(L, settings.fullscreen); + lua_setfield(L, -2, settingName(Window::SETTING_FULLSCREEN)); - luax_pushboolean(L, attribs.vsync); - lua_setfield(L, -2, attribName(Window::ATTRIB_VSYNC)); + luax_pushboolean(L, settings.vsync); + lua_setfield(L, -2, settingName(Window::SETTING_VSYNC)); - lua_pushinteger(L, attribs.fsaa); - lua_setfield(L, -2, attribName(Window::ATTRIB_FSAA)); + lua_pushinteger(L, settings.fsaa); + lua_setfield(L, -2, settingName(Window::SETTING_FSAA)); - luax_pushboolean(L, attribs.resizable); - lua_setfield(L, -2, attribName(Window::ATTRIB_RESIZABLE)); + luax_pushboolean(L, settings.resizable); + lua_setfield(L, -2, settingName(Window::SETTING_RESIZABLE)); - lua_pushinteger(L, attribs.minwidth); - lua_setfield(L, -2, attribName(Window::ATTRIB_MIN_WIDTH)); + lua_pushinteger(L, settings.minwidth); + lua_setfield(L, -2, settingName(Window::SETTING_MIN_WIDTH)); - lua_pushinteger(L, attribs.minheight); - lua_setfield(L, -2, attribName(Window::ATTRIB_MIN_HEIGHT)); + lua_pushinteger(L, settings.minheight); + lua_setfield(L, -2, settingName(Window::SETTING_MIN_HEIGHT)); - luax_pushboolean(L, attribs.borderless); - lua_setfield(L, -2, attribName(Window::ATTRIB_BORDERLESS)); + luax_pushboolean(L, settings.borderless); + lua_setfield(L, -2, settingName(Window::SETTING_BORDERLESS)); - luax_pushboolean(L, attribs.centered); - lua_setfield(L, -2, attribName(Window::ATTRIB_CENTERED)); + luax_pushboolean(L, settings.centered); + lua_setfield(L, -2, settingName(Window::SETTING_CENTERED)); // Display index is 0-based internally and 1-based in Lua. - lua_pushinteger(L, attribs.display + 1); - lua_setfield(L, -2, attribName(Window::ATTRIB_DISPLAY)); + lua_pushinteger(L, settings.display + 1); + lua_setfield(L, -2, settingName(Window::SETTING_DISPLAY)); + + luax_pushboolean(L, settings.highdpi); + lua_setfield(L, -2, settingName(Window::SETTING_HIGHDPI)); return 3; } @@ -202,14 +205,14 @@ int w_setFullscreen(lua_State *L) int w_getFullscreen(lua_State *L) { int w, h; - WindowAttributes attribs; - instance->getWindow(w, h, attribs); + WindowSettings settings; + instance->getWindow(w, h, settings); const char *typestr; - if (!Window::getConstant(attribs.fstype, typestr)) + if (!Window::getConstant(settings.fstype, typestr)) luaL_error(L, "Unknown fullscreen type."); - luax_pushboolean(L, attribs.fullscreen); + luax_pushboolean(L, settings.fullscreen); lua_pushstring(L, typestr); return 2; } @@ -300,6 +303,12 @@ int w_isVisible(lua_State *L) return 1; } +int w_getPixelScale(lua_State *L) +{ + lua_pushnumber(L, instance->getPixelScale()); + return 1; +} + static const luaL_Reg functions[] = { { "getDisplayCount", w_getDisplayCount }, @@ -320,6 +329,7 @@ static const luaL_Reg functions[] = { "hasFocus", w_hasFocus }, { "hasMouseFocus", w_hasMouseFocus }, { "isVisible", w_isVisible }, + { "getPixelScale", w_getPixelScale }, { 0, 0 } }; diff --git a/src/modules/window/wrap_Window.h b/src/modules/window/wrap_Window.h index 6bba9a574..760374c14 100644 --- a/src/modules/window/wrap_Window.h +++ b/src/modules/window/wrap_Window.h @@ -47,6 +47,7 @@ int w_getTitle(lua_State *L); int w_hasFocus(lua_State *L); int w_hasMouseFocus(lua_State *L); int w_isVisible(lua_State *L); +int w_getPixelScale(lua_State *L); extern "C" LOVE_EXPORT int luaopen_love_window(lua_State *L); } // window diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index a02e698b8..bf8766dca 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -300,6 +300,7 @@ function love.init() borderless = false, resizable = false, centered = true, + highdpi = false, }, modules = { event = true, diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index 24349aacc..f9b9d7f84 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -27,7 +27,7 @@ const unsigned char boot_lua[] = 0x2d, 0x2d, 0x5b, 0x5b, 0x0a, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, - 0x2d, 0x32, 0x30, 0x31, 0x33, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x27, 0x61, 0x73, 0x2d, 0x69, 0x73, 0x27, 0x2c, 0x20, 0x77, @@ -537,6 +537,8 @@ const unsigned char boot_lua[] = 0x73, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x2c, 0x0a, 0x09, 0x09, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a,