From 7ddda4fe18222c3a3561e9e576535bc6341ac464 Mon Sep 17 00:00:00 2001
From: Semphris <[EMAIL REDACTED]>
Date: Wed, 4 Dec 2024 21:45:58 -0500
Subject: [PATCH] Add system theme support for Emscripten
---
src/video/emscripten/SDL_emscriptenvideo.c | 75 ++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/src/video/emscripten/SDL_emscriptenvideo.c b/src/video/emscripten/SDL_emscriptenvideo.c
index 02b193c7f1a85..d7515bb2f08f2 100644
--- a/src/video/emscripten/SDL_emscriptenvideo.c
+++ b/src/video/emscripten/SDL_emscriptenvideo.c
@@ -55,6 +55,77 @@ static void Emscripten_DeleteDevice(SDL_VideoDevice *device)
SDL_free(device);
}
+static SDL_SystemTheme Emscripten_GetSystemTheme(void)
+{
+ /* Technically, light theme can mean explicit light theme or no preference.
+ https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme#syntax */
+
+ int theme_code = EM_ASM_INT({
+ if (!window.matchMedia) {
+ return -1;
+ }
+
+ if (window.matchMedia('(prefers-color-scheme: light)').matches) {
+ return 0;
+ }
+
+ if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ return 1;
+ }
+
+ return -1;
+ });
+
+ switch (theme_code) {
+ case 0:
+ return SDL_SYSTEM_THEME_LIGHT;
+
+ case 1:
+ return SDL_SYSTEM_THEME_DARK;
+
+ default:
+ return SDL_SYSTEM_THEME_UNKNOWN;
+ }
+}
+
+static void Emscripten_ListenSystemTheme(void)
+{
+ MAIN_THREAD_EM_ASM({
+ if (window.matchMedia) {
+ if (typeof(Module['SDL3']) === 'undefined') {
+ Module['SDL3'] = {};
+ }
+
+ var SDL3 = Module['SDL3'];
+
+ SDL3.eventHandlerThemeChanged = function(event) {
+ _Emscripten_SendSystemThemeChangedEvent();
+ };
+
+ SDL3.themeChangedMatchMedia = window.matchMedia('(prefers-color-scheme: dark)');
+ SDL3.themeChangedMatchMedia.addEventListener('change', SDL3.eventHandlerThemeChanged);
+ }
+ });
+}
+
+static void Emscripten_UnlistenSystemTheme(void)
+{
+ MAIN_THREAD_EM_ASM({
+ if (typeof(Module['SDL3']) !== 'undefined') {
+ var SDL3 = Module['SDL3'];
+
+ SDL3.themeChangedMatchMedia.removeEventListener('change', SDL3.eventHandlerThemeChanged);
+ SDL3.themeChangedMatchMedia = undefined;
+ SDL3.eventHandlerThemeChanged = undefined;
+ }
+ });
+}
+
+EMSCRIPTEN_KEEPALIVE void Emscripten_SendSystemThemeChangedEvent(void)
+{
+ SDL_SetSystemTheme(Emscripten_GetSystemTheme());
+}
+
static SDL_VideoDevice *Emscripten_CreateDevice(void)
{
SDL_VideoDevice *device;
@@ -111,6 +182,9 @@ static SDL_VideoDevice *Emscripten_CreateDevice(void)
device->free = Emscripten_DeleteDevice;
+ Emscripten_ListenSystemTheme();
+ device->system_theme = Emscripten_GetSystemTheme();
+
return device;
}
@@ -153,6 +227,7 @@ static bool Emscripten_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *
static void Emscripten_VideoQuit(SDL_VideoDevice *_this)
{
Emscripten_QuitMouse();
+ Emscripten_UnlistenSystemTheme();
}
static bool Emscripten_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)