From d317fc9c080a233b24982f99197c20ff653882c3 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 17 Jan 2025 17:57:44 -0500 Subject: [PATCH] emscripten: resizable windows take whole page, resize with browser window. This also implements the SetWindowResizable interface, so this can be now toggled after window creation, too. Fixes #11949. --- src/video/emscripten/SDL_emscriptenevents.c | 9 +- src/video/emscripten/SDL_emscriptenvideo.c | 92 ++++++++++++++------- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/src/video/emscripten/SDL_emscriptenevents.c b/src/video/emscripten/SDL_emscriptenevents.c index 834bca8beb..c9437a9412 100644 --- a/src/video/emscripten/SDL_emscriptenevents.c +++ b/src/video/emscripten/SDL_emscriptenevents.c @@ -624,14 +624,9 @@ static EM_BOOL Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *u } if (!(window_data->window->flags & SDL_WINDOW_FULLSCREEN)) { - // this will only work if the canvas size is set through css if (window_data->window->flags & SDL_WINDOW_RESIZABLE) { - double w = window_data->window->w; - double h = window_data->window->h; - - if (window_data->external_size) { - emscripten_get_element_css_size(window_data->canvas_id, &w, &h); - } + const double w = (double) uiEvent->windowInnerWidth; + const double h = (double) uiEvent->windowInnerHeight; emscripten_set_canvas_element_size(window_data->canvas_id, SDL_lroundf(w * window_data->pixel_ratio), SDL_lroundf(h * window_data->pixel_ratio)); diff --git a/src/video/emscripten/SDL_emscriptenvideo.c b/src/video/emscripten/SDL_emscriptenvideo.c index 413d96fc60..91c954874b 100644 --- a/src/video/emscripten/SDL_emscriptenvideo.c +++ b/src/video/emscripten/SDL_emscriptenvideo.c @@ -47,6 +47,7 @@ static void Emscripten_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) static SDL_FullscreenResult Emscripten_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen); static void Emscripten_PumpEvents(SDL_VideoDevice *_this); static void Emscripten_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window); +static void Emscripten_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable); static bool pumpevents_has_run = false; static int pending_swap_interval = -1; @@ -156,6 +157,7 @@ static SDL_VideoDevice *Emscripten_CreateDevice(void) device->CreateSDLWindow = Emscripten_CreateWindow; device->SetWindowTitle = Emscripten_SetWindowTitle; + device->SetWindowResizable = Emscripten_SetWindowResizable; /*device->SetWindowIcon = Emscripten_SetWindowIcon; device->SetWindowPosition = Emscripten_SetWindowPosition;*/ device->SetWindowSize = Emscripten_SetWindowSize; @@ -281,8 +283,6 @@ EMSCRIPTEN_KEEPALIVE void requestFullscreenThroughSDL(SDL_Window *window) static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props) { SDL_WindowData *wdata; - double scaled_w, scaled_h; - double css_w, css_h; const char *selector; // Allocate window internal data @@ -304,44 +304,20 @@ static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, wdata->pixel_ratio = 1.0f; } - scaled_w = SDL_floor(window->w * wdata->pixel_ratio); - scaled_h = SDL_floor(window->h * wdata->pixel_ratio); - - // set a fake size to check if there is any CSS sizing the canvas - emscripten_set_canvas_element_size(wdata->canvas_id, 1, 1); - emscripten_get_element_css_size(wdata->canvas_id, &css_w, &css_h); - - wdata->external_size = SDL_floor(css_w) != 1 || SDL_floor(css_h) != 1; - - if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) { - // external css has resized us - scaled_w = css_w * wdata->pixel_ratio; - scaled_h = css_h * wdata->pixel_ratio; - - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, SDL_lroundf(css_w), SDL_lroundf(css_h)); - } - emscripten_set_canvas_element_size(wdata->canvas_id, SDL_lroundf(scaled_w), SDL_lroundf(scaled_h)); - - // if the size is not being controlled by css, we need to scale down for hidpi - if (!wdata->external_size) { - if (wdata->pixel_ratio != 1.0f) { - // scale canvas down - emscripten_set_element_css_size(wdata->canvas_id, window->w, window->h); - } - } - wdata->window = window; // Setup driver data for this window window->internal = wdata; + Emscripten_SetWindowResizable(_this, window, (window->flags & SDL_WINDOW_RESIZABLE) != 0); + // One window, it always has focus SDL_SetMouseFocus(window); SDL_SetKeyboardFocus(window); Emscripten_RegisterEventHandlers(wdata); - // disable the emscripten "fullscreen" button. + // Make the emscripten "fullscreen" button go through SDL. MAIN_THREAD_EM_ASM({ Module['requestFullscreen'] = function(lockPointer, resizeCanvas) { _requestFullscreenThroughSDL($0); @@ -354,10 +330,12 @@ static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, static void Emscripten_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) { - SDL_WindowData *data; + if ((window->flags & SDL_WINDOW_RESIZABLE) == 0) { + return; // canvas size is being dictated by the browser window size, refuse request. + } if (window->internal) { - data = window->internal; + SDL_WindowData *data = window->internal; // update pixel ratio if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) { data->pixel_ratio = emscripten_get_device_pixel_ratio(); @@ -455,4 +433,56 @@ static void Emscripten_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window emscripten_set_window_title(window->title); } +static void Emscripten_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable) +{ + SDL_WindowData *wdata = window->internal; + double scaled_w = SDL_floor(window->w * wdata->pixel_ratio); + double scaled_h = SDL_floor(window->h * wdata->pixel_ratio); + double css_w, css_h; + + // set a fake size to check if there is any CSS sizing the canvas + emscripten_set_canvas_element_size(wdata->canvas_id, 1, 1); + emscripten_get_element_css_size(wdata->canvas_id, &css_w, &css_h); + + wdata->external_size = SDL_floor(css_w) != 1 || SDL_floor(css_h) != 1; + if (wdata->external_size) { + window->flags &= ~SDL_WINDOW_RESIZABLE; // can't be resizable if something else is controlling it. + } + + // SDL_WINDOW_RESIZABLE takes up the entire page and resizes as the browser window resizes. + if (window->flags & SDL_WINDOW_RESIZABLE) { + const double w = (double) MAIN_THREAD_EM_ASM_INT({ return window.innerWidth; }); + const double h = (double) MAIN_THREAD_EM_ASM_INT({ return window.innerHeight; }); + + scaled_w = w * wdata->pixel_ratio; + scaled_h = h * wdata->pixel_ratio; + + MAIN_THREAD_EM_ASM({ + var canvas = document.querySelector(UTF8ToString($0)); + canvas.style.position = 'absolute'; + canvas.style.top = '0'; + canvas.style.right = '0'; + }, wdata->canvas_id); + + SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, SDL_lroundf(scaled_w), SDL_lroundf(scaled_h)); + } else { + MAIN_THREAD_EM_ASM({ + var canvas = document.querySelector(UTF8ToString($0)); + canvas.style.position = undefined; + canvas.style.top = undefined; + canvas.style.right = undefined; + }, wdata->canvas_id); + } + + emscripten_set_canvas_element_size(wdata->canvas_id, SDL_lroundf(scaled_w), SDL_lroundf(scaled_h)); + + // if the size is not being controlled by css, we need to scale down for hidpi + if (!wdata->external_size) { + if (wdata->pixel_ratio != 1.0f) { + // scale canvas down + emscripten_set_element_css_size(wdata->canvas_id, window->w, window->h); + } + } +} + #endif // SDL_VIDEO_DRIVER_EMSCRIPTEN