diff --git a/doc/changelog.dox b/doc/changelog.dox index 8df52aa7c..86b4d494f 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -958,9 +958,11 @@ See also: - The Emscripten toolchain now looks for `lib*.a` files in addition to `*.bc` for better compatibility with 3rd party toolchains and package managers like Vcpkg (see [mosra/magnum#520](https://github.com/mosra/magnum/issues/520)). -- @ref Platform::Sdl2Application and @ref Platform::EmscriptenApplication now - use `UTF8ToString` instead of `AsciiToString` as the latter is no longer - included by default on Emscripten 3.1.21+ (see [mosra/magnum#619](https://github.com/mosra/magnum/issues/619)). +- The Emscripten build now uses `--js-library` instead of inline `EM_ASM()` + for calling into JavaScript. This allows it to properly specify its runtime + dependencies without risking breakages when new Emscripten versions make + more JS API functions optional, and circumvents the need for users to + specify `-s EXPORTED_FUNCTIONS` on their side. See [mosra/magnum#619](https://github.com/mosra/magnum/issues/619). @subsection changelog-latest-bugfixes Bug fixes diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index db701682f..fed3a7cdb 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -162,6 +162,7 @@ # MAGNUM_*_LIBRARY - Component libraries (w/o dependencies) # MAGNUM_*_LIBRARY_DEBUG - Debug version of given library, if found # MAGNUM_*_LIBRARY_RELEASE - Release version of given library, if found +# MAGNUM_PLATFORM_JS - Path to MagnumPlatform.js file # MAGNUM_BINARY_INSTALL_DIR - Binary installation directory # MAGNUM_LIBRARY_INSTALL_DIR - Library installation directory # MAGNUM_DATA_INSTALL_DIR - Data installation directory @@ -696,7 +697,17 @@ foreach(_component ${Magnum_FIND_COMPONENTS}) set_property(TARGET Magnum::${_component} APPEND PROPERTY INTERFACE_LINK_LIBRARIES android EGL::EGL) - # EmscriptenApplication has no additional dependencies + # Emscripten application dependencies + elseif(_component STREQUAL EmscriptenApplication) + # Emscripten has various stuff implemented in JS + if(CORRADE_TARGET_EMSCRIPTEN) + find_file(MAGNUM_PLATFORM_JS MagnumPlatform.js + PATH_SUFFIXES lib) + set_property(TARGET Magnum::${_component} APPEND PROPERTY + # TODO switch to INTERFACE_LINK_OPTIONS and SHELL: once + # we require CMake 3.13 unconditionally + INTERFACE_LINK_LIBRARIES "--js-library ${MAGNUM_PLATFORM_JS}") + endif() # GLFW application dependencies elseif(_component STREQUAL GlfwApplication) @@ -752,6 +763,14 @@ foreach(_component ${Magnum_FIND_COMPONENTS}) elseif(CORRADE_TARGET_UNIX) set_property(TARGET Magnum::${_component} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS}) + # Emscripten has various stuff implemented in JS + elseif(CORRADE_TARGET_EMSCRIPTEN) + find_file(MAGNUM_PLATFORM_JS MagnumPlatform.js + PATH_SUFFIXES lib) + set_property(TARGET Magnum::${_component} APPEND PROPERTY + # TODO switch to INTERFACE_LINK_OPTIONS and SHELL: once + # we require CMake 3.13 unconditionally + INTERFACE_LINK_LIBRARIES "--js-library ${MAGNUM_PLATFORM_JS}") endif() # With GLVND (since CMake 3.11) we need to explicitly link to diff --git a/src/Magnum/Platform/CMakeLists.txt b/src/Magnum/Platform/CMakeLists.txt index dd481b163..75041d754 100644 --- a/src/Magnum/Platform/CMakeLists.txt +++ b/src/Magnum/Platform/CMakeLists.txt @@ -203,6 +203,24 @@ if(CORRADE_TARGET_EMSCRIPTEN AND (MAGNUM_WITH_EMSCRIPTENAPPLICATION OR MAGNUM_WI if(EMSCRIPTEN_VERSION VERSION_LESS 1.39.5) message(SEND_ERROR "Emscripten 1.39.5+, which enables DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR by default, is required to build EmscriptenApplication and Sdl2Application. Found version ${EMSCRIPTEN_VERSION}.") endif() + + # Patch the Platform.js file to contain only __deps that match given + # Emscripten version. No, there's no known better way. See the comment in + # the file itself for details. + if(EMSCRIPTEN_VERSION VERSION_LESS 3.1.35) + set(MagnumPlatform_EMSCRIPTEN_3135_ONLY "//") # Haha + else() + set(MagnumPlatform_EMSCRIPTEN_3135_ONLY "/* Emscripten 3.1.35+ */") + endif() + if(EMSCRIPTEN_VERSION VERSION_LESS 2.0.10) + set(MagnumPlatform_EMSCRIPTEN_2010_ONLY "//") # Haha + else() + set(MagnumPlatform_EMSCRIPTEN_2010_ONLY "/* Emscripten 2.0.10+ */") + endif() + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Platform.js.in + ${CMAKE_CURRENT_BINARY_DIR}/Platform.js) + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Platform.js DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR} RENAME MagnumPlatform.js) endif() # Emscripten application @@ -232,6 +250,14 @@ if(MAGNUM_WITH_EMSCRIPTENAPPLICATION) if(MAGNUM_TARGET_GL) target_link_libraries(MagnumEmscriptenApplication PUBLIC MagnumGL) endif() + if(CORRADE_TARGET_EMSCRIPTEN) + # TODO switch to target_link_options() and SHELL: once we require CMake + # 3.13 unconditionally + target_link_libraries(MagnumEmscriptenApplication PUBLIC "--js-library ${CMAKE_CURRENT_BINARY_DIR}/Platform.js") + # TODO this adds the dependency only on 3.13+ and only for Make/Ninja, + # any better option? + set_property(TARGET MagnumEmscriptenApplication APPEND PROPERTY INTERFACE_LINK_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Platform.js) + endif() install(FILES ${MagnumEmscriptenApplication_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) install(TARGETS MagnumEmscriptenApplication @@ -344,6 +370,14 @@ if(MAGNUM_WITH_SDL2APPLICATION) MagnumGL ${MagnumSomeContext_LIBRARY}) endif() + if(CORRADE_TARGET_EMSCRIPTEN) + # TODO switch to target_link_options() and SHELL: once we require CMake + # 3.13 unconditionally + target_link_libraries(MagnumSdl2Application PUBLIC "--js-library ${CMAKE_CURRENT_BINARY_DIR}/Platform.js") + # TODO this adds the dependency only on 3.13+ and only for Make/Ninja, + # any better option? + set_property(TARGET MagnumSdl2Application APPEND PROPERTY INTERFACE_LINK_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Platform.js) + endif() install(FILES ${MagnumSdl2Application_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) install(TARGETS MagnumSdl2Application diff --git a/src/Magnum/Platform/EmscriptenApplication.cpp b/src/Magnum/Platform/EmscriptenApplication.cpp index 20fc3d675..958813a8a 100644 --- a/src/Magnum/Platform/EmscriptenApplication.cpp +++ b/src/Magnum/Platform/EmscriptenApplication.cpp @@ -43,6 +43,18 @@ #include "Magnum/GL/Version.h" #endif +#ifdef CORRADE_TARGET_EMSCRIPTEN +/* Implemented in Platform.js.in */ +extern "C" { + char* magnumPlatformCanvasId(); + char* magnumPlatformKeyboardListeningElement(); + void magnumPlatformSetWindowTitle(const char* string, std::size_t size); + void magnumPlatformSetContainerCssClass(const char* string, std::size_t size); + void magnumPlatformSetCursor(const char* string, std::size_t size); + void magnumPlatformRequestAnimationFrame(int(*callback)(void*), void* state); +} +#endif + namespace Magnum { namespace Platform { using namespace Containers::Literals; @@ -178,20 +190,7 @@ namespace { } Containers::String canvasId() { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" - /* Note: can't use let or const, as that breaks closure compiler: - ERROR - [JSC_LANGUAGE_FEATURE] This language feature is only - supported for ECMASCRIPT6 mode or better: const declaration. */ - char* id = reinterpret_cast(EM_ASM_INT({ - var id = '#' + Module['canvas'].id; - var bytes = lengthBytesUTF8(id) + 1; - var memory = _malloc(bytes); - stringToUTF8(id, memory, bytes); - return memory; - })); - #pragma GCC diagnostic pop - return Containers::String{id, [](char* data, std::size_t) { std::free(data); }}; + return Containers::String{magnumPlatformCanvasId(), [](char* data, std::size_t) { std::free(data); }}; } } @@ -434,23 +433,11 @@ Vector2i EmscriptenApplication::framebufferSize() const { #endif void EmscriptenApplication::setWindowTitle(const Containers::StringView title) { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension" - EM_ASM_({document.title = UTF8ToString($0, $1);}, title.data(), title.size()); - #pragma GCC diagnostic pop + magnumPlatformSetWindowTitle(title.data(), title.size()); } void EmscriptenApplication::setContainerCssClass(const Containers::StringView cssClass) { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension" - EM_ASM_({ - /* Handle also the classic #container for backwards compatibility. We - also need to preserve the mn-container otherwise next time we'd have - no way to look for it anymore. */ - (Module['canvas'].closest('.mn-container') || - document.getElementById('container')).className = (['mn-container', UTF8ToString($0, $1)]).join(' '); - }, cssClass.data(), cssClass.size()); - #pragma GCC diagnostic pop + magnumPlatformSetContainerCssClass(cssClass.data(), cssClass.size()); /* Trigger a potential viewport event -- we don't poll the canvas size like Sdl2Application does, so it needs to be done explicitly */ @@ -539,32 +526,12 @@ void EmscriptenApplication::setupCallbacks(bool resizable) { return e.isAccepted(); })); - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" /* document and window are 'specialEventTargets' in emscripten, matching EMSCRIPTEN_EVENT_TARGET_DOCUMENT and EMSCRIPTEN_EVENT_TARGET_WINDOW. As the lookup happens with the passed parameter and arrays support element lookup via strings, we can unify the code by returning string of 1 or 2 if the target is document or window. */ - /* Note: can't use let or const, as that breaks closure compiler: - ERROR - [JSC_LANGUAGE_FEATURE] This language feature is only - supported for ECMASCRIPT6 mode or better: const declaration. */ - char* const keyboardListeningElement = reinterpret_cast(EM_ASM_INT({ - var element = Module['keyboardListeningElement'] || document; - - if(element === document) return 1; /* EMSCRIPTEN_EVENT_TARGET_DOCUMENT */ - if(element === window) return 2; /* EMSCRIPTEN_EVENT_TARGET_WINDOW */ - if('id' in element) { - var id = '#' + element.id; - var bytes = lengthBytesUTF8(id) + 1; - var memory = _malloc(bytes); - stringToUTF8(id, memory, bytes); - return memory; - } - - return 0; - })); - #pragma GCC diagnostic pop + char* const keyboardListeningElement = magnumPlatformKeyboardListeningElement(); /* If the element is a heap-allocated string, ensure it gets properly freed after */ @@ -650,43 +617,43 @@ void EmscriptenApplication::setupAnimationFrame(bool forceAnimationFrame) { namespace { -constexpr const char* CursorMap[] { - "auto", - "default", - "none", - "context-menu", - "help", - "pointer", - "progress", - "wait", - "cell", - "crosshair", - "text", - "vertical-text", - "alias", - "copy", - "move", - "no-drop", - "not-allowed", - "grab", - "grabbing", - "all-scroll", - "col-resize", - "row-resize", - "n-resize", - "e-resize", - "s-resize", - "w-resize", - "ne-resize", - "nw-resize", - "se-resize", - "sw-resize", - "ew-resize", - "ns-resize", - "nesw-resize", - "nwse-resize", - "zoom-in", - "zoom-out" +constexpr Containers::StringView CursorMap[]{ + "auto"_s, + "default"_s, + "none"_s, + "context-menu"_s, + "help"_s, + "pointer"_s, + "progress"_s, + "wait"_s, + "cell"_s, + "crosshair"_s, + "text"_s, + "vertical-text"_s, + "alias"_s, + "copy"_s, + "move"_s, + "no-drop"_s, + "not-allowed"_s, + "grab"_s, + "grabbing"_s, + "all-scroll"_s, + "col-resize"_s, + "row-resize"_s, + "n-resize"_s, + "e-resize"_s, + "s-resize"_s, + "w-resize"_s, + "ne-resize"_s, + "nw-resize"_s, + "se-resize"_s, + "sw-resize"_s, + "ew-resize"_s, + "ns-resize"_s, + "nesw-resize"_s, + "nwse-resize"_s, + "zoom-in"_s, + "zoom-out"_s }; } @@ -694,10 +661,8 @@ constexpr const char* CursorMap[] { void EmscriptenApplication::setCursor(Cursor cursor) { _cursor = cursor; CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(CursorMap)); - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension" - EM_ASM_({Module['canvas'].style.cursor = UTF8ToString($0);}, CursorMap[UnsignedInt(cursor)]); - #pragma GCC diagnostic pop + magnumPlatformSetCursor(CursorMap[UnsignedInt(cursor)].data(), + CursorMap[UnsignedInt(cursor)].size()); } EmscriptenApplication::Cursor EmscriptenApplication::cursor() { @@ -753,49 +718,7 @@ void EmscriptenApplication::redraw() { /* Start requestAnimationFrame loop */ _flags |= Flag::LoopActive; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension" - EM_ASM({ - /* Animation frame callback */ - var drawEvent = function() { - var id = window.requestAnimationFrame(drawEvent); - - /* Call our callback via function pointer taking an int and - returning int as well. This used to be - - if(!dynCall('ii', $0, [$1])) { - - but since 2.0.10 the dynCall isn't exported by default anymore: - https://github.com/emscripten-core/emscripten/commit/496967e00735c1523299e116dc692572d3d6d082 - and making it exported again doing so involves crazy shit with - CMake 3.13-only features and a ton of backslashes: - - target_link_options(MagnumEmscriptenApplication INTERFACE - "SHELL:-s \"DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=['\${xylophone}dynCall']\"" - "SHELL:-s \"EXPORTED_FUNCTIONS=['_main', 'dynCall']\"") - - (the ${xylophone} is needed because CMake expands that to - `\$${xylophone}dynCall` for some reason, which then the shell - collapses to `$dynCall` (assuming a $xylophone env var doesn't - exist, which it shoulndn't, but also it's 2021 and so everything - is possible), and no amount of \\\\$$$ helps avoiding that - xylophone); but doing so means we forever hardcode what - functions are exported and thus whatever extra Emscripten needs - to export will be overridden by this, causing only pain and - misery. - - So instead we rely on the implementation details of dynCall, - which are actually really simple: - https://github.com/emscripten-core/emscripten/blob/496967e00735c1523299e116dc692572d3d6d082/src/library.js#L3730-L3747 - and PRAY it doesn't change again in the future. */ - if(!wasmTable.get($0).apply(null, [$1])) { - window.cancelAnimationFrame(id); - } - }; - - window.requestAnimationFrame(drawEvent); - }, _callback, this); - #pragma GCC diagnostic pop + magnumPlatformRequestAnimationFrame(_callback, this); } void EmscriptenApplication::exit(int) { diff --git a/src/Magnum/Platform/Platform.js.in b/src/Magnum/Platform/Platform.js.in new file mode 100644 index 000000000..2664c3acc --- /dev/null +++ b/src/Magnum/Platform/Platform.js.in @@ -0,0 +1,137 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022, 2023 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/* JavaScript called by C++ code in EmscriptenApplication and Sdl2Application. + Doing it this way instead of having it inline with EM_ASM(), because this + provides an actually usable way of expressing dependencies. With EM_ASM() + one would instead have to pass + -s EXPORTED_FUNCTIONS=[...] + to the linker, and OF COURSE there still isn't a way to combine multiple of + those together: https://github.com/emscripten-core/emscripten/issues/19058 + Which would mean shifting the burden of specifying all possible exported + functions to the end user, which has no way to know if the list is correct + until the actual code needing given function gets called! + + Note: can't use let or const, as that breaks closure compiler: + ERROR - [JSC_LANGUAGE_FEATURE] This language feature is only supported for + ECMASCRIPT6 mode or better: const declaration. + + Also, lengthBytesUTF8, stringToUTF8 and UTF8ToString are only made library + functions as of https://github.com/emscripten-core/emscripten/pull/19097 + (Emscripten 3.1.35), before that they cause an error if included in __deps. + There's (of course, what else to expect) no way to query Emscripten version + from within the JS library file, and there's also no useful change in the + predefined setting variables between 3.1.34 and 35 I could rely on. Well, + except for STRUCT_INFO, which got removed from settings_internal.js in 35, + but the dumb-as-a-rock preprocessor in src/parseTools.js doesn't even + recognize #ifndef, tells me to use #if if I attempt to use #ifdef, and then + while it does what's expected on 3.1.34, on 3.1.35 it fails on + ReferenceError: STRUCT_INFO is not defined + Ourageously stupid. All of this. So what I do instead is passing this file + through configure_file() and replacing MagnumPlatform_EMSCRIPTEN_3135_ONLY + with a // on older versions. */ + +mergeInto(LibraryManager.library, { + /* Used by both EmscriptenApplication and Sdl2Application */ + magnumPlatformSetContainerCssClass__deps: [ + ${MagnumPlatform_EMSCRIPTEN_3135_ONLY} '$UTF8ToString' + ], + magnumPlatformSetContainerCssClass: function(string, size) { + /* Handle also the classic #container for backwards compatibility. We + also need to preserve the mn-container otherwise next time we'd have + no way to look for it anymore. + + Using UTF8ToString() instead of AsciiToString() as it has an + explicit size parameter and thus doesn't need a null-terminated + input, which would potentially require yet another allocation. + UTF8ToString() is also used elsewhere while AsciiToString() isn't, + so even while AsciiToString() is significantly smaller it would + still cause the JS to get bigger compared to using UTF8ToString() + everywhere. */ + (Module['canvas'].closest('.mn-container') || + document.getElementById('container')).className = (['mn-container', UTF8ToString(string, size)]).join(' '); + }, + magnumPlatformSetCursor__deps: [ + ${MagnumPlatform_EMSCRIPTEN_3135_ONLY} '$UTF8ToString' + ], + magnumPlatformSetCursor: function(string, size) { + /* This could again use AsciiToString() but here we can pass explicit + size and avoid a length calculation */ + Module['canvas'].style.cursor = UTF8ToString(string, size); + }, + + /* Used by EmscriptenApplication only */ + magnumPlatformCanvasId__deps: ['malloc', + ${MagnumPlatform_EMSCRIPTEN_3135_ONLY} '$lengthBytesUTF8', '$stringToUTF8' + ], + magnumPlatformCanvasId: function() { + var id = '#' + Module['canvas'].id; + var bytes = lengthBytesUTF8(id) + 1; + var memory = _malloc(bytes); + stringToUTF8(id, memory, bytes); + return memory; + }, + magnumPlatformSetWindowTitle__deps: [ + ${MagnumPlatform_EMSCRIPTEN_3135_ONLY} '$UTF8ToString' + ], + magnumPlatformSetWindowTitle: function(string, size) { + document.title = UTF8ToString(string, size); + }, + magnumPlatformKeyboardListeningElement__deps: ['malloc', + ${MagnumPlatform_EMSCRIPTEN_3135_ONLY} '$lengthBytesUTF8', '$stringToUTF8' + ], + magnumPlatformKeyboardListeningElement: function() { + var element = Module['keyboardListeningElement'] || document; + + if(element === document) return 1; /* EMSCRIPTEN_EVENT_TARGET_DOCUMENT */ + if(element === window) return 2; /* EMSCRIPTEN_EVENT_TARGET_WINDOW */ + if('id' in element) { + var id = '#' + element.id; + /* This could theoretically also use just stringToAscii(), but + as stringToUTF8() is used elsewhere stringToAscii() would still + inflate the JS even though it's smaller. */ + var bytes = lengthBytesUTF8(id) + 1; + var memory = _malloc(bytes); + stringToUTF8(id, memory, bytes); + return memory; + } + + return 0; + }, + magnumPlatformRequestAnimationFrame__deps: [ + ${MagnumPlatform_EMSCRIPTEN_2010_ONLY} '$dynCall' + ], + magnumPlatformRequestAnimationFrame: function(callback, state) { + var drawEvent = function() { + var id = window.requestAnimationFrame(drawEvent); + if(!dynCall('ii', callback, [state])) + window.cancelAnimationFrame(id); + }; + window.requestAnimationFrame(drawEvent); + }, + +}); + +// kate: hl javascript diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index 1eff0e93c..cd63432c2 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -68,6 +68,14 @@ #include #endif +#ifdef CORRADE_TARGET_EMSCRIPTEN +/* Implemented in Platform.js.in */ +extern "C" { + void magnumPlatformSetContainerCssClass(const char* string, std::size_t size); + void magnumPlatformSetCursor(const char* string, std::size_t size); +} +#endif + namespace Magnum { namespace Platform { using namespace Containers::Literals; @@ -752,16 +760,7 @@ Vector2i Sdl2Application::framebufferSize() const { #ifdef CORRADE_TARGET_EMSCRIPTEN void Sdl2Application::setContainerCssClass(const Containers::StringView cssClass) { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension" - EM_ASM_({ - /* Handle also the classic #container for backwards compatibility. We - also need to preserve the mn-container otherwise next time we'd have - no way to look for it anymore. */ - (Module['canvas'].closest('.mn-container') || - document.getElementById('container')).className = (['mn-container', UTF8ToString($0, $1)]).join(' '); - }, cssClass.data(), cssClass.size()); - #pragma GCC diagnostic pop + magnumPlatformSetContainerCssClass(cssClass.data(), cssClass.size()); } #endif @@ -1047,20 +1046,20 @@ constexpr SDL_SystemCursor CursorMap[] { SDL_SYSTEM_CURSOR_HAND }; #else -constexpr const char* CursorMap[] { - "default", - "text", - "wait", - "crosshair", - "progress", - "nwse-resize", - "nesw-resize", - "ew-resize", - "ns-resize", - "move", - "not-allowed", - "pointer", - "none" +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 @@ -1099,10 +1098,8 @@ void Sdl2Application::setCursor(Cursor cursor) { CORRADE_ASSERT(_surface, "Platform::Sdl2Application::setCursor(): no window opened", ); _cursor = cursor; CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(CursorMap)); - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension" - EM_ASM_({Module['canvas'].style.cursor = UTF8ToString($0);}, CursorMap[UnsignedInt(cursor)]); - #pragma GCC diagnostic pop + magnumPlatformSetCursor(CursorMap[UnsignedInt(cursor)].data(), + CursorMap[UnsignedInt(cursor)].size()); #endif }