Commit 81479d8784d0e1a61eafb3a444dd3865ad762fb2

David Gow 2022-11-18T21:08:36

wayland: keyboard: Cache text input parameters. Some applications (and embarrassingly, testime is one of them) call SDL_StartTextInput() or SDL_SetTextInputRect() every frame. On KDE/KWin with fcitx5, this causes there to be several preedit events every frame (particularly given some of the workarounds in Wayland_StartTextInput), which slows testime down to an unusable crawl. Instead, make SDL_StartTextInput() a no-op if text input is already enabled, and cache the input rect, only changing it when the new rect is actually different. With these changes, we only get preedit events (and hence SDL_TEXTEDITING events) when the preedit string actually changes. This matches the behaviour under XWayland, and works very smoothly.

diff --git a/src/video/wayland/SDL_waylandkeyboard.c b/src/video/wayland/SDL_waylandkeyboard.c
index 6f6115d..5cea5ef 100644
--- a/src/video/wayland/SDL_waylandkeyboard.c
+++ b/src/video/wayland/SDL_waylandkeyboard.c
@@ -61,6 +61,10 @@ Wayland_StartTextInput(_THIS)
         if (input != NULL && input->text_input) {
             const SDL_Rect *rect = &input->text_input->cursor_rect;
 
+            /* Don't re-enable if we're already enabled. */
+            if (input->text_input->is_enabled)
+                return;
+
             /* For some reason this has to be done twice, it appears to be a
              * bug in mutter? Maybe?
              * -flibit
@@ -83,6 +87,7 @@ Wayland_StartTextInput(_THIS)
                                                        rect->h);
             }
             zwp_text_input_v3_commit(input->text_input->text_input);
+            input->text_input->is_enabled = SDL_TRUE;
         }
     }
 }
@@ -97,6 +102,7 @@ Wayland_StopTextInput(_THIS)
         if (input != NULL && input->text_input) {
             zwp_text_input_v3_disable(input->text_input->text_input);
             zwp_text_input_v3_commit(input->text_input->text_input);
+            input->text_input->is_enabled = SDL_FALSE;
         }
     }
 
@@ -120,13 +126,16 @@ Wayland_SetTextInputRect(_THIS, const SDL_Rect *rect)
     if (driverdata->text_input_manager) {
         struct SDL_WaylandInput *input = driverdata->input;
         if (input != NULL && input->text_input) {
-            SDL_copyp(&input->text_input->cursor_rect, rect);
-            zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
-                                                   rect->x,
-                                                   rect->y,
-                                                   rect->w,
-                                                   rect->h);
-            zwp_text_input_v3_commit(input->text_input->text_input);
+            if (!SDL_RectEquals(rect, &input->text_input->cursor_rect))
+            {
+                SDL_copyp(&input->text_input->cursor_rect, rect);
+                zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
+                                                       rect->x,
+                                                       rect->y,
+                                                       rect->w,
+                                                       rect->h);
+                zwp_text_input_v3_commit(input->text_input->text_input);
+            }
         }
     }
 
diff --git a/src/video/wayland/SDL_waylandkeyboard.h b/src/video/wayland/SDL_waylandkeyboard.h
index 5909a24..a56ccba 100644
--- a/src/video/wayland/SDL_waylandkeyboard.h
+++ b/src/video/wayland/SDL_waylandkeyboard.h
@@ -28,6 +28,7 @@ typedef struct SDL_WaylandTextInput
     struct zwp_text_input_v3 *text_input;
     SDL_Rect cursor_rect;
     SDL_bool has_preedit;
+    SDL_bool is_enabled;
 } SDL_WaylandTextInput;
 
 extern int Wayland_InitKeyboard(_THIS);