@ -266,12 +266,19 @@ bool EmscriptenApplication::tryCreate(const Configuration& configuration) {
}
}
# endif
# endif
_canvasTarget = configuration . canvasTarget ( ) ;
std : : ostream * verbose = _verboseLog ? Debug : : output ( ) : nullptr ;
_deprecatedTargetBehavior = checkForDeprecatedEmscriptenTargetBehavior ( ) ;
if ( _deprecatedTargetBehavior ) {
Debug { verbose } < < " Platform::EmscriptenApplication::tryCreate(): using old Emscripten target behavior " ;
}
_canvasTarget = ( _deprecatedTargetBehavior ? " " : " # " ) + canvasId ( ) ;
_dpiScaling = dpiScaling ( configuration ) ;
_dpiScaling = dpiScaling ( configuration ) ;
if ( ! configuration . size ( ) . isZero ( ) ) {
if ( ! configuration . size ( ) . isZero ( ) ) {
const Vector2i scaledCanvasSize = configuration . size ( ) * _dpiScaling ;
const Vector2i scaledCanvasSize = configuration . size ( ) * _dpiScaling ;
emscripten_set_canvas_element_size ( _canvasTarget . c_str ( ) , scaledCanvasSize . x ( ) , scaledCanvasSize . y ( ) ) ;
emscripten_set_canvas_element_size ( _canvasTarget . data ( ) , scaledCanvasSize . x ( ) , scaledCanvasSize . y ( ) ) ;
}
}
setupCallbacks ( ! ! ( configuration . windowFlags ( ) & Configuration : : WindowFlag : : Resizable ) ) ;
setupCallbacks ( ! ! ( configuration . windowFlags ( ) & Configuration : : WindowFlag : : Resizable ) ) ;
@ -329,7 +336,16 @@ bool EmscriptenApplication::tryCreate(const Configuration& configuration, const
_devicePixelRatio = Vector2 { Float ( emscripten_get_device_pixel_ratio ( ) ) } ;
_devicePixelRatio = Vector2 { Float ( emscripten_get_device_pixel_ratio ( ) ) } ;
Debug { verbose } < < " Platform::EmscriptenApplication: device pixel ratio " < < _devicePixelRatio . x ( ) ;
Debug { verbose } < < " Platform::EmscriptenApplication: device pixel ratio " < < _devicePixelRatio . x ( ) ;
_canvasTarget = configuration . canvasTarget ( ) ;
/* Find out which elemen target strings Emscripten expects. This depends on
the DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR compiler option . */
_deprecatedTargetBehavior = checkForDeprecatedEmscriptenTargetBehavior ( ) ;
if ( _deprecatedTargetBehavior ) {
Debug { verbose } < < " Platform::EmscriptenApplication::tryCreate(): using old Emscripten target behavior " ;
}
/* Get the canvas ID from Module.canvas, either set by EmscriptenApplication.js
or overridden / manually set by the user . */
_canvasTarget = ( _deprecatedTargetBehavior ? " " : " # " ) + canvasId ( ) ;
/* Get CSS canvas size and cache it. This is used later to detect canvas
/* Get CSS canvas size and cache it. This is used later to detect canvas
resizes in emscripten_set_resize_callback ( ) and fire viewport events ,
resizes in emscripten_set_resize_callback ( ) and fire viewport events ,
@ -350,10 +366,10 @@ bool EmscriptenApplication::tryCreate(const Configuration& configuration, const
}
}
_dpiScaling = dpiScaling ( configuration ) ;
_dpiScaling = dpiScaling ( configuration ) ;
const Vector2i scaledCanvasSize = canvasSize * _dpiScaling * _devicePixelRatio ;
const Vector2i scaledCanvasSize = canvasSize * _dpiScaling * _devicePixelRatio ;
emscripten_set_canvas_element_size ( _canvasTarget . c_str ( ) , scaledCanvasSize . x ( ) , scaledCanvasSize . y ( ) ) ;
emscripten_set_canvas_element_size ( _canvasTarget . data ( ) , scaledCanvasSize . x ( ) , scaledCanvasSize . y ( ) ) ;
/* Create WebGL context */
/* Create WebGL context */
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context ( _canvasTarget . c_str ( ) , & attrs ) ;
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context ( _canvasTarget . data ( ) , & attrs ) ;
if ( ! context ) {
if ( ! context ) {
/* When context creation fails, `context` is a negative integer
/* When context creation fails, `context` is a negative integer
matching EMSCRIPTEN_RESULT_ * defines */
matching EMSCRIPTEN_RESULT_ * defines */
@ -375,14 +391,14 @@ bool EmscriptenApplication::tryCreate(const Configuration& configuration, const
Vector2i EmscriptenApplication : : windowSize ( ) const {
Vector2i EmscriptenApplication : : windowSize ( ) const {
Vector2d size ;
Vector2d size ;
emscripten_get_element_css_size ( _canvasTarget . c_str ( ) , & size . x ( ) , & size . y ( ) ) ;
emscripten_get_element_css_size ( _canvasTarget . data ( ) , & size . x ( ) , & size . y ( ) ) ;
return Vector2i { Math : : round ( size ) } ;
return Vector2i { Math : : round ( size ) } ;
}
}
# ifdef MAGNUM_TARGET_GL
# ifdef MAGNUM_TARGET_GL
Vector2i EmscriptenApplication : : framebufferSize ( ) const {
Vector2i EmscriptenApplication : : framebufferSize ( ) const {
Vector2i size ;
Vector2i size ;
emscripten_get_canvas_element_size ( _canvasTarget . c_str ( ) , & size . x ( ) , & size . y ( ) ) ;
emscripten_get_canvas_element_size ( _canvasTarget . data ( ) , & size . x ( ) , & size . y ( ) ) ;
return size ;
return size ;
}
}
# endif
# endif
@ -422,7 +438,7 @@ void EmscriptenApplication::handleCanvasResize(const EmscriptenUiEvent* event) {
if ( canvasSize ! = _lastKnownCanvasSize ) {
if ( canvasSize ! = _lastKnownCanvasSize ) {
_lastKnownCanvasSize = canvasSize ;
_lastKnownCanvasSize = canvasSize ;
const Vector2i size = canvasSize * _dpiScaling * _devicePixelRatio ;
const Vector2i size = canvasSize * _dpiScaling * _devicePixelRatio ;
emscripten_set_canvas_element_size ( _canvasTarget . c_str ( ) , size . x ( ) , size . y ( ) ) ;
emscripten_set_canvas_element_size ( _canvasTarget . data ( ) , size . x ( ) , size . y ( ) ) ;
ViewportEvent e { event , canvasSize ,
ViewportEvent e { event , canvasSize ,
# ifdef MAGNUM_TARGET_GL
# ifdef MAGNUM_TARGET_GL
framebufferSize ( ) ,
framebufferSize ( ) ,
@ -448,11 +464,11 @@ void EmscriptenApplication::setupCallbacks(bool resizable) {
changes . Better than polling for this change in every frame like
changes . Better than polling for this change in every frame like
Sdl2Application does , but still not ideal . */
Sdl2Application does , but still not ideal . */
if ( resizable ) {
if ( resizable ) {
const char * target =
# ifdef EMSCRIPTEN_EVENT_TARGET_WINDOW
# ifdef EMSCRIPTEN_EVENT_TARGET_WINDOW
const char * target = EMSCRIPTEN_EVENT_TARGET_WINDOW ;
! _deprecatedTargetBehavior ? EMSCRIPTEN_EVENT_TARGET_WINDOW :
# else
const char * target = " #window " ;
# endif
# endif
" #window " ;
auto cb = [ ] ( int , const EmscriptenUiEvent * event , void * userData ) - > Int {
auto cb = [ ] ( int , const EmscriptenUiEvent * event , void * userData ) - > Int {
static_cast < EmscriptenApplication * > ( userData ) - > handleCanvasResize ( event ) ;
static_cast < EmscriptenApplication * > ( userData ) - > handleCanvasResize ( event ) ;
return false ; /** @todo what does ignoring a resize event mean? */
return false ; /** @todo what does ignoring a resize event mean? */
@ -460,21 +476,21 @@ void EmscriptenApplication::setupCallbacks(bool resizable) {
emscripten_set_resize_callback ( target , this , false , cb ) ;
emscripten_set_resize_callback ( target , this , false , cb ) ;
}
}
emscripten_set_mousedown_callback ( _canvasTarget . c_str ( ) , this , false ,
emscripten_set_mousedown_callback ( _canvasTarget . data ( ) , this , false ,
( [ ] ( int , const EmscriptenMouseEvent * event , void * userData ) - > Int {
( [ ] ( int , const EmscriptenMouseEvent * event , void * userData ) - > Int {
MouseEvent e { * event } ;
MouseEvent e { * event } ;
static_cast < EmscriptenApplication * > ( userData ) - > mousePressEvent ( e ) ;
static_cast < EmscriptenApplication * > ( userData ) - > mousePressEvent ( e ) ;
return e . isAccepted ( ) ;
return e . isAccepted ( ) ;
} ) ) ;
} ) ) ;
emscripten_set_mouseup_callback ( _canvasTarget . c_str ( ) , this , false ,
emscripten_set_mouseup_callback ( _canvasTarget . data ( ) , this , false ,
( [ ] ( int , const EmscriptenMouseEvent * event , void * userData ) - > Int {
( [ ] ( int , const EmscriptenMouseEvent * event , void * userData ) - > Int {
MouseEvent e { * event } ;
MouseEvent e { * event } ;
static_cast < EmscriptenApplication * > ( userData ) - > mouseReleaseEvent ( e ) ;
static_cast < EmscriptenApplication * > ( userData ) - > mouseReleaseEvent ( e ) ;
return e . isAccepted ( ) ;
return e . isAccepted ( ) ;
} ) ) ;
} ) ) ;
emscripten_set_mousemove_callback ( _canvasTarget . c_str ( ) , this , false ,
emscripten_set_mousemove_callback ( _canvasTarget . data ( ) , this , false ,
( [ ] ( int , const EmscriptenMouseEvent * event , void * userData ) - > Int {
( [ ] ( int , const EmscriptenMouseEvent * event , void * userData ) - > Int {
auto & app = * static_cast < EmscriptenApplication * > ( userData ) ;
auto & app = * static_cast < EmscriptenApplication * > ( userData ) ;
/* With DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR, canvasX/Y is
/* With DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR, canvasX/Y is
@ -491,7 +507,7 @@ void EmscriptenApplication::setupCallbacks(bool resizable) {
return e . isAccepted ( ) ;
return e . isAccepted ( ) ;
} ) ) ;
} ) ) ;
emscripten_set_wheel_callback ( _canvasTarget . c_str ( ) , this , false ,
emscripten_set_wheel_callback ( _canvasTarget . data ( ) , this , false ,
( [ ] ( int , const EmscriptenWheelEvent * event , void * userData ) - > Int {
( [ ] ( int , const EmscriptenWheelEvent * event , void * userData ) - > Int {
MouseScrollEvent e { * event } ;
MouseScrollEvent e { * event } ;
static_cast < EmscriptenApplication * > ( userData ) - > mouseScrollEvent ( e ) ;
static_cast < EmscriptenApplication * > ( userData ) - > mouseScrollEvent ( e ) ;
@ -508,8 +524,7 @@ void EmscriptenApplication::setupCallbacks(bool resizable) {
1.38 .27 depending on - s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR = 1
1.38 .27 depending on - s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR = 1
but we don ' t want to force this flag on the users so the behavior
but we don ' t want to force this flag on the users so the behavior
handles both . */
handles both . */
# ifdef EMSCRIPTEN_EVENT_TARGET_DOCUMENT
char * keyboardListeningElement = reinterpret_cast < char * > ( EM_ASM_INT ( {
char * const keyboardListeningElement = reinterpret_cast < char * > ( EM_ASM_INT ( {
var element = Module [ ' keyboardListeningElement ' ] | | document ;
var element = Module [ ' keyboardListeningElement ' ] | | document ;
if ( element = = = document ) return 1 ;
if ( element = = = document ) return 1 ;
@ -519,29 +534,31 @@ void EmscriptenApplication::setupCallbacks(bool resizable) {
return 0 ;
return 0 ;
} ) ) ;
} ) ) ;
# else
char * const keyboardListeningElement = reinterpret_cast < char * > ( EM_ASM_INT ( {
var element = Module [ ' keyboardListeningElement ' ] | | document ;
if ( element = = = document ) element = { id : ' # document ' } ;
if ( element = = = window ) element = { id : ' # window ' } ;
if ( ' id ' in element )
return allocate ( intArrayFromString ( element . id ) , ' i8 ' , ALLOC_NORMAL ) ;
return 0 ;
} ) ) ;
# endif
# pragma GCC diagnostic pop
# pragma GCC diagnostic pop
std : : string keyboardListeningElementString ;
const char * keyboardListeningTarget = keyboardListeningElement ;
if ( _deprecatedTargetBehavior & & keyboardListeningElement = = reinterpret_cast < char * > ( 1 ) ) {
keyboardListeningTarget = " #document " ;
} else if ( _deprecatedTargetBehavior & & keyboardListeningElement = = reinterpret_cast < char * > ( 2 ) ) {
keyboardListeningTarget = " #window " ;
} else if ( keyboardListeningElement ) {
if ( ! _deprecatedTargetBehavior )
keyboardListeningElementString = " # " ;
keyboardListeningElementString + = keyboardListeningElement ;
std : : free ( keyboardListeningElement ) ;
keyboardListeningTarget = keyboardListeningElementString . data ( ) ;
}
/* Happens only if keyboardListeningElement was set, but did not have an
/* Happens only if keyboardListeningElement was set, but did not have an
` id ` attribute . Instead it should be either null or undefined , a DOM
` id ` attribute . Instead it should be either null or undefined , a DOM
element , ` window ` or ` document ` . */
element , ` window ` or ` document ` . */
CORRADE_ASSERT ( keyboardListeningElement ,
CORRADE_ASSERT ( keyboardListeningTarge t ,
" EmscriptenApplication::setupCallbacks(): invalid value for Module['keyboardListeningElement'] " , ) ;
" EmscriptenApplication::setupCallbacks(): invalid value for Module['keyboardListeningElement'] " , ) ;
/* keypress_callback does not fire for most of the keys and the modifiers
/* keypress_callback does not fire for most of the keys and the modifiers
don ' t seem to work , keydown on the other hand works fine for all */
don ' t seem to work , keydown on the other hand works fine for all */
emscripten_set_keydown_callback ( keyboardListeningElement , this , false ,
emscripten_set_keydown_callback ( keyboardListeningTarge t , this , false ,
( [ ] ( int , const EmscriptenKeyboardEvent * event , void * userData ) - > Int {
( [ ] ( int , const EmscriptenKeyboardEvent * event , void * userData ) - > Int {
EmscriptenApplication & app = * static_cast < EmscriptenApplication * > ( userData ) ;
EmscriptenApplication & app = * static_cast < EmscriptenApplication * > ( userData ) ;
const std : : size_t keyLen = std : : strlen ( event - > key ) ;
const std : : size_t keyLen = std : : strlen ( event - > key ) ;
@ -557,20 +574,12 @@ void EmscriptenApplication::setupCallbacks(bool resizable) {
return e . isAccepted ( ) ;
return e . isAccepted ( ) ;
} ) ) ;
} ) ) ;
emscripten_set_keyup_callback ( keyboardListeningElemen t , this , false ,
emscripten_set_keyup_callback ( keyboardListeningTarge t , this , false ,
( [ ] ( int , const EmscriptenKeyboardEvent * event , void * userData ) - > Int {
( [ ] ( int , const EmscriptenKeyboardEvent * event , void * userData ) - > Int {
KeyEvent e { * event } ;
KeyEvent e { * event } ;
static_cast < EmscriptenApplication * > ( userData ) - > keyReleaseEvent ( e ) ;
static_cast < EmscriptenApplication * > ( userData ) - > keyReleaseEvent ( e ) ;
return e . isAccepted ( ) ;
return e . isAccepted ( ) ;
} ) ) ;
} ) ) ;
# ifdef EMSCRIPTEN_EVENT_TARGET_DOCUMENT
if ( keyboardListeningElement ! = EMSCRIPTEN_EVENT_TARGET_DOCUMENT & &
keyboardListeningElement ! = EMSCRIPTEN_EVENT_TARGET_WINDOW )
# endif
{
std : : free ( keyboardListeningElement ) ;
}
}
}
void EmscriptenApplication : : setupAnimationFrame ( bool forceAnimationFrame ) {
void EmscriptenApplication : : setupAnimationFrame ( bool forceAnimationFrame ) {
@ -662,7 +671,7 @@ void EmscriptenApplication::setCursor(Cursor cursor) {
CORRADE_INTERNAL_ASSERT ( UnsignedInt ( cursor ) < Containers : : arraySize ( CursorMap ) ) ;
CORRADE_INTERNAL_ASSERT ( UnsignedInt ( cursor ) < Containers : : arraySize ( CursorMap ) ) ;
# pragma GCC diagnostic push
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
# pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
EM_ASM_ ( { document . querySelector ( UTF8 ToString( $ 0 ) ) . style . cursor = AsciiToString ( $ 1 ) ; } , _canvasTarget . c_str ( ) , CursorMap [ UnsignedInt ( cursor ) ] ) ;
EM_ASM_ ( { document . querySelector ( Ascii ToString( $ 0 ) ) . style . cursor = AsciiToString ( $ 1 ) ; } , _canvasTarget . data ( ) , CursorMap [ UnsignedInt ( cursor ) ] ) ;
# pragma GCC diagnostic pop
# pragma GCC diagnostic pop
}
}
@ -739,6 +748,38 @@ void EmscriptenApplication::exit(int) {
_flags | = Flag : : ExitRequested ;
_flags | = Flag : : ExitRequested ;
}
}
bool EmscriptenApplication : : checkForDeprecatedEmscriptenTargetBehavior ( ) {
/* Emscripten 1.38.27 changed to generic CSS selectors from element IDs
depending on - s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR = 1 being
set .
https : //github.com/emscripten-core/emscripten/pull/7977
There is no simple way to check for compiler options so check
whether the new CSS selectors are being used . If so , it should find
canvas # [ id ] which is any canvas with the ID of Module . canvas .
The old target behavior will look for an element with id = " canvas#[id] "
which could theoretically exist but that ' s highly unlikely . */
bool deprecated = true ;
# ifdef EMSCRIPTEN_EVENT_TARGET_WINDOW
Vector2d tempSize ;
if ( emscripten_get_element_css_size ( ( " canvas# " + canvasId ( ) ) . data ( ) , & tempSize . x ( ) , & tempSize . y ( ) ) > = 0 ) {
deprecated = false ;
}
# endif
return deprecated ;
}
std : : string EmscriptenApplication : : canvasId ( ) {
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
char * id = reinterpret_cast < char * > ( EM_ASM_INT ( {
return allocate ( intArrayFromString ( Module [ ' canvas ' ] . id ) , ' i8 ' , ALLOC_NORMAL ) ;
} ) ) ;
# pragma GCC diagnostic pop
std : : string str = id ;
std : : free ( id ) ;
return str ;
}
EmscriptenApplication : : MouseEvent : : Button EmscriptenApplication : : MouseEvent : : button ( ) const {
EmscriptenApplication : : MouseEvent : : Button EmscriptenApplication : : MouseEvent : : button ( ) const {
return Button ( _event . button ) ;
return Button ( _event . button ) ;
}
}