wayland: Only create/destroy the compose table when necessary

Initializing the compose table is a very expensive operation, and only necessary if the locale envvar changed, which is often not the case when just changing the keymap, so don't destroy and recreate it whenever the keymap changes. The state only needs to be reset in this case.
This commit is contained in:
Frank Praznik
2025-07-11 11:10:09 -04:00
parent 9b00f3a728
commit 9c9bb9cec7
2 changed files with 33 additions and 19 deletions

View File

@@ -1495,7 +1495,6 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
{
SDL_WaylandSeat *seat = data;
char *map_str;
const char *locale;
if (!data) {
close(fd);
@@ -1588,7 +1587,7 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
*/
// Look up the preferred locale, falling back to "C" as default
locale = SDL_getenv("LC_ALL");
const char *locale = SDL_getenv("LC_ALL");
if (!locale) {
locale = SDL_getenv("LC_CTYPE");
if (!locale) {
@@ -1599,26 +1598,38 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
}
}
// Set up XKB compose table
if (seat->keyboard.xkb.compose_table != NULL) {
WAYLAND_xkb_compose_table_unref(seat->keyboard.xkb.compose_table);
seat->keyboard.xkb.compose_table = NULL;
}
seat->keyboard.xkb.compose_table = WAYLAND_xkb_compose_table_new_from_locale(seat->display->xkb_context,
locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
if (seat->keyboard.xkb.compose_table) {
// Set up XKB compose state
if (seat->keyboard.xkb.compose_state != NULL) {
WAYLAND_xkb_compose_state_unref(seat->keyboard.xkb.compose_state);
seat->keyboard.xkb.compose_state = NULL;
}
seat->keyboard.xkb.compose_state = WAYLAND_xkb_compose_state_new(seat->keyboard.xkb.compose_table,
XKB_COMPOSE_STATE_NO_FLAGS);
if (!seat->keyboard.xkb.compose_state) {
SDL_SetError("could not create XKB compose state");
/* Set up the XKB compose table.
*
* This is a very slow operation, so it is only done during initialization,
* or if the locale envvar changed during runtime.
*/
if (!seat->keyboard.current_locale || SDL_strcmp(seat->keyboard.current_locale, locale) != 0) {
// Cache the current locale for later comparison.
SDL_free(seat->keyboard.current_locale);
seat->keyboard.current_locale = SDL_strdup(locale);
if (seat->keyboard.xkb.compose_table != NULL) {
WAYLAND_xkb_compose_table_unref(seat->keyboard.xkb.compose_table);
seat->keyboard.xkb.compose_table = NULL;
}
seat->keyboard.xkb.compose_table = WAYLAND_xkb_compose_table_new_from_locale(seat->display->xkb_context,
locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
if (seat->keyboard.xkb.compose_table) {
// Set up XKB compose state
if (seat->keyboard.xkb.compose_state != NULL) {
WAYLAND_xkb_compose_state_unref(seat->keyboard.xkb.compose_state);
seat->keyboard.xkb.compose_state = NULL;
}
seat->keyboard.xkb.compose_state = WAYLAND_xkb_compose_state_new(seat->keyboard.xkb.compose_table,
XKB_COMPOSE_STATE_NO_FLAGS);
if (!seat->keyboard.xkb.compose_state) {
SDL_SetError("could not create XKB compose state");
WAYLAND_xkb_compose_table_unref(seat->keyboard.xkb.compose_table);
seat->keyboard.xkb.compose_table = NULL;
}
}
} else if (seat->keyboard.xkb.compose_state) {
WAYLAND_xkb_compose_state_reset(seat->keyboard.xkb.compose_state);
}
}
@@ -2216,6 +2227,8 @@ static void Wayland_SeatDestroyKeyboard(SDL_WaylandSeat *seat, bool send_event)
}
}
SDL_free(seat->keyboard.current_locale);
if (seat->keyboard.xkb.compose_state) {
WAYLAND_xkb_compose_state_unref(seat->keyboard.xkb.compose_state);
}

View File

@@ -76,6 +76,7 @@ typedef struct SDL_WaylandSeat
struct zwp_keyboard_shortcuts_inhibitor_v1 *key_inhibitor;
SDL_WindowData *focus;
SDL_Keymap *sdl_keymap;
char *current_locale;
SDL_WaylandKeyboardRepeat repeat;
Uint64 highres_timestamp_ns;