2525#include "../SDL_sysvideo.h"
2626#include "../SDL_pixels_c.h"
2727#include "../../events/SDL_events_c.h"
28+ #include "../../SDL_hints_c.h"
2829
2930#include "SDL_emscriptenvideo.h"
3031#include "SDL_emscriptenopengles.h"
@@ -50,14 +51,18 @@ static void Emscripten_PumpEvents(SDL_VideoDevice *_this);
5051static void Emscripten_SetWindowTitle (SDL_VideoDevice * _this , SDL_Window * window );
5152static bool Emscripten_SetWindowIcon (SDL_VideoDevice * _this , SDL_Window * window , SDL_Surface * icon );
5253
54+ SDL_Window * Emscripten_fill_document_window = NULL ;
55+
5356static bool pumpevents_has_run = false;
5457static int pending_swap_interval = -1 ;
5558
56-
5759// Emscripten driver bootstrap functions
5860
61+ static void SDLCALL Emscripten_FillDocHintChanged (void * userdata , const char * name , const char * oldValue , const char * hint );
62+
5963static void Emscripten_DeleteDevice (SDL_VideoDevice * device )
6064{
65+ SDL_RemoveHintCallback (SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT , Emscripten_FillDocHintChanged , device );
6166 SDL_free (device );
6267}
6368
@@ -192,6 +197,8 @@ static SDL_VideoDevice *Emscripten_CreateDevice(void)
192197 Emscripten_ListenSystemTheme ();
193198 device -> system_theme = Emscripten_GetSystemTheme ();
194199
200+ SDL_AddHintCallback (SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT , Emscripten_FillDocHintChanged , device );
201+
195202 return device ;
196203}
197204
@@ -456,65 +463,29 @@ EMSCRIPTEN_KEEPALIVE void requestFullscreenThroughSDL(SDL_Window *window)
456463 SDL_SetWindowFullscreen (window , true);
457464}
458465
459- static bool Emscripten_CreateWindow ( SDL_VideoDevice * _this , SDL_Window * window , SDL_PropertiesID props )
466+ static void Emscripten_SetWindowFillDocState ( SDL_Window * window , bool enable )
460467{
461- SDL_WindowData * wdata ;
462- double scaled_w , scaled_h ;
463- double css_w , css_h ;
464- const char * selector ;
468+ SDL_WindowData * wdata = window -> internal ;
465469
466- // Allocate window internal data
467- wdata = (SDL_WindowData * )SDL_calloc (1 , sizeof (SDL_WindowData ));
468- if (!wdata ) {
469- return false;
470- }
471-
472- selector = SDL_GetHint (SDL_HINT_EMSCRIPTEN_CANVAS_SELECTOR );
473- if (!selector || !* selector ) {
474- selector = SDL_GetStringProperty (props , SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING , "#canvas" );
475- }
476- wdata -> canvas_id = SDL_strdup (selector );
477-
478- selector = SDL_GetHint (SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT );
479- if (!selector || !* selector ) {
480- selector = SDL_GetStringProperty (props , SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING , "#window" );
481- }
482- wdata -> keyboard_element = SDL_strdup (selector );
483-
484- if (SDL_GetHint (SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT )) {
485- wdata -> fill_document = SDL_GetHintBoolean (SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT , false);
486- } else {
487- wdata -> fill_document = SDL_GetBooleanProperty (props , SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN , false);
488- }
489-
490- if (window -> flags & SDL_WINDOW_HIGH_PIXEL_DENSITY ) {
491- wdata -> pixel_ratio = emscripten_get_device_pixel_ratio ();
492- } else {
493- wdata -> pixel_ratio = 1.0f ;
494- }
495-
496- scaled_w = SDL_floor (window -> w * wdata -> pixel_ratio );
497- scaled_h = SDL_floor (window -> h * wdata -> pixel_ratio );
498-
499- // set a fake size to check if there is any CSS sizing the canvas
500- emscripten_set_canvas_element_size (wdata -> canvas_id , 1 , 1 );
501- emscripten_get_element_css_size (wdata -> canvas_id , & css_w , & css_h );
502-
503- wdata -> external_size = SDL_floor (css_w ) != 1 || SDL_floor (css_h ) != 1 ;
504- if (wdata -> external_size ) {
505- wdata -> fill_document = false; // can't be resizable if something else is controlling it.
506- }
470+ SDL_assert (!Emscripten_fill_document_window || !enable ); // one at a time, sorry.
507471
508472 // fill_document takes up the entire page and resizes as the browser window resizes.
509- if (wdata -> fill_document ) {
473+ if (enable ) {
474+ Emscripten_fill_document_window = window ;
475+
510476 const int w = MAIN_THREAD_EM_ASM_INT ({ return window .innerWidth ; });
511477 const int h = MAIN_THREAD_EM_ASM_INT ({ return window .innerHeight ; });
478+ const double scaled_w = w * wdata -> pixel_ratio ;
479+ const double scaled_h = h * wdata -> pixel_ratio ;
512480
513- scaled_w = w * wdata -> pixel_ratio ;
514- scaled_h = h * wdata -> pixel_ratio ;
481+ wdata -> non_fill_document_width = window -> w ;
482+ wdata -> non_fill_document_height = window -> h ;
515483
516484 MAIN_THREAD_EM_ASM ({
517485 var canvas = document .querySelector (UTF8ToString ($0 ));
486+ canvas .SDL3_original_position = canvas .style .position ;
487+ canvas .SDL3_original_top = canvas .style .top ;
488+ canvas .SDL3_original_left = canvas .style .left ;
518489
519490 // hide everything on the page that isn't the canvas.
520491 var div = document .createElement ('div' );
@@ -547,20 +518,119 @@ static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window,
547518 window -> w = window -> h = 0 ;
548519 SDL_SendWindowEvent (window , SDL_EVENT_WINDOW_RESIZED , SDL_lroundf (w ), SDL_lroundf (h ));
549520 } else {
521+ const bool transitioning = (Emscripten_fill_document_window == window );
522+ if (transitioning ) {
523+ MAIN_THREAD_EM_ASM ({
524+ // if we had previously hidden everything behind a fill_document window, put it back.
525+ var div = document .getElementById ('SDL3_fill_document_background_elements' );
526+ if (div ) {
527+ if (div .SDL3_canvas_nextsib ) {
528+ div .SDL3_canvas_parent .insertBefore (div .SDL3_canvas , div .SDL3_canvas_nextsib );
529+ } else {
530+ div .SDL3_canvas_parent .appendChild (div .SDL3_canvas );
531+ }
532+ while (div .firstChild ) {
533+ document .body .insertBefore (div .firstChild , div );
534+ }
535+ div .SDL3_canvas .style .position = div .SDL3_canvas .SDL3_original_position ;
536+ div .SDL3_canvas .style .top = div .SDL3_canvas .SDL3_original_top ;
537+ div .SDL3_canvas .style .left = div .SDL3_canvas .SDL3_original_left ;
538+ div .remove ();
539+ }
540+ });
541+ Emscripten_fill_document_window = NULL ;
542+ }
543+
544+ window -> w = wdata -> non_fill_document_width ;
545+ window -> h = wdata -> non_fill_document_height ;
546+ const double scaled_w = SDL_floor (window -> w * wdata -> pixel_ratio );
547+ const double scaled_h = SDL_floor (window -> h * wdata -> pixel_ratio );
550548 emscripten_set_canvas_element_size (wdata -> canvas_id , SDL_lroundf (scaled_w ), SDL_lroundf (scaled_h ));
551549
552550 // if the size is not being controlled by css, we need to scale down for hidpi
553551 if (!wdata -> external_size && (wdata -> pixel_ratio != 1.0f )) {
554552 // scale canvas down
555553 emscripten_set_element_css_size (wdata -> canvas_id , window -> w , window -> h );
556554 }
555+
556+ if (transitioning ) {
557+ window -> w = window -> h = 0 ;
558+ SDL_SendWindowEvent (window , SDL_EVENT_WINDOW_RESIZED , wdata -> non_fill_document_width , wdata -> non_fill_document_height );
559+ }
560+ }
561+ }
562+
563+ static void SDLCALL Emscripten_FillDocHintChanged (void * userdata , const char * name , const char * oldValue , const char * hint )
564+ {
565+ const bool enabled = SDL_GetStringBoolean (hint , false);
566+ if (Emscripten_fill_document_window && !enabled ) {
567+ Emscripten_SetWindowFillDocState (Emscripten_fill_document_window , false);
568+ } else if (!Emscripten_fill_document_window && enabled ) {
569+ /// there's currently only ever one canvas, but if this changes later, we can choose the one with keyboard focus or something.
570+ SDL_VideoDevice * device = (SDL_VideoDevice * ) userdata ;
571+ if (device && device -> windows ) { // take first window in the list for now.
572+ Emscripten_SetWindowFillDocState (device -> windows , true);
573+ }
574+ }
575+ }
576+
577+ static bool Emscripten_CreateWindow (SDL_VideoDevice * _this , SDL_Window * window , SDL_PropertiesID props )
578+ {
579+ SDL_WindowData * wdata ;
580+ double css_w , css_h ;
581+ const char * selector ;
582+
583+ // Allocate window internal data
584+ wdata = (SDL_WindowData * )SDL_calloc (1 , sizeof (SDL_WindowData ));
585+ if (!wdata ) {
586+ return false;
587+ }
588+
589+ selector = SDL_GetHint (SDL_HINT_EMSCRIPTEN_CANVAS_SELECTOR );
590+ if (!selector || !* selector ) {
591+ selector = SDL_GetStringProperty (props , SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING , "#canvas" );
592+ }
593+ wdata -> canvas_id = SDL_strdup (selector );
594+
595+ selector = SDL_GetHint (SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT );
596+ if (!selector || !* selector ) {
597+ selector = SDL_GetStringProperty (props , SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING , "#window" );
598+ }
599+ wdata -> keyboard_element = SDL_strdup (selector );
600+
601+ bool fill_document ;
602+ if (Emscripten_fill_document_window ) {
603+ fill_document = false; // only one allowed at a time.
604+ } else if (SDL_GetHint (SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT )) {
605+ fill_document = SDL_GetHintBoolean (SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT , false);
606+ } else {
607+ fill_document = SDL_GetBooleanProperty (props , SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN , false);
608+ }
609+
610+ if (window -> flags & SDL_WINDOW_HIGH_PIXEL_DENSITY ) {
611+ wdata -> pixel_ratio = emscripten_get_device_pixel_ratio ();
612+ } else {
613+ wdata -> pixel_ratio = 1.0f ;
614+ }
615+
616+ // set a fake size to check if there is any CSS sizing the canvas
617+ emscripten_set_canvas_element_size (wdata -> canvas_id , 1 , 1 );
618+ emscripten_get_element_css_size (wdata -> canvas_id , & css_w , & css_h );
619+
620+ wdata -> external_size = SDL_floor (css_w ) != 1 || SDL_floor (css_h ) != 1 ;
621+ if (wdata -> external_size ) {
622+ fill_document = false; // can't be resizable if something else is controlling it.
557623 }
558624
559625 wdata -> window = window ;
560626
561627 // Setup driver data for this window
562628 window -> internal = wdata ;
563629
630+ wdata -> non_fill_document_width = window -> w ;
631+ wdata -> non_fill_document_height = window -> h ;
632+ Emscripten_SetWindowFillDocState (window , fill_document );
633+
564634 // One window, it always has focus
565635 SDL_SetMouseFocus (window );
566636 SDL_SetKeyboardFocus (window );
@@ -577,7 +647,7 @@ static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window,
577647 // Ensure various things are added to the window's properties
578648 SDL_SetStringProperty (window -> props , SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING , wdata -> canvas_id );
579649 SDL_SetStringProperty (window -> props , SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING , wdata -> keyboard_element );
580- SDL_SetBooleanProperty (window -> props , SDL_PROP_WINDOW_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN , wdata -> fill_document );
650+ SDL_SetBooleanProperty (window -> props , SDL_PROP_WINDOW_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN , fill_document );
581651
582652 // Window has been successfully created
583653 return true;
@@ -592,7 +662,7 @@ static void Emscripten_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
592662{
593663 if (window -> internal ) {
594664 SDL_WindowData * data = window -> internal ;
595- if (data -> fill_document ) {
665+ if (window == Emscripten_fill_document_window ) {
596666 return ; // canvas size is being dictated by the browser window size, refuse request.
597667 }
598668
@@ -625,6 +695,10 @@ static void Emscripten_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
625695{
626696 SDL_WindowData * data ;
627697
698+ if (Emscripten_fill_document_window == window ) {
699+ Emscripten_SetWindowFillDocState (window , false);
700+ }
701+
628702 if (window -> internal ) {
629703 data = window -> internal ;
630704
@@ -646,23 +720,6 @@ static void Emscripten_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
646720 MAIN_THREAD_EM_ASM ({
647721 // just ignore clicks on the fullscreen button while there's no SDL window.
648722 Module ['requestFullscreen' ] = function (lockPointer , resizeCanvas ) {};
649-
650- // if we had previously hidden everything behind a fill_document window, put it back.
651- var div = document .getElementById ('SDL3_fill_document_background_elements' );
652- if (div ) {
653- if (div .SDL3_canvas_nextsib ) {
654- div .SDL3_canvas_parent .insertBefore (div .SDL3_canvas , div .SDL3_canvas_nextsib );
655- } else {
656- div .SDL3_canvas_parent .appendChild (div .SDL3_canvas );
657- }
658- while (div .firstChild ) {
659- document .body .insertBefore (div .firstChild , div );
660- }
661- div .SDL3_canvas .style .position = undefined ;
662- div .SDL3_canvas .style .top = undefined ;
663- div .SDL3_canvas .style .left = undefined ;
664- div .remove ();
665- }
666723 });
667724}
668725
0 commit comments