diff --git a/doc/changelog-old.dox b/doc/changelog-old.dox index 051cb66a2..294166150 100644 --- a/doc/changelog-old.dox +++ b/doc/changelog-old.dox @@ -108,7 +108,7 @@ Released 2018-05-01, tagged as - Ability to create @ref Platform::Sdl2Application and @ref Platform::GlfwApplication classes without implicitly created OpenGL - context by passing @ref Platform::Sdl2Application::Configuration::WindowFlag::Contextless "Configuration::WindowFlag::Contextless" + context by passing @cpp Configuration::WindowFlag::Contextless @ce to them. These two can be now also built completely without the GL library. - Added @ref Platform::AndroidApplication::windowSize() - Added @ref Platform::AndroidApplication::nativeActivity() to access @@ -157,10 +157,9 @@ Released 2018-05-01, tagged as @subsubsection changelog-2018-04-changes-platform Platform libraries -- Separated @ref Platform::Sdl2Application::Configuration "Platform::*Application::Configuration" - into @ref Platform::Sdl2Application::Configuration "Configuration" and - @ref Platform::Sdl2Application::GLConfiguration "GLConfiguration" to allow - creation of non-GL application instances in the future +- Separated @cpp Platform::*Application::Configuration @ce + into @cpp Configuration @ce and @cpp GLConfiguration @ce to allow creation + of non-GL application instances in the future @subsubsection changelog-2018-04-changes-plugins Plugins @@ -753,10 +752,10 @@ a high-level overview. possible - Ported @ref magnum-gl-info "magnum-info" to Emscripten - First-class support for scroll events in - @ref Platform::Sdl2Application::MouseScrollEvent (see - [mosra/magnum#157](https://github.com/mosra/magnum/pull/157)) -- Added @ref Platform::Sdl2Application::MouseEvent::clickCount() -- Added @ref Platform::Sdl2Application::multiGestureEvent() + @cpp Platform::Sdl2Application::MouseScrollEvent @ce + (see [mosra/magnum#157](https://github.com/mosra/magnum/pull/157)) +- Added @cpp Platform::Sdl2Application::MouseEvent::clickCount() @ce +- Added @cpp Platform::Sdl2Application::multiGestureEvent() @ce - Exposing key repeat in @ref Platform::Sdl2Application::KeyEvent::isRepeated() "Platform::*Application::KeyEvent::isRepeated()" (see [mosra/magnum#161](https://github.com/mosra/magnum/issues/161), @@ -773,8 +772,8 @@ a high-level overview. version is not what the application wants (as opposed to just aborting the application) (see [mosra/magnum#105](https://github.com/mosra/magnum/issues/105)) - Added @cpp Platform::Sdl2Application::Configuration::setSRGBCapable() @ce -- Added @ref Platform::Sdl2Application::Configuration::WindowFlag::Borderless - and `Platform::Sdl2Application::Configuration::WindowFlag::AllowHighDpi` +- Added @cpp Platform::Sdl2Application::Configuration::WindowFlag::Borderless @ce + and @cpp Platform::Sdl2Application::Configuration::WindowFlag::AllowHighDpi @ce for iOS and macOS - Added @ref Platform::WindowlessGlxApplication::Configuration::setFlags() "Platform::Windowless*Application::Configuration::setFlags()" with @ref Platform::WindowlessGlxApplication::Configuration::Flag::Debug "Flag::Debug" @@ -786,7 +785,7 @@ a high-level overview. with @ref Platform::GlfwApplication - Added modifier keys to @ref Platform::Sdl2Application::KeyEvent::Key "Platform::*Application::KeyEvent::Key" -- Added @ref Platform::Sdl2Application::InputEvent::Modifier::Super to be +- Added @cpp Platform::Sdl2Application::InputEvent::Modifier::Super @ce to be consistent with @ref Platform::GlfwApplication (see [mosra/magnum#159](https://github.com/mosra/magnum/pull/159)) - Added @ref Platform::Sdl2Application::KeyEvent::keyName() "Platform::*Application::KeyEvent::keyName()" @@ -1102,10 +1101,10 @@ a high-level overview. `Platform::GlfwApplication::MouseEvent::Button::WheelDown` mouse events are deprecated, use @ref Platform::Sdl2Application::mouseScrollEvent() / @ref Platform::GlfwApplication::mouseScrollEvent() and - @ref Platform::Sdl2Application::MouseScrollEvent / + @cpp Platform::Sdl2Application::MouseScrollEvent @ce / @ref Platform::GlfwApplication::MouseScrollEvent instead -- @ref Platform::Sdl2Application::Sdl2Application() "Platform::*Application::*Application()" - and @ref Platform::WindowlessGlxApplication::WindowlessGlxApplication() "Platform::Windowless*Application::Windowless*Application()" +- @cpp Platform::*Application::*Application() @ce and + @ref Platform::WindowlessGlxApplication::WindowlessGlxApplication() "Platform::Windowless*Application::Windowless*Application()" constructors taking @cpp nullptr @ce are deprecated, use constructors taking @ref NoCreateT instead to create an application without creating OpenGL context @@ -1844,7 +1843,7 @@ for a high-level overview. purely integral coordinates, useful e.g. for UI or 2D platformers. - Detailed collision queries and new `InvertedSphere` shape in Shapes library - Texture support in @cpp Shaders::Flat @ce -- Mouse button queries in @ref Platform::Sdl2Application::MouseMoveEvent "Platform::*Application::MouseMoveEvent" +- Mouse button queries in @cpp Platform::*Application::MouseMoveEvent @ce @subsection changelog-2013-10-changes Changes diff --git a/doc/changelog.dox b/doc/changelog.dox index 5654acdf3..d93c97180 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -732,13 +732,13 @@ See also: - Added @ref Platform::EmscriptenApplication::Configuration::addWindowFlags() and @ref Platform::EmscriptenApplication::Configuration::clearWindowFlags() for consistency with other application implementations -- Added @ref Platform::Sdl2Application::KeyEvent::Key::CapsLock, - @relativeref{Platform::Sdl2Application::KeyEvent::Key,ScrollLock}, - @relativeref{Platform::Sdl2Application::KeyEvent::Key,NumLock}, - @relativeref{Platform::Sdl2Application::KeyEvent::Key,PrintScreen}, - @relativeref{Platform::Sdl2Application::KeyEvent::Key,Pause} and - @relativeref{Platform::Sdl2Application::KeyEvent::Key,Menu} for consistency - with @ref Platform::EmscriptenApplication and +- Added @ref Platform::Sdl2ApplicationWindow::KeyEvent::Key::CapsLock, + @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,ScrollLock}, + @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,NumLock}, + @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,PrintScreen}, + @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,Pause} and + @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,Menu} for + consistency with @ref Platform::EmscriptenApplication and @ref Platform::GlfwApplication (see [mosra/magnum#547](https://github.com/mosra/magnum/pull/547)) - @ref Platform::Sdl2Application now overrides SDL's default behavior that prevents computer from entering a power-saving mode while the application @@ -1103,9 +1103,9 @@ See also: destroyed could fail with an error saying "cannot make the previous context current" on certain system. This was due to EGL not destroying the context if it's still made current. -- Fixed handling of @ref Platform::Sdl2Application::InputEvent::Modifier::Super, - which was misreported as @relativeref{Platform::Sdl2Application::InputEvent::Modifier,Alt} (see - [mosra/magnum#547](https://github.com/mosra/magnum/pull/547)) +- Fixed handling of @ref Platform::Sdl2ApplicationWindow::InputEvent::Modifier::Super, + which was misreported as @relativeref{Platform::Sdl2ApplicationWindow::InputEvent::Modifier,Alt} + (see [mosra/magnum#547](https://github.com/mosra/magnum/pull/547)) - For meshes with multiple sets of vertex attributes (such as texture coordinates), @ref MeshTools::compile() should be using only the first set but it wasn't. @@ -1969,12 +1969,12 @@ Released 2020-06-27, tagged as @ref Platform::AbstractXApplication::mainLoopIteration() for consistency with @ref Platform::Sdl2Application (see [mosra/magnum#387](https://github.com/mosra/magnum/pull/387)) -- Added @ref Platform::Sdl2Application::KeyEvent::Key::Quote "Key::Quote", - @ref Platform::Sdl2Application::KeyEvent::Key::LeftBracket "Key::LeftBracket", - @ref Platform::Sdl2Application::KeyEvent::Key::RightBracket "Key::RightBracket", - @ref Platform::Sdl2Application::KeyEvent::Key::Backslash "Key::Backslash" and - @ref Platform::Sdl2Application::KeyEvent::Key::Backquote "Key::Backquote" - keys to @ref Platform::Sdl2Application::KeyEvent and +- Added @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::Quote}, + @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::LeftBracket}, + @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::RightBracket}, + @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::Backslash} and + @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::Backquote} + keys to @cpp Platform::Sdl2Application::KeyEvent @ce and @ref Platform::GlfwApplication::KeyEvent - Added @ref Platform::GlfwApplication::KeyEvent::Key::World1 and @ref Platform::GlfwApplication::KeyEvent::Key::World2 @@ -1992,12 +1992,9 @@ Released 2020-06-27, tagged as - CUDA device selection in @ref Platform::WindowlessEglApplication (see [mosra/magnum#449](https://github.com/mosra/magnum/pull/449)) - Added @ref Platform::GlfwApplication::Configuration::WindowFlag::Borderless -- Added @ref Platform::Sdl2Application::Configuration::WindowFlag::FullscreenDesktop, - @ref Platform::Sdl2Application::Configuration::WindowFlag::AlwaysOnTop "AlwaysOnTop", - @ref Platform::Sdl2Application::Configuration::WindowFlag::SkipTaskbar "SkipTaskbar", - @ref Platform::Sdl2Application::Configuration::WindowFlag::Utility "Utility", - @ref Platform::Sdl2Application::Configuration::WindowFlag::Tooltip "Tooltip" - and @ref Platform::Sdl2Application::Configuration::WindowFlag::PopupMenu "PopupMenu" +- Added @cpp Platform::Sdl2Application::Configuration::WindowFlag::FullscreenDesktop @ce, + @cpp AlwaysOnTop @ce, @cpp SkipTaskbar @ce, @cpp Utility @ce, + @cpp Tooltip @ce and @cpp PopupMenu @ce - Added @ref Platform::Sdl2Application::Configuration::addWindowFlags() and @ref Platform::Sdl2Application::Configuration::clearWindowFlags() "clearWindowFlags()" for consistency with similar functions in @@ -2299,7 +2296,7 @@ Released 2020-06-27, tagged as - The @ref Primitives::cylinderSolid() and @ref Primitives::coneSolid() primitives were missing a face when both caps and texture coordinates were enabled (see [mosra/magnum#386](https://github.com/mosra/magnum/issues/386)) -- @ref Platform::Sdl2Application::Configuration::WindowFlag::Vulkan was +- @cpp Platform::Sdl2Application::Configuration::WindowFlag::Vulkan @ce was enabled conditionally only for SDL >= 2.0.6, but the version defines were never included so it was always disabled - Fixed missing handling of @@ -2330,7 +2327,7 @@ Released 2020-06-27, tagged as caused @ref Platform::Sdl2Application::setMinimalLoopPeriod() "setMinimalLoopPeriod()" to be ignored even though Vsync was in fact not enabled. - It was not possible to override DPI scaling using - @ref Platform::Sdl2Application::Configuration as command-line arguments + @cpp Platform::Sdl2Application::Configuration @ce as command-line arguments always got a priority (see [mosra/magnum#416](https://github.com/mosra/magnum/issues/416)) - Fixed an otherwise harmless OOB access in @ref MeshTools::tipsifyInPlace() that could trigger ASan or debug iterator errors @@ -2832,10 +2829,10 @@ Released 2019-10-24, tagged as in @ref Platform::GlfwApplication and @ref Platform::EmscriptenApplication) for changing window title at runtime as opposed to setting them on application startup -- Added @ref Platform::Sdl2Application::Configuration::WindowFlag::OpenGL and - @ref Platform::Sdl2Application::Configuration::WindowFlag::Vulkan "WindowFlag::Vulkan", - meant to be used together with @ref Platform::Sdl2Application::Configuration::WindowFlag::Contextless for - manual creation of OpenGL contexts and Vulkan instances +- Added @cpp Platform::Sdl2Application::Configuration::WindowFlag::OpenGL @ce + and @cpp WindowFlag::Vulkan @ce, meant to be used together with + @cpp Platform::Sdl2Application::Configuration::WindowFlag::Contextless @ce + for manual creation of OpenGL contexts and Vulkan instances - @ref Platform::WindowlessEglApplication now uses the @m_class{m-doc-external} [EGL_EXT_device_enumeration](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_enumeration.txt), @m_class{m-doc-external} [EGL_EXT_platform_base](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_platform_base.txt) and diff --git a/doc/platform.dox b/doc/platform.dox index 27636dd1a..78a77486d 100644 --- a/doc/platform.dox +++ b/doc/platform.dox @@ -136,8 +136,8 @@ target_link_libraries(myapplication @section platform-configuration Specifying configuration By default the application is created with some reasonable defaults (e.g. -window size 800x600 pixels). If you want something else, you can pass -@ref Platform::Sdl2Application::Configuration "Configuration" instance to +window size 800x600 pixels). If you want something else, you can pass a +@relativeref{Platform::Sdl2ApplicationWindow,Configuration} instance to the application constructor. Using method chaining it can be done conveniently like this: @@ -148,7 +148,7 @@ this: Sometimes you may want to set up the application based on a configuration file or system introspection, which can't really be done inside the base class initializer. You can specify @ref NoCreate in the constructor instead and pass -the @relativeref{Platform::Sdl2Application,Configuration} later to a +the @relativeref{Platform::Sdl2ApplicationWindow,Configuration} later to a @relativeref{Platform::Sdl2Application,create()} function: @snippet MagnumPlatform.cpp createcontext diff --git a/src/Magnum/Platform/AndroidApplication.h b/src/Magnum/Platform/AndroidApplication.h index 2c20b326e..dadab90a8 100644 --- a/src/Magnum/Platform/AndroidApplication.h +++ b/src/Magnum/Platform/AndroidApplication.h @@ -149,8 +149,8 @@ to simplify porting. @section Platform-AndroidApplication-resizing Responding to viewport events Unlike in desktop application implementations, where this is controlled via -@ref Sdl2Application::Configuration::WindowFlag::Resizable, for example, on -Android you have to describe this in the `AndroidManifest.xml` file, as by +@ref Sdl2ApplicationWindow::Configuration::WindowFlag::Resizable, for example, +on Android you have to describe this in the `AndroidManifest.xml` file, as by default the application gets killed and relaunched on screen orientation change. See the @ref platforms-android-apps-manifest-screen-resize "manifest file docs" for more information. diff --git a/src/Magnum/Platform/Screen.h b/src/Magnum/Platform/Screen.h index 6442389a3..ce65879ae 100644 --- a/src/Magnum/Platform/Screen.h +++ b/src/Magnum/Platform/Screen.h @@ -175,7 +175,7 @@ template class BasicScreen: * @brief Key event * * Defined only if the application has a - * @ref Sdl2Application::KeyEvent "KeyEvent". + * @relativeref{Sdl2ApplicationWindow,KeyEvent}. */ typedef typename BasicScreenedApplication::KeyEvent KeyEvent; #endif @@ -192,7 +192,7 @@ template class BasicScreen: * @m_since{2019,10} * * Defined only if the application has a - * @ref Sdl2Application::MouseScrollEvent "MouseScrollEvent". + * @relativeref{Sdl2ApplicationWindow,MouseScrollEvent}. */ typedef typename BasicScreenedApplication::MouseScrollEvent MouseScrollEvent; @@ -201,7 +201,7 @@ template class BasicScreen: * @m_since{2019,10} * * Defined only if the application has a - * @ref Sdl2Application::TextInputEvent "TextInputEvent". + * @relativeref{Sdl2ApplicationWindow,TextInputEvent}. */ typedef typename BasicScreenedApplication::TextInputEvent TextInputEvent; @@ -210,7 +210,7 @@ template class BasicScreen: * @m_since{2019,10} * * Defined only if the application has a - * @ref Sdl2Application::TextEditingEvent "TextEditingEvent". + * @relativeref{Sdl2ApplicationWindow,TextEditingEvent}. */ typedef typename BasicScreenedApplication::TextEditingEvent TextEditingEvent; #endif @@ -379,7 +379,7 @@ template class BasicScreen: * Called when @ref PropagatedEvent::Input is enabled and an key is * pressed. See @ref Sdl2Application::keyPressEvent() "*Application::keyPressEvent()" * for more information. Defined only if the application has a - * @ref Sdl2Application::KeyEvent "KeyEvent". + * @relativeref{Sdl2ApplicationWindow,KeyEvent}. */ virtual void keyPressEvent(KeyEvent& event); @@ -389,7 +389,7 @@ template class BasicScreen: * Called when @ref PropagatedEvent::Input is enabled and an key is * released. See @ref Sdl2Application::keyReleaseEvent() "*Application::keyReleaseEvent()" * for more information. Defined only if the application has a - * @ref Sdl2Application::KeyEvent "KeyEvent". + * @relativeref{Sdl2ApplicationWindow,KeyEvent}. */ virtual void keyReleaseEvent(KeyEvent& event); #endif @@ -437,7 +437,7 @@ template class BasicScreen: * Called when @ref PropagatedEvent::Input is enabled and mouse wheel * is rotated. See @ref Sdl2Application::mouseScrollEvent() "*Application::mouseScrollEvent()" * for more information. Defined only if the application has a - * @ref Sdl2Application::MouseScrollEvent "MouseScrollEvent". + * @relativeref{Sdl2ApplicationWindow,MouseScrollEvent}. */ virtual void mouseScrollEvent(MouseScrollEvent& event); #endif @@ -457,7 +457,7 @@ template class BasicScreen: * * Called when @ref PropagatedEvent::Input is enabled and text is being * input. Defined only if the application has a - * @ref Sdl2Application::TextInputEvent "TextInputEvent". + * @relativeref{Sdl2ApplicationWindow,TextInputEvent}. */ virtual void textInputEvent(TextInputEvent& event); @@ -467,7 +467,7 @@ template class BasicScreen: * * Called when @ref PropagatedEvent::Input and the text is being * edited. Defined only if the application has a - * @ref Sdl2Application::TextEditingEvent "TextEditingEvent". + * @relativeref{Sdl2ApplicationWindow,TextEditingEvent}. */ virtual void textEditingEvent(TextEditingEvent& event); #endif diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index 64bb91c54..c9eec6318 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -78,142 +78,25 @@ namespace Magnum { namespace Platform { using namespace Containers::Literals; -namespace { - -/* - * Fix up the modifiers -- we want >= operator to work properly on Shift, - * Ctrl, Alt, but SDL generates different event for left / right keys, thus - * (modifiers >= Shift) would pass only if both left and right were pressed, - * which is usually not what the developers wants. - */ -Sdl2Application::InputEvent::Modifiers fixedModifiers(Uint16 mod) { - Sdl2Application::InputEvent::Modifiers modifiers(static_cast(mod)); - if(modifiers & Sdl2Application::InputEvent::Modifier::Shift) modifiers |= Sdl2Application::InputEvent::Modifier::Shift; - if(modifiers & Sdl2Application::InputEvent::Modifier::Ctrl) modifiers |= Sdl2Application::InputEvent::Modifier::Ctrl; - if(modifiers & Sdl2Application::InputEvent::Modifier::Alt) modifiers |= Sdl2Application::InputEvent::Modifier::Alt; - if(modifiers & Sdl2Application::InputEvent::Modifier::Super) modifiers |= Sdl2Application::InputEvent::Modifier::Super; - return modifiers; -} - -} - -enum class Sdl2Application::Flag: UnsignedByte { +enum class Sdl2ApplicationWindow::WindowFlag: UnsignedByte { Redraw = 1 << 0, - VSyncEnabled = 1 << 1, - NoTickEvent = 1 << 2, - NoAnyEvent = 1 << 3, - Exit = 1 << 4, #ifdef CORRADE_TARGET_EMSCRIPTEN - TextInputActive = 1 << 5, - Resizable = 1 << 6, - #endif - #ifdef CORRADE_TARGET_APPLE - HiDpiWarningPrinted = 1 << 7 + TextInputActive = 1 << 1, + Resizable = 1 << 2, #endif }; -Sdl2Application::Sdl2Application(const Arguments& arguments): Sdl2Application{arguments, Configuration{}} {} - -Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration& configuration): Sdl2Application{arguments, NoCreate} { - create(configuration); -} - -#ifdef MAGNUM_TARGET_GL -Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration& configuration, const GLConfiguration& glConfiguration): Sdl2Application{arguments, NoCreate} { - create(configuration, glConfiguration); -} -#endif +Sdl2ApplicationWindow::Sdl2ApplicationWindow(Sdl2Application& application, NoCreateT): _application{application}, _windowFlags{WindowFlag::Redraw} {} -Sdl2Application::Sdl2Application(const Arguments& arguments, NoCreateT): +Sdl2ApplicationWindow::~Sdl2ApplicationWindow() { + /* SDL_DestroyWindow(_window) crashes on windows when _window is nullptr + (it doesn't seem to crash on Linux) */ #ifndef CORRADE_TARGET_EMSCRIPTEN - _minimalLoopPeriod{0}, - #endif - _flags{Flag::Redraw} -{ - Utility::Arguments args{Implementation::windowScalingArguments()}; - #ifdef MAGNUM_TARGET_GL - _context.emplace(NoCreate, args, arguments.argc, arguments.argv); - #else - /** @todo this is duplicated here, in GlfwApplication and in - EmscriptenApplication, figure out a nice non-duplicated way to handle - this */ - args.addOption("log", "default").setHelp("log", "console logging", "default|quiet|verbose") - .setFromEnvironment("log") - .parse(arguments.argc, arguments.argv); - #endif - - /* Available since 2.0.4, disables interception of SIGINT and SIGTERM so - it's possible to Ctrl-C the application even if exitEvent() doesn't set - event.setAccepted(). */ - #ifdef SDL_HINT_NO_SIGNAL_HANDLERS - SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); - #endif - /* Available since 2.0.6, uses dedicated OpenGL ES drivers if EGL is used, - and desktop GLES context otherwise. */ - #if defined(MAGNUM_TARGET_GLES) && defined(MAGNUM_TARGET_EGL) && defined(SDL_HINT_OPENGL_ES_DRIVER) - SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1"); - #endif - /* Available since 2.0.8, disables compositor bypass on X11, which causes - flickering on KWin as the compositor gets shut down on every startup */ - #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR - SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); - #endif - /* By default, SDL behaves like if it was playing a video or whatever, - preventing the computer from turning off the screen or going to sleep. - While it sorta makes sense for games, it's useless and annoying for - regular apps. Together with the compositor disabling those two are the - most stupid defaults. */ - #ifdef SDL_HINT_VIDEO_ALLOW_SCREENSAVER - SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1"); - #endif - /* Available since 2.0.12, use EGL if desired */ - #if defined(MAGNUM_TARGET_EGL) && defined(SDL_HINT_VIDEO_X11_FORCE_EGL) - SDL_SetHint(SDL_HINT_VIDEO_X11_FORCE_EGL, "1"); - #endif - - if(SDL_Init(SDL_INIT_VIDEO) < 0) { - Error() << "Cannot initialize SDL:" << SDL_GetError(); - std::exit(1); - } - - /* Save command-line arguments */ - if(args.value("log") == "verbose") _verboseLog = true; - const Containers::StringView dpiScaling = args.value("dpi-scaling"); - if(dpiScaling == "default"_s) - _commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Default; - #ifdef CORRADE_TARGET_APPLE - else if(dpiScaling == "framebuffer"_s) - _commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Framebuffer; - #endif - #ifndef CORRADE_TARGET_APPLE - #if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_ANDROID) - else if(dpiScaling == "virtual"_s) - _commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Virtual; - #endif - else if(dpiScaling == "physical"_s) - _commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Physical; + if(_window) SDL_DestroyWindow(_window); #endif - else if(dpiScaling.containsAny(" \t\n"_s)) - _commandLineDpiScaling = args.value("dpi-scaling"); - else - _commandLineDpiScaling = Vector2{args.value("dpi-scaling")}; } -void Sdl2Application::create() { - create(Configuration{}); -} - -void Sdl2Application::create(const Configuration& configuration) { - if(!tryCreate(configuration)) std::exit(1); -} - -#ifdef MAGNUM_TARGET_GL -void Sdl2Application::create(const Configuration& configuration, const GLConfiguration& glConfiguration) { - if(!tryCreate(configuration, glConfiguration)) std::exit(1); -} -#endif - -Vector2 Sdl2Application::dpiScaling(const Configuration& configuration) { +Vector2 Sdl2ApplicationWindow::dpiScaling(const Configuration& configuration) { /* Print a helpful warning in case some extra steps are needed for HiDPI support */ #ifdef CORRADE_TARGET_APPLE @@ -229,18 +112,18 @@ Vector2 Sdl2Application::dpiScaling(const Configuration& configuration) { return dpiScalingInternal(configuration.dpiScalingPolicy(), configuration.dpiScaling()); } -Vector2 Sdl2Application::dpiScalingInternal(const Implementation::Sdl2DpiScalingPolicy configurationDpiScalingPolicy, const Vector2& configurationDpiScaling) const { - std::ostream* verbose = _verboseLog ? Debug::output() : nullptr; +Vector2 Sdl2ApplicationWindow::dpiScalingInternal(const Implementation::Sdl2DpiScalingPolicy configurationDpiScalingPolicy, const Vector2& configurationDpiScaling) const { + std::ostream* verbose = _application._verboseLog ? Debug::output() : nullptr; /* Use values from the configuration only if not overridden on command line to something non-default. In any case explicit scaling has a precedence before the policy. */ Implementation::Sdl2DpiScalingPolicy dpiScalingPolicy{}; - if(!_commandLineDpiScaling.isZero()) { - Debug{verbose} << "Platform::Sdl2Application: user-defined DPI scaling" << _commandLineDpiScaling; - return _commandLineDpiScaling; - } else if(_commandLineDpiScalingPolicy != Implementation::Sdl2DpiScalingPolicy::Default) { - dpiScalingPolicy = _commandLineDpiScalingPolicy; + if(!_application._commandLineDpiScaling.isZero()) { + Debug{verbose} << "Platform::Sdl2Application: user-defined DPI scaling" << _application._commandLineDpiScaling; + return _application._commandLineDpiScaling; + } else if(_application._commandLineDpiScalingPolicy != Implementation::Sdl2DpiScalingPolicy::Default) { + dpiScalingPolicy = _application._commandLineDpiScalingPolicy; } else if(!configurationDpiScaling.isZero()) { Debug{verbose} << "Platform::Sdl2Application: app-defined DPI scaling" << configurationDpiScaling; return configurationDpiScaling; @@ -322,72 +205,360 @@ Vector2 Sdl2Application::dpiScalingInternal(const Implementation::Sdl2DpiScaling #else Debug{verbose} << "Platform::Sdl2Application: sorry, physical DPI scaling only available on SDL 2.0.4+"; #endif - return Vector2{1.0f}; + return Vector2{1.0f}; + + /* HOWEVER, on Windows it gets the virtual DPI scaling, which we don't + want, so we need to call Windows APIs directly instead. Consistency my + ass. Related bug report that will probably never get actually + implemented: https://bugzilla.libsdl.org/show_bug.cgi?id=2473 */ + #elif defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT) + HDC hDC = GetWindowDC(nullptr); + Vector2i monitorSize{GetDeviceCaps(hDC, HORZSIZE), GetDeviceCaps(hDC, VERTSIZE)}; + SDL_DisplayMode mode; + CORRADE_INTERNAL_ASSERT(SDL_GetDesktopDisplayMode(0, &mode) == 0); + auto dpi = Vector2{Vector2i{mode.w, mode.h}*25.4f/Vector2{monitorSize}}; + const Vector2 dpiScaling{dpi/96.0f}; + Debug{verbose} << "Platform::Sdl2Application: physical DPI scaling" << dpiScaling; + return dpiScaling; + + /* Not implemented otherwise */ + #else + Debug{verbose} << "Platform::Sdl2Application: sorry, physical DPI scaling not implemented on this platform yet"; + return Vector2{1.0f}; + #endif + #endif +} + +void Sdl2ApplicationWindow::setWindowTitle(const Containers::StringView title) { + #ifndef CORRADE_TARGET_EMSCRIPTEN + SDL_SetWindowTitle(_window, + Containers::String::nullTerminatedGlobalView(title).data()); + #else + /* We don't have the _window because SDL_CreateWindow() doesn't exist in + the SDL1/2 hybrid. But it's not used anyway, so pass nullptr there. */ + SDL_SetWindowTitle(nullptr, + Containers::String::nullTerminatedGlobalView(title).data()); + #endif +} + +#if !defined(CORRADE_TARGET_EMSCRIPTEN) && SDL_MAJOR_VERSION*1000 + SDL_MINOR_VERSION*100 + SDL_PATCHLEVEL >= 2005 +void Sdl2ApplicationWindow::setWindowIcon(const ImageView2D& image) { + Uint32 format; /** @todo handle sRGB differently? */ + switch(image.format()) { + case PixelFormat::RGB8Srgb: + case PixelFormat::RGB8Unorm: + format = SDL_PIXELFORMAT_RGB24; + break; + case PixelFormat::RGBA8Srgb: + case PixelFormat::RGBA8Unorm: + format = SDL_PIXELFORMAT_RGBA32; + break; + default: + CORRADE_ASSERT_UNREACHABLE("Platform::Sdl2ApplicationWindow::setWindowIcon(): unexpected format" << image.format(), ); + } + + /* Images are loaded with origin at bottom left, flip it to top left. SDL + only accepted a negative stride until version 2.23.1 and commit + https://github.com/libsdl-org/SDL/commit/535fdc3adcdc08a193ab0d45540014fd536cf251 + so we need to manually flip the image now */ + /** @todo take ImageFlag::YUp into account once it exists */ + Image2D flippedImage{PixelStorage{}.setAlignment(1), image.format(), image.size(), Containers::Array{NoInit, std::size_t(image.size().product()*image.pixelSize())}}; + const Containers::StridedArrayView3D flippedPixels = flippedImage.pixels(); + Utility::copy(image.pixels().flipped<0>(), flippedPixels); + + SDL_Surface* const icon = SDL_CreateRGBSurfaceWithFormatFrom(const_cast(flippedPixels.data()) , flippedImage.size().x(), flippedImage.size().y(), 32, flippedPixels.stride()[0], format); + CORRADE_INTERNAL_ASSERT(icon); + + SDL_SetWindowIcon(_window, icon); + SDL_FreeSurface(icon); +} +#endif + +Vector2i Sdl2ApplicationWindow::windowSize() const { + Vector2i size; + #ifndef CORRADE_TARGET_EMSCRIPTEN + CORRADE_ASSERT(_window, "Platform::Sdl2Application::windowSize(): no window opened", {}); + SDL_GetWindowSize(_window, &size.x(), &size.y()); + #else + CORRADE_ASSERT(_surface, "Platform::Sdl2Application::windowSize(): no window opened", {}); + emscripten_get_canvas_element_size("#canvas", &size.x(), &size.y()); + #endif + return size; +} + +#ifndef CORRADE_TARGET_EMSCRIPTEN +void Sdl2ApplicationWindow::setWindowSize(const Vector2i& size) { + CORRADE_ASSERT(_window, "Platform::Sdl2Application::setWindowSize(): no window opened", ); + + const Vector2i newSize = dpiScaling()*size; + SDL_SetWindowSize(_window, newSize.x(), newSize.y()); +} + +void Sdl2ApplicationWindow::setMinWindowSize(const Vector2i& size) { + CORRADE_ASSERT(_window, "Platform::Sdl2Application::setMinWindowSize(): no window opened", ); + + const Vector2i newSize = dpiScaling()*size; + SDL_SetWindowMinimumSize(_window, newSize.x(), newSize.y()); +} + +void Sdl2ApplicationWindow::setMaxWindowSize(const Vector2i& size) { + CORRADE_ASSERT(_window, "Platform::Sdl2Application::setMaxWindowSize(): no window opened", ); + + const Vector2i newSize = dpiScaling()*size; + SDL_SetWindowMaximumSize(_window, newSize.x(), newSize.y()); +} +#endif + +#ifdef MAGNUM_TARGET_GL +Vector2i Sdl2ApplicationWindow::framebufferSize() const { + Vector2i size; + #ifndef CORRADE_TARGET_EMSCRIPTEN + CORRADE_ASSERT(_window, "Platform::Sdl2Application::framebufferSize(): no window opened", {}); + SDL_GL_GetDrawableSize(_window, &size.x(), &size.y()); + #else + CORRADE_ASSERT(_surface, "Platform::Sdl2Application::framebufferSize(): no window opened", {}); + emscripten_get_canvas_element_size("#canvas", &size.x(), &size.y()); + #endif + return size; +} +#endif + +Vector2 Sdl2ApplicationWindow::dpiScaling() const { + return dpiScalingInternal(_application._configurationDpiScalingPolicy, _application._configurationDpiScaling); +} + +void Sdl2ApplicationWindow::redraw() { _windowFlags |= WindowFlag::Redraw; } + +namespace { + +#ifndef CORRADE_TARGET_EMSCRIPTEN +constexpr SDL_SystemCursor CursorMap[] { + SDL_SYSTEM_CURSOR_ARROW, + SDL_SYSTEM_CURSOR_IBEAM, + SDL_SYSTEM_CURSOR_WAIT, + SDL_SYSTEM_CURSOR_CROSSHAIR, + SDL_SYSTEM_CURSOR_WAITARROW, + SDL_SYSTEM_CURSOR_SIZENWSE, + SDL_SYSTEM_CURSOR_SIZENESW, + SDL_SYSTEM_CURSOR_SIZEWE, + SDL_SYSTEM_CURSOR_SIZENS, + SDL_SYSTEM_CURSOR_SIZEALL, + SDL_SYSTEM_CURSOR_NO, + SDL_SYSTEM_CURSOR_HAND +}; +#else +constexpr Containers::StringView CursorMap[] { + "default"_s, + "text"_s, + "wait"_s, + "crosshair"_s, + "progress"_s, + "nwse-resize"_s, + "nesw-resize"_s, + "ew-resize"_s, + "ns-resize"_s, + "move"_s, + "not-allowed"_s, + "pointer"_s, + "none"_s + /* Hidden & locked not supported yet */ +}; +#endif + +} + +void Sdl2ApplicationWindow::setCursor(Cursor cursor) { + #ifndef CORRADE_TARGET_EMSCRIPTEN + CORRADE_ASSERT(_window, "Platform::Sdl2ApplicationWindow::setCursor(): no window opened", ); + + if(cursor == Cursor::Hidden) { + SDL_ShowCursor(SDL_DISABLE); + SDL_SetWindowGrab(_window, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + return; + } else if(cursor == Cursor::HiddenLocked) { + SDL_SetWindowGrab(_window, SDL_TRUE); + SDL_SetRelativeMouseMode(SDL_TRUE); + return; + } else { + SDL_ShowCursor(SDL_ENABLE); + SDL_SetWindowGrab(_window, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + } + + /* The second condition could be a static assert but it doesn't let me + because "this pointer only accessible in a constexpr function". Thanks + for nothing, C++. */ + CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(_application._cursors) && Containers::arraySize(_application._cursors) == Containers::arraySize(CursorMap)); + + if(!_application._cursors[UnsignedInt(cursor)]) + _application._cursors[UnsignedInt(cursor)] = SDL_CreateSystemCursor(CursorMap[UnsignedInt(cursor)]); + + SDL_SetCursor(_application._cursors[UnsignedInt(cursor)]); + #else + CORRADE_ASSERT(_surface, "Platform::Sdl2Application::setCursor(): no window opened", ); + _cursor = cursor; + CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(CursorMap)); + magnumPlatformSetCursor(CursorMap[UnsignedInt(cursor)].data(), + CursorMap[UnsignedInt(cursor)].size()); + #endif +} + +Sdl2Application::Cursor Sdl2ApplicationWindow::cursor() { + #ifndef CORRADE_TARGET_EMSCRIPTEN + if(SDL_GetRelativeMouseMode()) + return Cursor::HiddenLocked; + else if(!SDL_ShowCursor(SDL_QUERY)) + return Cursor::Hidden; + + SDL_Cursor* cursor = SDL_GetCursor(); + + if(cursor) for(UnsignedInt i = 0; i < sizeof(_application._cursors); i++) + if(_application._cursors[i] == cursor) return Cursor(i); + + return Cursor::Arrow; + #else + return _cursor; + #endif +} + +void Sdl2ApplicationWindow::viewportEvent(ViewportEvent&) {} +void Sdl2ApplicationWindow::keyPressEvent(KeyEvent&) {} +void Sdl2ApplicationWindow::keyReleaseEvent(KeyEvent&) {} +void Sdl2ApplicationWindow::mousePressEvent(MouseEvent&) {} +void Sdl2ApplicationWindow::mouseReleaseEvent(MouseEvent&) {} +void Sdl2ApplicationWindow::mouseMoveEvent(MouseMoveEvent&) {} +void Sdl2ApplicationWindow::mouseScrollEvent(MouseScrollEvent&) {} +void Sdl2ApplicationWindow::multiGestureEvent(MultiGestureEvent&) {} +void Sdl2ApplicationWindow::textInputEvent(TextInputEvent&) {} +void Sdl2ApplicationWindow::textEditingEvent(TextEditingEvent&) {} + +namespace { + +/* + * Fix up the modifiers -- we want >= operator to work properly on Shift, + * Ctrl, Alt, but SDL generates different event for left / right keys, thus + * (modifiers >= Shift) would pass only if both left and right were pressed, + * which is usually not what the developers wants. + */ +Sdl2Application::InputEvent::Modifiers fixedModifiers(Uint16 mod) { + Sdl2Application::InputEvent::Modifiers modifiers(static_cast(mod)); + if(modifiers & Sdl2Application::InputEvent::Modifier::Shift) modifiers |= Sdl2Application::InputEvent::Modifier::Shift; + if(modifiers & Sdl2Application::InputEvent::Modifier::Ctrl) modifiers |= Sdl2Application::InputEvent::Modifier::Ctrl; + if(modifiers & Sdl2Application::InputEvent::Modifier::Alt) modifiers |= Sdl2Application::InputEvent::Modifier::Alt; + if(modifiers & Sdl2Application::InputEvent::Modifier::Super) modifiers |= Sdl2Application::InputEvent::Modifier::Super; + return modifiers; +} + +} + +enum class Sdl2Application::Flag: UnsignedByte { + VSyncEnabled = 1 << 0, + NoTickEvent = 1 << 1, + NoAnyEvent = 1 << 2, + Exit = 1 << 3, + #ifdef CORRADE_TARGET_APPLE + HiDpiWarningPrinted = 1 << 4 + #endif +}; + +Sdl2Application::Sdl2Application(const Arguments& arguments): Sdl2Application{arguments, Configuration{}} {} + +Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration& configuration): Sdl2Application{arguments, NoCreate} { + create(configuration); +} + +#ifdef MAGNUM_TARGET_GL +Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration& configuration, const GLConfiguration& glConfiguration): Sdl2Application{arguments, NoCreate} { + create(configuration, glConfiguration); +} +#endif + +Sdl2Application::Sdl2Application(const Arguments& arguments, NoCreateT): Sdl2ApplicationWindow{*this, NoCreate} + #ifndef CORRADE_TARGET_EMSCRIPTEN + , _minimalLoopPeriod{0} + #endif +{ + Utility::Arguments args{Implementation::windowScalingArguments()}; + #ifdef MAGNUM_TARGET_GL + _context.emplace(NoCreate, args, arguments.argc, arguments.argv); + #else + /** @todo this is duplicated here, in GlfwApplication and in + EmscriptenApplication, figure out a nice non-duplicated way to handle + this */ + args.addOption("log", "default").setHelp("log", "console logging", "default|quiet|verbose") + .setFromEnvironment("log") + .parse(arguments.argc, arguments.argv); + #endif + + /* Available since 2.0.4, disables interception of SIGINT and SIGTERM so + it's possible to Ctrl-C the application even if exitEvent() doesn't set + event.setAccepted(). */ + #ifdef SDL_HINT_NO_SIGNAL_HANDLERS + SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); + #endif + /* Available since 2.0.6, uses dedicated OpenGL ES drivers if EGL is used, + and desktop GLES context otherwise. */ + #if defined(MAGNUM_TARGET_GLES) && defined(MAGNUM_TARGET_EGL) && defined(SDL_HINT_OPENGL_ES_DRIVER) + SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1"); + #endif + /* Available since 2.0.8, disables compositor bypass on X11, which causes + flickering on KWin as the compositor gets shut down on every startup */ + #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR + SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); + #endif + /* By default, SDL behaves like if it was playing a video or whatever, + preventing the computer from turning off the screen or going to sleep. + While it sorta makes sense for games, it's useless and annoying for + regular apps. Together with the compositor disabling those two are the + most stupid defaults. */ + #ifdef SDL_HINT_VIDEO_ALLOW_SCREENSAVER + SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1"); + #endif + /* Available since 2.0.12, use EGL if desired */ + #if defined(MAGNUM_TARGET_EGL) && defined(SDL_HINT_VIDEO_X11_FORCE_EGL) + SDL_SetHint(SDL_HINT_VIDEO_X11_FORCE_EGL, "1"); + #endif - /* HOWEVER, on Windows it gets the virtual DPI scaling, which we don't - want, so we need to call Windows APIs directly instead. Consistency my - ass. Related bug report that will probably never get actually - implemented: https://bugzilla.libsdl.org/show_bug.cgi?id=2473 */ - #elif defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT) - HDC hDC = GetWindowDC(nullptr); - Vector2i monitorSize{GetDeviceCaps(hDC, HORZSIZE), GetDeviceCaps(hDC, VERTSIZE)}; - SDL_DisplayMode mode; - CORRADE_INTERNAL_ASSERT(SDL_GetDesktopDisplayMode(0, &mode) == 0); - auto dpi = Vector2{Vector2i{mode.w, mode.h}*25.4f/Vector2{monitorSize}}; - const Vector2 dpiScaling{dpi/96.0f}; - Debug{verbose} << "Platform::Sdl2Application: physical DPI scaling" << dpiScaling; - return dpiScaling; + if(SDL_Init(SDL_INIT_VIDEO) < 0) { + Error() << "Cannot initialize SDL:" << SDL_GetError(); + std::exit(1); + } - /* Not implemented otherwise */ - #else - Debug{verbose} << "Platform::Sdl2Application: sorry, physical DPI scaling not implemented on this platform yet"; - return Vector2{1.0f}; + /* Save command-line arguments */ + if(args.value("log") == "verbose") _verboseLog = true; + const Containers::StringView dpiScaling = args.value("dpi-scaling"); + if(dpiScaling == "default"_s) + _commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Default; + #ifdef CORRADE_TARGET_APPLE + else if(dpiScaling == "framebuffer"_s) + _commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Framebuffer; #endif + #ifndef CORRADE_TARGET_APPLE + #if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_ANDROID) + else if(dpiScaling == "virtual"_s) + _commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Virtual; #endif -} - -void Sdl2Application::setWindowTitle(const Containers::StringView title) { - #ifndef CORRADE_TARGET_EMSCRIPTEN - SDL_SetWindowTitle(_window, - Containers::String::nullTerminatedGlobalView(title).data()); - #else - /* We don't have the _window because SDL_CreateWindow() doesn't exist in - the SDL1/2 hybrid. But it's not used anyway, so pass nullptr there. */ - SDL_SetWindowTitle(nullptr, - Containers::String::nullTerminatedGlobalView(title).data()); + else if(dpiScaling == "physical"_s) + _commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Physical; #endif + else if(dpiScaling.containsAny(" \t\n"_s)) + _commandLineDpiScaling = args.value("dpi-scaling"); + else + _commandLineDpiScaling = Vector2{args.value("dpi-scaling")}; } -#if !defined(CORRADE_TARGET_EMSCRIPTEN) && SDL_MAJOR_VERSION*1000 + SDL_MINOR_VERSION*100 + SDL_PATCHLEVEL >= 2005 -void Sdl2Application::setWindowIcon(const ImageView2D& image) { - Uint32 format; /** @todo handle sRGB differently? */ - switch(image.format()) { - case PixelFormat::RGB8Srgb: - case PixelFormat::RGB8Unorm: - format = SDL_PIXELFORMAT_RGB24; - break; - case PixelFormat::RGBA8Srgb: - case PixelFormat::RGBA8Unorm: - format = SDL_PIXELFORMAT_RGBA32; - break; - default: - CORRADE_ASSERT_UNREACHABLE("Platform::Sdl2Application::setWindowIcon(): unexpected format" << image.format(), ); - } - - /* Images are loaded with origin at bottom left, flip it to top left. SDL - only accepted a negative stride until version 2.23.1 and commit - https://github.com/libsdl-org/SDL/commit/535fdc3adcdc08a193ab0d45540014fd536cf251 - so we need to manually flip the image now */ - /** @todo take ImageFlag::YUp into account once it exists */ - Image2D flippedImage{PixelStorage{}.setAlignment(1), image.format(), image.size(), Containers::Array{NoInit, std::size_t(image.size().product()*image.pixelSize())}}; - const Containers::StridedArrayView3D flippedPixels = flippedImage.pixels(); - Utility::copy(image.pixels().flipped<0>(), flippedPixels); +void Sdl2Application::create() { + create(Configuration{}); +} - SDL_Surface* const icon = SDL_CreateRGBSurfaceWithFormatFrom(const_cast(flippedPixels.data()) , flippedImage.size().x(), flippedImage.size().y(), 32, flippedPixels.stride()[0], format); - CORRADE_INTERNAL_ASSERT(icon); +void Sdl2Application::create(const Configuration& configuration) { + if(!tryCreate(configuration)) std::exit(1); +} - SDL_SetWindowIcon(_window, icon); - SDL_FreeSurface(icon); +#ifdef MAGNUM_TARGET_GL +void Sdl2Application::create(const Configuration& configuration, const GLConfiguration& glConfiguration) { + if(!tryCreate(configuration, glConfiguration)) std::exit(1); } #endif @@ -735,66 +906,13 @@ bool Sdl2Application::tryCreate(const Configuration& configuration, const GLConf } #endif -Vector2i Sdl2Application::windowSize() const { - Vector2i size; - #ifndef CORRADE_TARGET_EMSCRIPTEN - CORRADE_ASSERT(_window, "Platform::Sdl2Application::windowSize(): no window opened", {}); - SDL_GetWindowSize(_window, &size.x(), &size.y()); - #else - CORRADE_ASSERT(_surface, "Platform::Sdl2Application::windowSize(): no window opened", {}); - emscripten_get_canvas_element_size("#canvas", &size.x(), &size.y()); - #endif - return size; -} - -#ifndef CORRADE_TARGET_EMSCRIPTEN -void Sdl2Application::setWindowSize(const Vector2i& size) { - CORRADE_ASSERT(_window, "Platform::Sdl2Application::setWindowSize(): no window opened", ); - - const Vector2i newSize = dpiScaling()*size; - SDL_SetWindowSize(_window, newSize.x(), newSize.y()); -} - -void Sdl2Application::setMinWindowSize(const Vector2i& size) { - CORRADE_ASSERT(_window, "Platform::Sdl2Application::setMinWindowSize(): no window opened", ); - - const Vector2i newSize = dpiScaling()*size; - SDL_SetWindowMinimumSize(_window, newSize.x(), newSize.y()); -} - -void Sdl2Application::setMaxWindowSize(const Vector2i& size) { - CORRADE_ASSERT(_window, "Platform::Sdl2Application::setMaxWindowSize(): no window opened", ); - - const Vector2i newSize = dpiScaling()*size; - SDL_SetWindowMaximumSize(_window, newSize.x(), newSize.y()); -} -#endif - -#ifdef MAGNUM_TARGET_GL -Vector2i Sdl2Application::framebufferSize() const { - Vector2i size; - #ifndef CORRADE_TARGET_EMSCRIPTEN - CORRADE_ASSERT(_window, "Platform::Sdl2Application::framebufferSize(): no window opened", {}); - SDL_GL_GetDrawableSize(_window, &size.x(), &size.y()); - #else - CORRADE_ASSERT(_surface, "Platform::Sdl2Application::framebufferSize(): no window opened", {}); - emscripten_get_canvas_element_size("#canvas", &size.x(), &size.y()); - #endif - return size; -} -#endif - -Vector2 Sdl2Application::dpiScaling() const { - return dpiScalingInternal(_configurationDpiScalingPolicy, _configurationDpiScaling); -} - #ifdef CORRADE_TARGET_EMSCRIPTEN void Sdl2Application::setContainerCssClass(const Containers::StringView cssClass) { magnumPlatformSetContainerCssClass(cssClass.data(), cssClass.size()); } #endif -void Sdl2Application::swapBuffers() { +void Sdl2ApplicationWindow::swapBuffers() { #ifndef CORRADE_TARGET_EMSCRIPTEN SDL_GL_SwapWindow(_window); #else @@ -827,8 +945,6 @@ bool Sdl2Application::setSwapInterval(const Int interval) { return true; } -void Sdl2Application::redraw() { _flags |= Flag::Redraw; } - Sdl2Application::~Sdl2Application() { /* SDL_DestroyWindow(_window) crashes on windows when _window is nullptr (it doesn't seem to crash on Linux). Because this seems to be yet @@ -852,9 +968,14 @@ Sdl2Application::~Sdl2Application() { SDL_FreeCursor(cursor); #endif - #ifndef CORRADE_TARGET_EMSCRIPTEN - if(_window) SDL_DestroyWindow(_window); - #endif + /* The window would be destroyed in the base ~Sdl2ApplicationWindow(), but + that's too late. Do it before calling SDL_Quit() and then reset the + window pointer so it's not called again after. */ + if(_window) { + SDL_DestroyWindow(_window); + _window = nullptr; + } + SDL_Quit(); } @@ -946,14 +1067,14 @@ bool Sdl2Application::mainLoopIteration() { dpiScaling()}; /** @todo handle also WM_DPICHANGED events when a window is moved between displays with different DPI */ viewportEvent(e); - _flags |= Flag::Redraw; + _windowFlags |= WindowFlag::Redraw; #endif } break; /* Direct everything that wasn't exposed via a callback to anyEvent(), so users can implement event handling for things not present in the Application APIs */ case SDL_WINDOWEVENT_EXPOSED: - _flags |= Flag::Redraw; + _windowFlags |= WindowFlag::Redraw; if(!(_flags & Flag::NoAnyEvent)) anyEvent(event); break; default: @@ -1027,8 +1148,8 @@ bool Sdl2Application::mainLoopIteration() { if(!(_flags & Flag::NoTickEvent)) tickEvent(); /* Draw event */ - if(_flags & Flag::Redraw) { - _flags &= ~Flag::Redraw; + if(_windowFlags & WindowFlag::Redraw) { + _windowFlags &= ~WindowFlag::Redraw; drawEvent(); #ifndef CORRADE_TARGET_EMSCRIPTEN @@ -1058,99 +1179,6 @@ bool Sdl2Application::mainLoopIteration() { return !(_flags & Flag::Exit); } -namespace { - -#ifndef CORRADE_TARGET_EMSCRIPTEN -constexpr SDL_SystemCursor CursorMap[] { - SDL_SYSTEM_CURSOR_ARROW, - SDL_SYSTEM_CURSOR_IBEAM, - SDL_SYSTEM_CURSOR_WAIT, - SDL_SYSTEM_CURSOR_CROSSHAIR, - SDL_SYSTEM_CURSOR_WAITARROW, - SDL_SYSTEM_CURSOR_SIZENWSE, - SDL_SYSTEM_CURSOR_SIZENESW, - SDL_SYSTEM_CURSOR_SIZEWE, - SDL_SYSTEM_CURSOR_SIZENS, - SDL_SYSTEM_CURSOR_SIZEALL, - SDL_SYSTEM_CURSOR_NO, - SDL_SYSTEM_CURSOR_HAND -}; -#else -constexpr Containers::StringView CursorMap[] { - "default"_s, - "text"_s, - "wait"_s, - "crosshair"_s, - "progress"_s, - "nwse-resize"_s, - "nesw-resize"_s, - "ew-resize"_s, - "ns-resize"_s, - "move"_s, - "not-allowed"_s, - "pointer"_s, - "none"_s - /* Hidden & locked not supported yet */ -}; -#endif - -} - -void Sdl2Application::setCursor(Cursor cursor) { - #ifndef CORRADE_TARGET_EMSCRIPTEN - CORRADE_ASSERT(_window, "Platform::Sdl2Application::setCursor(): no window opened", ); - - if(cursor == Cursor::Hidden) { - SDL_ShowCursor(SDL_DISABLE); - SDL_SetWindowGrab(_window, SDL_FALSE); - SDL_SetRelativeMouseMode(SDL_FALSE); - return; - } else if(cursor == Cursor::HiddenLocked) { - SDL_SetWindowGrab(_window, SDL_TRUE); - SDL_SetRelativeMouseMode(SDL_TRUE); - return; - } else { - SDL_ShowCursor(SDL_ENABLE); - SDL_SetWindowGrab(_window, SDL_FALSE); - SDL_SetRelativeMouseMode(SDL_FALSE); - } - - /* The second condition could be a static assert but it doesn't let me - because "this pointer only accessible in a constexpr function". Thanks - for nothing, C++. */ - CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(_cursors) && Containers::arraySize(_cursors) == Containers::arraySize(CursorMap)); - - if(!_cursors[UnsignedInt(cursor)]) - _cursors[UnsignedInt(cursor)] = SDL_CreateSystemCursor(CursorMap[UnsignedInt(cursor)]); - - SDL_SetCursor(_cursors[UnsignedInt(cursor)]); - #else - CORRADE_ASSERT(_surface, "Platform::Sdl2Application::setCursor(): no window opened", ); - _cursor = cursor; - CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(CursorMap)); - magnumPlatformSetCursor(CursorMap[UnsignedInt(cursor)].data(), - CursorMap[UnsignedInt(cursor)].size()); - #endif -} - -Sdl2Application::Cursor Sdl2Application::cursor() { - #ifndef CORRADE_TARGET_EMSCRIPTEN - if(SDL_GetRelativeMouseMode()) - return Cursor::HiddenLocked; - else if(!SDL_ShowCursor(SDL_QUERY)) - return Cursor::Hidden; - - SDL_Cursor* cursor = SDL_GetCursor(); - - if(cursor) for(UnsignedInt i = 0; i < sizeof(_cursors); i++) - if(_cursors[i] == cursor) return Cursor(i); - - return Cursor::Arrow; - #else - return _cursor; - #endif -} - #ifdef MAGNUM_BUILD_DEPRECATED void Sdl2Application::setMouseLocked(bool enabled) { /** @todo Implement this in Emscripten */ @@ -1207,34 +1235,7 @@ void Sdl2Application::anyEvent(SDL_Event&) { _flags |= Flag::NoAnyEvent; } -void Sdl2Application::viewportEvent(ViewportEvent&) {} -void Sdl2Application::keyPressEvent(KeyEvent&) {} -void Sdl2Application::keyReleaseEvent(KeyEvent&) {} -void Sdl2Application::mousePressEvent(MouseEvent&) {} -void Sdl2Application::mouseReleaseEvent(MouseEvent&) {} -void Sdl2Application::mouseMoveEvent(MouseMoveEvent&) {} -void Sdl2Application::mouseScrollEvent(MouseScrollEvent&) {} -void Sdl2Application::multiGestureEvent(MultiGestureEvent&) {} -void Sdl2Application::textInputEvent(TextInputEvent&) {} -void Sdl2Application::textEditingEvent(TextEditingEvent&) {} - -#ifdef MAGNUM_TARGET_GL -Sdl2Application::GLConfiguration::GLConfiguration(): - _colorBufferSize{8, 8, 8, 8}, _depthBufferSize{24}, _stencilBufferSize{0}, - _sampleCount(0) - #ifndef CORRADE_TARGET_EMSCRIPTEN - , _version{GL::Version::None}, _srgbCapable{false} - #endif -{ - #ifndef MAGNUM_TARGET_GLES - addFlags(Flag::ForwardCompatible); - #endif -} - -Sdl2Application::GLConfiguration::~GLConfiguration() = default; -#endif - -Sdl2Application::Configuration::Configuration(): +Sdl2ApplicationWindow::Configuration::Configuration(): #if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_IOS) _title(Containers::String::nullTerminatedGlobalView("Magnum SDL2 Application"_s)), #endif @@ -1245,38 +1246,54 @@ Sdl2Application::Configuration::Configuration(): #endif _dpiScalingPolicy{DpiScalingPolicy::Default} {} -Sdl2Application::Configuration::~Configuration() = default; +Sdl2ApplicationWindow::Configuration::~Configuration() = default; -Containers::StringView Sdl2Application::KeyEvent::keyName(const Key key) { +Containers::StringView Sdl2ApplicationWindow::KeyEvent::keyName(const Key key) { return SDL_GetKeyName(SDL_Keycode(key)); } -Containers::StringView Sdl2Application::KeyEvent::keyName() const { +Containers::StringView Sdl2ApplicationWindow::KeyEvent::keyName() const { return keyName(_key); } -Sdl2Application::InputEvent::Modifiers Sdl2Application::MouseEvent::modifiers() { +Sdl2ApplicationWindow::InputEvent::Modifiers Sdl2ApplicationWindow::MouseEvent::modifiers() { if(_modifiers) return *_modifiers; return *(_modifiers = fixedModifiers(Uint16(SDL_GetModState()))); } -Sdl2Application::InputEvent::Modifiers Sdl2Application::MouseMoveEvent::modifiers() { +Sdl2ApplicationWindow::InputEvent::Modifiers Sdl2ApplicationWindow::MouseMoveEvent::modifiers() { if(_modifiers) return *_modifiers; return *(_modifiers = fixedModifiers(Uint16(SDL_GetModState()))); } -Vector2i Sdl2Application::MouseScrollEvent::position() { +Vector2i Sdl2ApplicationWindow::MouseScrollEvent::position() { if(_position) return *_position; _position = Vector2i{}; SDL_GetMouseState(&_position->x(), &_position->y()); return *_position; } -Sdl2Application::InputEvent::Modifiers Sdl2Application::MouseScrollEvent::modifiers() { +Sdl2ApplicationWindow::InputEvent::Modifiers Sdl2ApplicationWindow::MouseScrollEvent::modifiers() { if(_modifiers) return *_modifiers; return *(_modifiers = fixedModifiers(Uint16(SDL_GetModState()))); } +#ifdef MAGNUM_TARGET_GL +Sdl2Application::GLConfiguration::GLConfiguration(): + _colorBufferSize{8, 8, 8, 8}, _depthBufferSize{24}, _stencilBufferSize{0}, + _sampleCount(0) + #ifndef CORRADE_TARGET_EMSCRIPTEN + , _version{GL::Version::None}, _srgbCapable{false} + #endif +{ + #ifndef MAGNUM_TARGET_GLES + addFlags(Flag::ForwardCompatible); + #endif +} + +Sdl2Application::GLConfiguration::~GLConfiguration() = default; +#endif + template class BasicScreen; template class BasicScreenedApplication; diff --git a/src/Magnum/Platform/Sdl2Application.h b/src/Magnum/Platform/Sdl2Application.h index fd4be4674..552af95e1 100644 --- a/src/Magnum/Platform/Sdl2Application.h +++ b/src/Magnum/Platform/Sdl2Application.h @@ -95,6 +95,430 @@ namespace Implementation { enum class Sdl2DpiScalingPolicy: UnsignedByte; } +class Sdl2Application; + +/** +@brief SDL2 application window +@m_since_latest + +@ref TODOTODO document + +See @ref Sdl2Application for more information. +*/ +class Sdl2ApplicationWindow { + public: + class Configuration; + class ViewportEvent; + class InputEvent; + class KeyEvent; + class MouseEvent; + class MouseMoveEvent; + class MouseScrollEvent; + class MultiGestureEvent; + class TextInputEvent; + class TextEditingEvent; + + /** @brief Copying is not allowed */ + Sdl2ApplicationWindow(const Sdl2ApplicationWindow&) = delete; + + /** @brief Moving is not allowed */ + Sdl2ApplicationWindow(Sdl2ApplicationWindow&&) = delete; + + /** @brief Copying is not allowed */ + Sdl2ApplicationWindow& operator=(const Sdl2ApplicationWindow&) = delete; + + /** @brief Moving is not allowed */ + Sdl2ApplicationWindow& operator=(Sdl2ApplicationWindow&&) = delete; + + /* Compared to the top-level application which is never deleted through + a pointer, standalone windows most likely will, so the destructor is + virtual */ + virtual ~Sdl2ApplicationWindow(); + + #ifndef CORRADE_TARGET_EMSCRIPTEN + /** + * @brief Underlying window handle + * + * Use in case you need to call SDL functionality directly. Returns + * @cpp nullptr @ce in case the window was not created yet. + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + */ + SDL_Window* window() { return _window; } + #endif + + /** @{ @name Window handling */ + + /** + * @brief Window size + * + * Window size to which all input event coordinates can be related. + * Note that, especially on HiDPI systems, it may be different from + * @ref framebufferSize(). Expects that a window is already created. + * See @ref Platform-Sdl2Application-dpi for more information. + * @see @ref dpiScaling() + */ + Vector2i windowSize() const; + + #if !defined(CORRADE_TARGET_EMSCRIPTEN) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * @brief Set window size + * @param size The size, in screen coordinates + * @m_since{2020,06} + * + * To make the sizing work independently of the display DPI, @p size is + * internally multiplied with @ref dpiScaling() before getting applied. + * Expects that a window is already created. + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + * @see @ref setMinWindowSize(), @ref setMaxWindowSize() + */ + void setWindowSize(const Vector2i& size); + + /** + * @brief Set minimum window size + * @param size The minimum size, in screen coordinates + * @m_since{2019,10} + * + * Note that, unlike in @ref GlfwApplication, SDL2 doesn't have a way + * to disable/remove a size limit. To make the sizing work + * independently of the display DPI, @p size is internally multiplied + * with @ref dpiScaling() before getting applied. Expects that a window + * is already created. + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + * @see @ref setMaxWindowSize(), @ref setWindowSize() + */ + void setMinWindowSize(const Vector2i& size); + + /** + * @brief Set maximal window size + * @param size The maximum size, in screen coordinates + * @m_since{2019,10} + * + * Note that, unlike in @ref GlfwApplication, SDL2 doesn't have a way + * to disable/remove a size limit. To make the sizing work + * independently of the display DPI, @p size is internally multiplied + * with @ref dpiScaling() before getting applied. Expects that a window + * is already created. + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + * @see @ref setMinWindowSize(), @ref setMaxWindowSize() + */ + void setMaxWindowSize(const Vector2i& size); + #endif + + #if defined(MAGNUM_TARGET_GL) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * @brief Framebuffer size + * + * Size of the default framebuffer. Note that, especially on HiDPI + * systems, it may be different from @ref windowSize(). Expects that a + * window is already created. See @ref Platform-Sdl2Application-dpi for + * more information. + * + * @note This function is available only if Magnum is compiled with + * @ref MAGNUM_TARGET_GL enabled (done by default). See + * @ref building-features for more information. + * + * @see @ref Sdl2Application::framebufferSize(), @ref dpiScaling() + */ + Vector2i framebufferSize() const; + #endif + + /** + * @brief DPI scaling + * + * How the content should be scaled relative to system defaults for + * given @ref windowSize(). If a window is not created yet, returns + * zero vector, use @ref dpiScaling(const Configuration&) for + * calculating a value independently. See @ref Platform-Sdl2Application-dpi + * for more information. + * @see @ref framebufferSize() + */ + Vector2 dpiScaling() const; + + /** + * @brief DPI scaling for given configuration + * + * Calculates DPI scaling that would be used when creating a window + * with given @p configuration. Takes into account DPI scaling policy + * and custom scaling specified on the command-line. See + * @ref Platform-Sdl2Application-dpi for more information. + */ + Vector2 dpiScaling(const Configuration& configuration); + + /** + * @brief Set window title + * @m_since{2019,10} + * + * The @p title is expected to be encoded in UTF-8. + */ + void setWindowTitle(Containers::StringView title); + + #if !defined(CORRADE_TARGET_EMSCRIPTEN) && (SDL_MAJOR_VERSION*1000 + SDL_MINOR_VERSION*100 + SDL_PATCHLEVEL >= 2005 || defined(DOXYGEN_GENERATING_OUTPUT)) + /** + * @brief Set window icon + * @m_since{2020,06} + * + * The @p image is expected to be with origin at bottom left (which is + * the default for imported images) and in one of + * @ref PixelFormat::RGB8Unorm, @ref PixelFormat::RGB8Srgb, + * @ref PixelFormat::RGBA8Unorm or @ref PixelFormat::RGBA8Srgb formats. + * Unlike @ref GlfwApplication::setWindowIcon(), SDL doesn't provide a + * way to supply multiple images in different sizes. + * @note Available since SDL 2.0.5. Not available on + * @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten", use + * @cb{.html} @ce in your HTML markup instead. + * Although it's not documented in SDL itself, the function might + * have no effect on macOS / Wayland, similarly to how + * @ref GlfwApplication::setWindowIcon() behaves on those + * platforms. + * @see @ref platform-windows-icon "Excecutable icon on Windows", + * @ref Trade::IcoImporter "IcoImporter" + */ + void setWindowIcon(const ImageView2D& image); + #endif + + /** + * @brief Swap buffers + * + * Paints currently rendered framebuffer on screen. + * @see @ref Sdl2Application::setSwapInterval() + */ + void swapBuffers(); + + /** + * @brief Redraw immediately + * + * Marks the window for redrawing, resulting in call to @ref drawEvent() + * in the next iteration. You can call it from @ref drawEvent() itself + * to redraw immediately without waiting for user input. + */ + void redraw(); + + private: + /** + * @brief Viewport event + * + * Called when window size changes. The default implementation does + * nothing. If you want to respond to size changes, you should pass the + * new *framebuffer* size to @ref GL::DefaultFramebuffer::setViewport() + * (if using OpenGL) and possibly elsewhere (to + * @ref SceneGraph::Camera::setViewport(), other framebuffers...) and + * the new *window* size and DPI scaling to APIs that respond to user + * events or scale UI elements. + * + * Note that this function might not get called at all if the window + * size doesn't change. You should configure the initial state of your + * cameras, framebuffers etc. in application constructor rather than + * relying on this function to be called. Size of the window can be + * retrieved using @ref windowSize(), size of the backing framebuffer + * via @ref framebufferSize() and DPI scaling using @ref dpiScaling(). + * See @ref Platform-Sdl2Application-dpi for detailed info about these + * values. + */ + virtual void viewportEvent(ViewportEvent& event); + + /** + * @brief Draw event + * + * Called when the screen is redrawn. You should clean the framebuffer + * using @ref GL::DefaultFramebuffer::clear() (if using OpenGL) and + * then add your own drawing functions. After drawing is finished, call + * @ref swapBuffers(). If you want to draw immediately again, call also + * @ref redraw(). + */ + virtual void drawEvent() = 0; + + /* Since 1.8.17, the original short-hand group closing doesn't work + anymore. FFS. */ + /** + * @} + */ + + /** @{ @name Keyboard handling */ + + /** + * @brief Key press event + * + * Called when an key is pressed. Default implementation does nothing. + */ + virtual void keyPressEvent(KeyEvent& event); + + /** + * @brief Key release event + * + * Called when an key is released. Default implementation does nothing. + */ + virtual void keyReleaseEvent(KeyEvent& event); + + /* Since 1.8.17, the original short-hand group closing doesn't work + anymore. FFS. */ + /** + * @} + */ + + /** @{ @name Mouse handling */ + + public: + /** + * @brief Cursor type + * @m_since{2020,06} + * + * @see @ref setCursor() + */ + enum class Cursor: UnsignedInt { + Arrow, /**< Arrow */ + TextInput, /**< Text input */ + Wait, /**< Wait */ + Crosshair, /**< Crosshair */ + WaitArrow, /**< Small wait cursor */ + ResizeNWSE, /**< Double arrow pointing northwest and southeast */ + ResizeNESW, /**< Double arrow pointing northeast and southwest */ + ResizeWE, /**< Double arrow pointing west and east */ + ResizeNS, /**< Double arrow pointing north and south */ + ResizeAll, /**< Four pointed arrow pointing north, south, east, and west */ + No, /**< Slashed circle or crossbones */ + Hand, /**< Hand */ + Hidden, /**< Hidden */ + + #ifndef CORRADE_TARGET_EMSCRIPTEN + /** + * Hidden and locked. When the mouse is locked, only + * @ref MouseMoveEvent::relativePosition() is changing, absolute + * position stays the same. + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + */ + HiddenLocked + #endif + }; + + /** + * @brief Set cursor type + * @m_since{2020,06} + * + * Expects that a window is already created. Default is + * @ref Cursor::Arrow. + * @ref TODOTODO uhh clean up the docs to say "that the window is", not "a" + */ + void setCursor(Cursor cursor); + + /** + * @brief Get current cursor type + * @m_since{2020,06} + */ + Cursor cursor(); + + #ifndef CORRADE_TARGET_EMSCRIPTEN + /** + * @brief Warp mouse cursor to given coordinates + * + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + */ + void warpCursor(const Vector2i& position) { + SDL_WarpMouseInWindow(_window, position.x(), position.y()); + } + #endif + + private: + /** + * @brief Mouse press event + * + * Called when mouse button is pressed. Default implementation does + * nothing. + */ + virtual void mousePressEvent(MouseEvent& event); + + /** + * @brief Mouse release event + * + * Called when mouse button is released. Default implementation does + * nothing. + */ + virtual void mouseReleaseEvent(MouseEvent& event); + + /** + * @brief Mouse move event + * + * Called when mouse is moved. Default implementation does nothing. + */ + virtual void mouseMoveEvent(MouseMoveEvent& event); + + /** + * @brief Mouse scroll event + * + * Called when a scrolling device is used (mouse wheel or scrolling + * area on a touchpad). Default implementation does nothing. + */ + virtual void mouseScrollEvent(MouseScrollEvent& event); + + /* Since 1.8.17, the original short-hand group closing doesn't work + anymore. FFS. */ + /** + * @} + */ + + /** @{ @name Touch gesture handling */ + + /** + * @brief Multi gesture event + * + * Called when the user performs a gesture using multiple fingers. + * Default implementation does nothing. + * @experimental + */ + virtual void multiGestureEvent(MultiGestureEvent& event); + + /* Since 1.8.17, the original short-hand group closing doesn't work + anymore. FFS. */ + /** + * @} + */ + + /** @{ @name Text input handling */ + + /** + * @brief Text input event + * + * Called when text input is active and the text is being input. + * @see @ref Sdl2Application::isTextInputActive() + */ + virtual void textInputEvent(TextInputEvent& event); + + /** + * @brief Text editing event + * + * Called when text input is active and the text is being edited. + */ + virtual void textEditingEvent(TextEditingEvent& event); + + /* Since 1.8.17, the original short-hand group closing doesn't work + anymore. FFS. */ + /** + * @} + */ + + private: + friend Sdl2Application; + + enum class WindowFlag: UnsignedByte; + typedef Containers::EnumSet WindowFlags; + CORRADE_ENUMSET_FRIEND_OPERATORS(WindowFlags) + + /* Used by Sdl2Application(NoCreateT) */ + explicit Sdl2ApplicationWindow(Sdl2Application& application, NoCreateT); + + Vector2 dpiScalingInternal(Implementation::Sdl2DpiScalingPolicy configurationDpiScalingPolicy, const Vector2& configurationDpiScaling) const; + + Sdl2Application& _application; + + #ifndef CORRADE_TARGET_EMSCRIPTEN + SDL_Window* _window{}; + #else + SDL_Surface* _surface{}; + Vector2i _lastKnownCanvasSize; + #endif + + WindowFlags _windowFlags; +}; + /** @nosubgrouping @brief SDL2 application @@ -339,8 +763,9 @@ the compositor in system-wide KWin settings. @subsection Platform-Sdl2Application-usage-ios iOS specifics -Leaving a default (zero) window size in @ref Configuration will cause the app -to autodetect it based on the actual device screen size. This also depends on +Leaving a default (zero) window size in +@relativeref{Sdl2ApplicationWindow,Configuration} will cause the app to +autodetect it based on the actual device screen size. This also depends on @ref Platform-Sdl2Application-dpi "DPI awareness", see below for details. As noted in the @ref platforms-ios-bundle "iOS platform guide", a lot of @@ -348,20 +773,22 @@ options needs to be set via a `*.plist` file. Some options can be configured from runtime when creating the SDL2 application window, see documentation of a particular value for details: -- @ref Configuration::WindowFlag::Borderless hides the menu bar -- @ref Configuration::WindowFlag::Resizable makes the application respond to - device orientation changes +- @relativeref{Sdl2ApplicationWindow,Configuration::WindowFlag::Borderless} + hides the menu bar +- @relativeref{Sdl2ApplicationWindow,Configuration::WindowFlag::Resizable} + makes the application respond to device orientation changes @subsection Platform-Sdl2Application-usage-emscripten Emscripten specifics -Leaving a default (zero) window size in @ref Configuration will cause the app -to use a window size that corresponds to *CSS pixel size* of the -@cb{.html} @ce element. The size is then multiplied by DPI scaling +Leaving a default (zero) window size in @relativeref{Sdl2ApplicationWindow,Configuration} +will cause the app to use a window size that corresponds to *CSS pixel size* of +the @cb{.html} @ce element. The size is then multiplied by DPI scaling value, see @ref Platform-Sdl2Application-dpi "DPI awareness" below for details. -If you enable @ref Configuration::WindowFlag::Resizable, the canvas will be -resized when size of the canvas changes and you get @ref viewportEvent(). If -the flag is not enabled, no canvas resizing is performed. +If you enable @relativeref{Sdl2ApplicationWindow,Configuration::WindowFlag::Resizable}, +the canvas will be resized when size of the canvas changes and you get +@ref viewportEvent(). If the flag is not enabled, no canvas resizing is +performed. @note While this implementation supports Esmcripten and is going to continue supporting it for the foreseeable future, @ref EmscriptenApplication is now @@ -395,8 +822,8 @@ variable). However, the window backing framebuffer has a different size. This is only supported on macOS and iOS. See @ref platforms-macos-hidpi for details how to enable it. Equivalent to passing - @ref Configuration::DpiScalingPolicy::Framebuffer to - @ref Configuration::setSize() or `framebuffer` via command line / + @relativeref{Sdl2ApplicationWindow,Configuration::DpiScalingPolicy::Framebuffer} + to @ref Configuration::setSize() or `framebuffer` via command line / environment. - Virtual DPI scaling. Scales the window based on DPI scaling setting in the system. For example if a 800x600 window is requested and DPI scaling is set @@ -405,8 +832,8 @@ variable). Windows; on Windows the application is first checked for DPI awareness as described in @ref platforms-windows-hidpi and if the application is not DPI-aware, 1:1 scaling is used. Equivalent to passing - @ref Configuration::DpiScalingPolicy::Virtual to - @ref Configuration::setSize() or `virtual` on command line. + @relativeref{Sdl2ApplicationWindow,Configuration::DpiScalingPolicy::Virtual} + to @ref Configuration::setSize() or `virtual` on command line. - Physical DPI scaling. Takes the requested window size as a physical size that a window would have on platform's default DPI and scales it to have the same physical size on given display physical DPI. So, for example on a @@ -418,8 +845,9 @@ variable). This is supported on Linux and all mobile platforms (except iOS) and Emscripten. On Windows this is equivalent to virtual DPI scaling but without doing an explicit check for DPI awareness first. Equivalent to - passing @ref Configuration::DpiScalingPolicy::Physical to - @ref Configuration::setSize() or `physical` via command line / environment. + passing @relativeref{Sdl2ApplicationWindow,Configuration::DpiScalingPolicy::Physical} + to @ref Configuration::setSize() or `physical` via command line / + environment. Besides the above, it's possible to supply a custom DPI scaling value to @ref Configuration::setSize() or the `--magnum-dpi-scaling` command-line @@ -433,24 +861,25 @@ affect sharpness of the contents. The default is depending on the platform: - On macOS and iOS, the default and only supported option is - @ref Configuration::DpiScalingPolicy::Framebuffer. On this platform, - @ref windowSize() and @ref framebufferSize() will differ depending on - whether `NSHighResolutionCapable` is enabled in the `*.plist` file or not. - By default, @ref dpiScaling() is @cpp 1.0f @ce in both dimensions but it - can be overridden using custom DPI scaling. -- On Windows, the default is @ref Configuration::DpiScalingPolicy::Framebuffer. + @relativeref{Sdl2ApplicationWindow,Configuration::DpiScalingPolicy::Framebuffer}. + On this platform, @ref windowSize() and @ref framebufferSize() will differ + depending on whether `NSHighResolutionCapable` is enabled in the `*.plist` + file or not. By default, @ref dpiScaling() is @cpp 1.0f @ce in both + dimensions but it can be overridden using custom DPI scaling. +- On Windows, the default is @relativeref{Sdl2ApplicationWindow,Configuration::DpiScalingPolicy::Framebuffer}. The @ref windowSize() and @ref framebufferSize() is always the same. Depending on whether the DPI awareness was enabled in the manifest file or set by the `SetProcessDpiAwareness()` API, @ref dpiScaling() is either @cpp 1.0f @ce in both dimensions, indicating a low-DPI screen or a non-DPI-aware app, or some other value for HiDPI screens. In both cases the value can be overridden using custom DPI scaling. -- On Linux, the default is @ref Configuration::DpiScalingPolicy::Virtual, +- On Linux, the default is @relativeref{Sdl2ApplicationWindow,Configuration::DpiScalingPolicy::Virtual}, taken from the `Xft.dpi` property. If the property is not available, it - falls back to @ref Configuration::DpiScalingPolicy::Physical, querying the - monitor DPI value. The @ref windowSize() and @ref framebufferSize() is - always the same, @ref dpiScaling() contains the queried DPI scaling value. - The value can be overridden using custom DPI scaling. + falls back to @relativeref{Sdl2ApplicationWindow,Configuration::DpiScalingPolicy::Physical}, + querying the monitor DPI value. The @ref windowSize() and + @ref framebufferSize() is always the same, @ref dpiScaling() contains the + queried DPI scaling value. The value can be overridden using custom DPI + scaling. - On @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten", the default is physical DPI scaling, taken from [Window.getDevicePixelRatio()](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio). The @ref windowSize() and @ref framebufferSize() is always the same, @@ -480,7 +909,7 @@ If your application is saving and restoring window size, it's advisable to take properly handle cases where the window is opened on a display with different DPI. */ -class Sdl2Application { +class Sdl2Application: public Sdl2ApplicationWindow { public: /** @brief Application arguments */ struct Arguments { @@ -491,20 +920,10 @@ class Sdl2Application { char** argv; /**< @brief Argument values */ }; - class Configuration; #ifdef MAGNUM_TARGET_GL class GLConfiguration; #endif class ExitEvent; - class ViewportEvent; - class InputEvent; - class KeyEvent; - class MouseEvent; - class MouseMoveEvent; - class MouseScrollEvent; - class MultiGestureEvent; - class TextInputEvent; - class TextEditingEvent; #ifdef MAGNUM_TARGET_GL /** @@ -514,9 +933,9 @@ class Sdl2Application { * @param glConfiguration OpenGL context configuration * * Creates application with default or user-specified configuration. - * See @ref Configuration for more information. The program exits if - * the context cannot be created, see @ref tryCreate() for an - * alternative. + * See @relativeref{Sdl2ApplicationWindow,Configuration} for more + * information. The program exits if the context cannot be created, see + * @ref tryCreate() for an alternative. * * @note This function is available only if Magnum is compiled with * @ref MAGNUM_TARGET_GL enabled (done by default). See @@ -528,9 +947,10 @@ class Sdl2Application { /** * @brief Construct without explicit GPU context configuration * - * If @ref Configuration::WindowFlag::Contextless is present or Magnum - * was not built with @ref MAGNUM_TARGET_GL, this creates a window - * without any GPU context attached, leaving that part on the user. + * If @relativeref{Sdl2ApplicationWindow,Configuration::WindowFlag::Contextless} + * is present or Magnum was not built with @ref MAGNUM_TARGET_GL, this + * creates a window without any GPU context attached, leaving that part + * on the user. * * If none of the flags is present and Magnum was built with * @ref MAGNUM_TARGET_GL, this is equivalent to calling @@ -615,17 +1035,6 @@ class Sdl2Application { */ void exit(int exitCode = 0); - #ifndef CORRADE_TARGET_EMSCRIPTEN - /** - * @brief Underlying window handle - * - * Use in case you need to call SDL functionality directly. Returns - * @cpp nullptr @ce in case the window was not created yet. - * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". - */ - SDL_Window* window() { return _window; } - #endif - #if defined(MAGNUM_TARGET_GL) && !defined(CORRADE_TARGET_EMSCRIPTEN) /** * @brief Underlying OpenGL context @@ -672,181 +1081,54 @@ class Sdl2Application { /** * @brief Create a window with given configuration * - * If @ref Configuration::WindowFlag::Contextless is present or Magnum - * was not built with @ref MAGNUM_TARGET_GL, this creates a window - * without any GPU context attached, leaving that part on the user. + * If @relativeref{Sdl2ApplicationWindow,Configuration::WindowFlag::Contextless} + * is present or Magnum was not built with @ref MAGNUM_TARGET_GL, this + * creates a window without any GPU context attached, leaving that part + * on the user. * * If none of the flags is present and Magnum was built with * @ref MAGNUM_TARGET_GL, this is equivalent to calling * @ref create(const Configuration&, const GLConfiguration&) with * default-constructed @ref GLConfiguration. * - * See also @ref building-features for more information. - */ - void create(const Configuration& configuration); - - /** - * @brief Create a window with default configuration and OpenGL context - * - * Equivalent to calling @ref create(const Configuration&) with - * default-constructed @ref Configuration. - */ - void create(); - - #ifdef MAGNUM_TARGET_GL - /** - * @brief Try to create context with given configuration for OpenGL context - * - * Unlike @ref create(const Configuration&, const GLConfiguration&) - * returns @cpp false @ce if the context cannot be created, - * @cpp true @ce otherwise. - * - * @note This function is available only if Magnum is compiled with - * @ref MAGNUM_TARGET_GL enabled (done by default). See - * @ref building-features for more information. - */ - bool tryCreate(const Configuration& configuration, const GLConfiguration& glConfiguration); - #endif - - /** - * @brief Try to create context with given configuration - * - * Unlike @ref create(const Configuration&) returns @cpp false @ce if - * the context cannot be created, @cpp true @ce otherwise. - */ - bool tryCreate(const Configuration& configuration); - - /** @{ @name Screen handling */ - - public: - /** - * @brief Window size - * - * Window size to which all input event coordinates can be related. - * Note that, especially on HiDPI systems, it may be different from - * @ref framebufferSize(). Expects that a window is already created. - * See @ref Platform-Sdl2Application-dpi for more information. - * @see @ref dpiScaling() - */ - Vector2i windowSize() const; - - #if !defined(CORRADE_TARGET_EMSCRIPTEN) || defined(DOXYGEN_GENERATING_OUTPUT) - /** - * @brief Set window size - * @param size The size, in screen coordinates - * @m_since{2020,06} - * - * To make the sizing work independently of the display DPI, @p size is - * internally multiplied with @ref dpiScaling() before getting applied. - * Expects that a window is already created. - * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". - * @see @ref setMinWindowSize(), @ref setMaxWindowSize() - */ - void setWindowSize(const Vector2i& size); - - /** - * @brief Set minimum window size - * @param size The minimum size, in screen coordinates - * @m_since{2019,10} - * - * Note that, unlike in @ref GlfwApplication, SDL2 doesn't have a way - * to disable/remove a size limit. To make the sizing work - * independently of the display DPI, @p size is internally multiplied - * with @ref dpiScaling() before getting applied. Expects that a window - * is already created. - * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". - * @see @ref setMaxWindowSize(), @ref setWindowSize() - */ - void setMinWindowSize(const Vector2i& size); - - /** - * @brief Set maximal window size - * @param size The maximum size, in screen coordinates - * @m_since{2019,10} - * - * Note that, unlike in @ref GlfwApplication, SDL2 doesn't have a way - * to disable/remove a size limit. To make the sizing work - * independently of the display DPI, @p size is internally multiplied - * with @ref dpiScaling() before getting applied. Expects that a window - * is already created. - * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". - * @see @ref setMinWindowSize(), @ref setMaxWindowSize() - */ - void setMaxWindowSize(const Vector2i& size); - #endif - - #if defined(MAGNUM_TARGET_GL) || defined(DOXYGEN_GENERATING_OUTPUT) - /** - * @brief Framebuffer size - * - * Size of the default framebuffer. Note that, especially on HiDPI - * systems, it may be different from @ref windowSize(). Expects that a - * window is already created. See @ref Platform-Sdl2Application-dpi for - * more information. - * - * @note This function is available only if Magnum is compiled with - * @ref MAGNUM_TARGET_GL enabled (done by default). See - * @ref building-features for more information. - * - * @see @ref Sdl2Application::framebufferSize(), @ref dpiScaling() - */ - Vector2i framebufferSize() const; - #endif - - /** - * @brief DPI scaling - * - * How the content should be scaled relative to system defaults for - * given @ref windowSize(). If a window is not created yet, returns - * zero vector, use @ref dpiScaling(const Configuration&) for - * calculating a value independently. See @ref Platform-Sdl2Application-dpi - * for more information. - * @see @ref framebufferSize() - */ - Vector2 dpiScaling() const; - - /** - * @brief DPI scaling for given configuration - * - * Calculates DPI scaling that would be used when creating a window - * with given @p configuration. Takes into account DPI scaling policy - * and custom scaling specified on the command-line. See - * @ref Platform-Sdl2Application-dpi for more information. + * See also @ref building-features for more information. */ - Vector2 dpiScaling(const Configuration& configuration); + void create(const Configuration& configuration); /** - * @brief Set window title - * @m_since{2019,10} + * @brief Create a window with default configuration and OpenGL context * - * The @p title is expected to be encoded in UTF-8. + * Equivalent to calling @ref create(const Configuration&) with + * default-constructed @relativeref{Sdl2ApplicationWindow,Configuration}. */ - void setWindowTitle(Containers::StringView title); + void create(); - #if !defined(CORRADE_TARGET_EMSCRIPTEN) && (SDL_MAJOR_VERSION*1000 + SDL_MINOR_VERSION*100 + SDL_PATCHLEVEL >= 2005 || defined(DOXYGEN_GENERATING_OUTPUT)) + #ifdef MAGNUM_TARGET_GL /** - * @brief Set window icon - * @m_since{2020,06} + * @brief Try to create context with given configuration for OpenGL context * - * The @p image is expected to be with origin at bottom left (which is - * the default for imported images) and in one of - * @ref PixelFormat::RGB8Unorm, @ref PixelFormat::RGB8Srgb, - * @ref PixelFormat::RGBA8Unorm or @ref PixelFormat::RGBA8Srgb formats. - * Unlike @ref GlfwApplication::setWindowIcon(), SDL doesn't provide a - * way to supply multiple images in different sizes. - * @note Available since SDL 2.0.5. Not available on - * @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten", use - * @cb{.html} @ce in your HTML markup instead. - * Although it's not documented in SDL itself, the function might - * have no effect on macOS / Wayland, similarly to how - * @ref GlfwApplication::setWindowIcon() behaves on those - * platforms. - * @see @ref platform-windows-icon "Excecutable icon on Windows", - * @ref Trade::IcoImporter "IcoImporter" + * Unlike @ref create(const Configuration&, const GLConfiguration&) + * returns @cpp false @ce if the context cannot be created, + * @cpp true @ce otherwise. + * + * @note This function is available only if Magnum is compiled with + * @ref MAGNUM_TARGET_GL enabled (done by default). See + * @ref building-features for more information. */ - void setWindowIcon(const ImageView2D& image); + bool tryCreate(const Configuration& configuration, const GLConfiguration& glConfiguration); #endif + /** + * @brief Try to create context with given configuration + * + * Unlike @ref create(const Configuration&) returns @cpp false @ce if + * the context cannot be created, @cpp true @ce otherwise. + */ + bool tryCreate(const Configuration& configuration); + + /** @{ @name Screen handling */ + + public: #if defined(CORRADE_TARGET_EMSCRIPTEN) || defined(DOXYGEN_GENERATING_OUTPUT) /** * @brief Set container CSS class @@ -872,14 +1154,6 @@ class Sdl2Application { void setContainerCssClass(Containers::StringView cssClass); #endif - /** - * @brief Swap buffers - * - * Paints currently rendered framebuffer on screen. - * @see @ref setSwapInterval() - */ - void swapBuffers(); - /** @brief Swap interval */ Int swapInterval() const; @@ -912,71 +1186,6 @@ class Sdl2Application { } #endif - /** - * @brief Redraw immediately - * - * Marks the window for redrawing, resulting in call to @ref drawEvent() - * in the next iteration. You can call it from @ref drawEvent() itself - * to redraw immediately without waiting for user input. - */ - void redraw(); - - private: - /** - * @brief Viewport event - * - * Called when window size changes. The default implementation does - * nothing. If you want to respond to size changes, you should pass the - * new *framebuffer* size to @ref GL::DefaultFramebuffer::setViewport() - * (if using OpenGL) and possibly elsewhere (to - * @ref SceneGraph::Camera::setViewport(), other framebuffers...) and - * the new *window* size and DPI scaling to APIs that respond to user - * events or scale UI elements. - * - * Note that this function might not get called at all if the window - * size doesn't change. You should configure the initial state of your - * cameras, framebuffers etc. in application constructor rather than - * relying on this function to be called. Size of the window can be - * retrieved using @ref windowSize(), size of the backing framebuffer - * via @ref framebufferSize() and DPI scaling using @ref dpiScaling(). - * See @ref Platform-Sdl2Application-dpi for detailed info about these - * values. - */ - virtual void viewportEvent(ViewportEvent& event); - - /** - * @brief Draw event - * - * Called when the screen is redrawn. You should clean the framebuffer - * using @ref GL::DefaultFramebuffer::clear() (if using OpenGL) and - * then add your own drawing functions. After drawing is finished, call - * @ref swapBuffers(). If you want to draw immediately again, call also - * @ref redraw(). - */ - virtual void drawEvent() = 0; - - /* Since 1.8.17, the original short-hand group closing doesn't work - anymore. FFS. */ - /** - * @} - */ - - /** @{ @name Keyboard handling */ - - /** - * @brief Key press event - * - * Called when an key is pressed. Default implementation does nothing. - */ - virtual void keyPressEvent(KeyEvent& event); - - /** - * @brief Key release event - * - * Called when an key is released. Default implementation does nothing. - */ - virtual void keyReleaseEvent(KeyEvent& event); - /* Since 1.8.17, the original short-hand group closing doesn't work anymore. FFS. */ /** @@ -985,65 +1194,6 @@ class Sdl2Application { /** @{ @name Mouse handling */ - public: - /** - * @brief Cursor type - * @m_since{2020,06} - * - * @see @ref setCursor() - */ - enum class Cursor: UnsignedInt { - Arrow, /**< Arrow */ - TextInput, /**< Text input */ - Wait, /**< Wait */ - Crosshair, /**< Crosshair */ - WaitArrow, /**< Small wait cursor */ - ResizeNWSE, /**< Double arrow pointing northwest and southeast */ - ResizeNESW, /**< Double arrow pointing northeast and southwest */ - ResizeWE, /**< Double arrow pointing west and east */ - ResizeNS, /**< Double arrow pointing north and south */ - ResizeAll, /**< Four pointed arrow pointing north, south, east, and west */ - No, /**< Slashed circle or crossbones */ - Hand, /**< Hand */ - Hidden, /**< Hidden */ - - #ifndef CORRADE_TARGET_EMSCRIPTEN - /** - * Hidden and locked. When the mouse is locked, only - * @ref MouseMoveEvent::relativePosition() is changing, absolute - * position stays the same. - * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". - */ - HiddenLocked - #endif - }; - - /** - * @brief Set cursor type - * @m_since{2020,06} - * - * Expects that a window is already created. Default is - * @ref Cursor::Arrow. - */ - void setCursor(Cursor cursor); - - /** - * @brief Get current cursor type - * @m_since{2020,06} - */ - Cursor cursor(); - - #ifndef CORRADE_TARGET_EMSCRIPTEN - /** - * @brief Warp mouse cursor to given coordinates - * - * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". - */ - void warpCursor(const Vector2i& position) { - SDL_WarpMouseInWindow(_window, position.x(), position.y()); - } - #endif - #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Whether mouse is locked @@ -1062,55 +1212,6 @@ class Sdl2Application { CORRADE_DEPRECATED("use setCursor() together with Cursor::HiddenLocked instead") void setMouseLocked(bool enabled); #endif - private: - /** - * @brief Mouse press event - * - * Called when mouse button is pressed. Default implementation does - * nothing. - */ - virtual void mousePressEvent(MouseEvent& event); - - /** - * @brief Mouse release event - * - * Called when mouse button is released. Default implementation does - * nothing. - */ - virtual void mouseReleaseEvent(MouseEvent& event); - - /** - * @brief Mouse move event - * - * Called when mouse is moved. Default implementation does nothing. - */ - virtual void mouseMoveEvent(MouseMoveEvent& event); - - /** - * @brief Mouse scroll event - * - * Called when a scrolling device is used (mouse wheel or scrolling - * area on a touchpad). Default implementation does nothing. - */ - virtual void mouseScrollEvent(MouseScrollEvent& event); - - /* Since 1.8.17, the original short-hand group closing doesn't work - anymore. FFS. */ - /** - * @} - */ - - /** @{ @name Touch gesture handling */ - - /** - * @brief Multi gesture event - * - * Called when the user performs a gesture using multiple fingers. - * Default implementation does nothing. - * @experimental - */ - virtual void multiGestureEvent(MultiGestureEvent& event); - /* Since 1.8.17, the original short-hand group closing doesn't work anymore. FFS. */ /** @@ -1118,7 +1219,7 @@ class Sdl2Application { */ /** @{ @name Text input handling */ - public: + /** * @brief Whether text input is active * @@ -1159,22 +1260,6 @@ class Sdl2Application { */ void setTextInputRect(const Range2Di& rect); - private: - /** - * @brief Text input event - * - * Called when text input is active and the text is being input. - * @see @ref isTextInputActive() - */ - virtual void textInputEvent(TextInputEvent& event); - - /** - * @brief Text editing event - * - * Called when text input is active and the text is being edited. - */ - virtual void textEditingEvent(TextEditingEvent& event); - /* Since 1.8.17, the original short-hand group closing doesn't work anymore. FFS. */ /** @@ -1183,6 +1268,7 @@ class Sdl2Application { /** @{ @name Special events */ + private: /** * @brief Exit event * @@ -1234,12 +1320,12 @@ class Sdl2Application { */ private: + friend Sdl2ApplicationWindow; + enum class Flag: UnsignedByte; typedef Containers::EnumSet Flags; CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) - Vector2 dpiScalingInternal(Implementation::Sdl2DpiScalingPolicy configurationDpiScalingPolicy, const Vector2& configurationDpiScaling) const; - #ifndef CORRADE_TARGET_EMSCRIPTEN SDL_Cursor* _cursors[12]{}; #else @@ -1253,11 +1339,7 @@ class Sdl2Application { Vector2 _commandLineDpiScaling, _configurationDpiScaling; #ifndef CORRADE_TARGET_EMSCRIPTEN - SDL_Window* _window{}; UnsignedInt _minimalLoopPeriod; - #else - SDL_Surface* _surface{}; - Vector2i _lastKnownCanvasSize; #endif #ifdef MAGNUM_TARGET_GL @@ -1285,7 +1367,7 @@ The created window is always with a double-buffered OpenGL context. @ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features for more information. -@see @ref Sdl2Application(), @ref create(), @ref tryCreate() +@see @ref Sdl2Application(const Arguments&, const Configuration&, const GLConfiguration&), @ref create(), @ref tryCreate() */ class Sdl2Application::GLConfiguration: public GL::Context::Configuration { public: @@ -1587,10 +1669,12 @@ namespace Implementation { /** @brief Configuration -@see @ref Sdl2Application(), @ref GLConfiguration, @ref create(), - @ref tryCreate() +@see @ref Sdl2ApplicationWindow(), + @ref Sdl2Application::Sdl2Application(const Arguments&, const Configuration&, const GLConfiguration&), + @ref Sdl2Application::GLConfiguration, @ref Sdl2Application::create(), + @ref Sdl2Application::tryCreate() */ -class Sdl2Application::Configuration { +class Sdl2ApplicationWindow::Configuration { public: /** * @brief Window flag @@ -1723,13 +1807,13 @@ class Sdl2Application::Configuration { /** * Do not create any GPU context. Use together with - * @ref Sdl2Application(const Arguments&, const Configuration&), - * @ref create(const Configuration&) or - * @ref tryCreate(const Configuration&) to prevent implicit - * creation of an OpenGL context. Can't be used with - * @ref Sdl2Application(const Arguments&, const Configuration&, const GLConfiguration&), - * @ref create(const Configuration&, const GLConfiguration&) or - * @ref tryCreate(const Configuration&, const GLConfiguration&). + * @ref Sdl2Application::Sdl2Application(const Arguments&, const Configuration&), + * @ref Sdl2Application::create(const Configuration&) or + * @ref Sdl2Application::tryCreate(const Configuration&) to prevent + * implicit creation of an OpenGL context. Can't be used with + * @ref Sdl2Application::Sdl2Application(const Arguments&, const Configuration&, const GLConfiguration&), + * @ref Sdl2Application::create(const Configuration&, const GLConfiguration&) or + * @ref Sdl2Application::tryCreate(const Configuration&, const GLConfiguration&). */ Contextless = 1u << 31, /* Hope this won't ever conflict with anything */ @@ -1737,9 +1821,9 @@ class Sdl2Application::Configuration { * Request a window for use with OpenGL. Useful in combination with * @ref WindowFlag::Contextless, otherwise enabled implicitly when * creating an OpenGL context using - * @ref Sdl2Application(const Arguments&, const Configuration&, const GLConfiguration&), - * @ref create(const Configuration&, const GLConfiguration&) or - * @ref tryCreate(const Configuration&, const GLConfiguration&). + * @ref Sdl2Application::Sdl2Application(const Arguments&, const Configuration&, const GLConfiguration&), + * @ref Sdl2Application::create(const Configuration&, const GLConfiguration&) + * or @ref Sdl2Application::tryCreate(const Configuration&, const GLConfiguration&). * @m_since{2019,10} */ OpenGL = SDL_WINDOW_OPENGL, @@ -2025,7 +2109,7 @@ class Sdl2Application::ExitEvent { @see @ref viewportEvent() */ -class Sdl2Application::ViewportEvent { +class Sdl2ApplicationWindow::ViewportEvent { public: /** @brief Copying is not allowed */ ViewportEvent(const ViewportEvent&) = delete; @@ -2126,7 +2210,7 @@ class Sdl2Application::ViewportEvent { @ref keyReleaseEvent(), @ref mousePressEvent(), @ref mouseReleaseEvent(), @ref mouseMoveEvent() */ -class Sdl2Application::InputEvent { +class Sdl2ApplicationWindow::InputEvent { public: /** * @brief Modifier @@ -2235,7 +2319,7 @@ class Sdl2Application::InputEvent { @see @ref keyPressEvent(), @ref keyReleaseEvent() */ -class Sdl2Application::KeyEvent: public Sdl2Application::InputEvent { +class Sdl2ApplicationWindow::KeyEvent: public InputEvent { public: /** * @brief Key @@ -2533,7 +2617,7 @@ class Sdl2Application::KeyEvent: public Sdl2Application::InputEvent { @see @ref MouseMoveEvent, @ref MouseScrollEvent, @ref mousePressEvent(), @ref mouseReleaseEvent() */ -class Sdl2Application::MouseEvent: public Sdl2Application::InputEvent { +class Sdl2ApplicationWindow::MouseEvent: public InputEvent { public: /** * @brief Mouse button @@ -2600,7 +2684,7 @@ class Sdl2Application::MouseEvent: public Sdl2Application::InputEvent { @see @ref MouseEvent, @ref MouseScrollEvent, @ref mouseMoveEvent() */ -class Sdl2Application::MouseMoveEvent: public Sdl2Application::InputEvent { +class Sdl2ApplicationWindow::MouseMoveEvent: public InputEvent { public: /** * @brief Mouse button @@ -2661,7 +2745,7 @@ class Sdl2Application::MouseMoveEvent: public Sdl2Application::InputEvent { @see @ref MouseEvent, @ref MouseMoveEvent, @ref mouseScrollEvent() */ -class Sdl2Application::MouseScrollEvent: public Sdl2Application::InputEvent { +class Sdl2ApplicationWindow::MouseScrollEvent: public InputEvent { public: /** @brief Scroll offset */ Vector2 offset() const { return _offset; } @@ -2696,7 +2780,7 @@ class Sdl2Application::MouseScrollEvent: public Sdl2Application::InputEvent { @experimental @see @ref multiGestureEvent() */ -class Sdl2Application::MultiGestureEvent { +class Sdl2ApplicationWindow::MultiGestureEvent { public: /** @brief Copying is not allowed */ MultiGestureEvent(const MultiGestureEvent&) = delete; @@ -2773,7 +2857,7 @@ class Sdl2Application::MultiGestureEvent { @see @ref TextEditingEvent, @ref textInputEvent() */ -class Sdl2Application::TextInputEvent { +class Sdl2ApplicationWindow::TextInputEvent { public: /** @brief Copying is not allowed */ TextInputEvent(const TextInputEvent&) = delete; @@ -2831,7 +2915,7 @@ class Sdl2Application::TextInputEvent { @see @ref textEditingEvent() */ -class Sdl2Application::TextEditingEvent { +class Sdl2ApplicationWindow::TextEditingEvent { public: /** @brief Copying is not allowed */ TextEditingEvent(const TextEditingEvent&) = delete; @@ -2939,6 +3023,7 @@ When no other application header is included this macro is also aliased to #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_APPLICATION_MAIN typedef Sdl2Application Application; +typedef Sdl2ApplicationWindow ApplicationWindow; typedef BasicScreen Screen; typedef BasicScreenedApplication ScreenedApplication; #define MAGNUM_APPLICATION_MAIN(className) MAGNUM_SDL2APPLICATION_MAIN(className) @@ -2947,9 +3032,9 @@ typedef BasicScreenedApplication ScreenedApplication; #endif #endif -CORRADE_ENUMSET_OPERATORS(Sdl2Application::Configuration::WindowFlags) -CORRADE_ENUMSET_OPERATORS(Sdl2Application::InputEvent::Modifiers) -CORRADE_ENUMSET_OPERATORS(Sdl2Application::MouseMoveEvent::Buttons) +CORRADE_ENUMSET_OPERATORS(Sdl2ApplicationWindow::Configuration::WindowFlags) +CORRADE_ENUMSET_OPERATORS(Sdl2ApplicationWindow::InputEvent::Modifiers) +CORRADE_ENUMSET_OPERATORS(Sdl2ApplicationWindow::MouseMoveEvent::Buttons) }} diff --git a/src/Magnum/SceneGraph/Camera.h b/src/Magnum/SceneGraph/Camera.h index 4f8abcca8..085639814 100644 --- a/src/Magnum/SceneGraph/Camera.h +++ b/src/Magnum/SceneGraph/Camera.h @@ -156,7 +156,7 @@ template class Camera: public AbstractFeature