Handling Window Resizing in the SDL2 Emscripten Port

I've updated the CMake + SDL2 + Emscripten sample project to handle window resizing, along with device pixel ratio scaling in a mobile web environment. The recent version 1.1 update also introduces a CMakePresets.json file that works well with Visual Studio and VS Code.

You can find the sample project over on my cmake-testing-grounds repository, in the sdl2-emscripten folder. There are two separate projects in the sdl2-emsdk-fullscreen-tests folder that can be used as a basis for testing the mobile web environment.

How the SDL2 Emscripten Port Handles Window Resizing

This is a summary of my understanding on how the SDL2 Emscripten Port handles window resizing.

If the SDL_WINDOW_RESIZABLE flag is turned on:

  • SDL internally listens for resize events.
  • SDL automatically updates the canvas element CSS size, and SDL_Window size, based on window resize events.
  • SDL does not automatically perform device pixel ratio scaling.

If the SDL_WINDOW_RESIZABLE flag is left off:

  • SDL does not listen for resize events.
  • Your application must keep the canvas and SDL_Window sizes in sync.

Device Pixel Ratio

Mobile devices will often pack multiple physical pixels into a single CSS pixel. This is referred to as the device pixel ratio. You can query the device pixel ratio one of two ways:

  • In JavaScript, with the Window.devicePixelRatio property.
  • In C/C++, with the emscripten_get_device_pixel_ratio function.

See the emscripten.h documentation for official information.

For applications that want to take control of the canvas and window size, the following code block can be used to handle device pixel ratio as part of a window resize handler:

double canvasCssWidth = 0.0, canvasCssHeight = 0.0;
emscripten_get_element_css_size("#canvas", &canvasCssWidth, &canvasCssHeight);
double dpr = emscripten_get_device_pixel_ratio();

int canvasWidth = (int)std::floor(canvasCssWidth * dpr);
int canvasHeight = (int)std::floor(canvasCssHeight * dpr);

emscripten_set_canvas_element_size("#canvas", canvasWidth, canvasHeight);
SDL_SetWindowSize(this->window, canvasWidth, canvasHeight);

Hard vs. Soft Fullscreen

A "hard" fullscreen toggle can be achieved by calling SDL_SetWindowFullscreen with the SDL_WINDOW_FULLSCREEN_DESKTOP flag.

A "soft" fullscreen toggle in the mobile web environment involves hiding HTML elements using CSS styles.

Failsafes

In my experience, it's possible that the canvas and window can go out of sync with one another on mobile devices. You can implement a failsafe to recover from this as follows:

  • Choose some event (such as mouse button or touch events) to detect whether the canvas and window are a difference size. Use emscripten_get_canvas_element_size and SDL_GetWindowSize for this purpose.
  • If they have gone out of sync, and the user is currently in fullscreen mode, then at a minimum toggle back out of fullscreen. Without this, the user may not know how to get control back of their mobile device.
  • Consider informing the user in some way that an unexpected issue was detected.

Conclusion

Check out my cmake-testing-grounds repository for sample projects related to CMake, SDL2, and Emscripten.