SDL: wayland: Set the text input cursor rect properly (195f7)

From 195f709eda95668807411ed235cb477e1511974e Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Tue, 20 May 2025 13:42:21 -0400
Subject: [PATCH] wayland: Set the text input cursor rect properly

The text input cursor should reflect the cursor position, not the entire text input rect. Set it correctly so that IME chooser dialogs appear in the correct location.

(cherry-picked from commit c7549eb0b61309992df8cd00f17e0d63ba6e3895)
---
 src/video/wayland/SDL_waylandkeyboard.c | 44 ++++++++++++++++++-------
 src/video/wayland/SDL_waylandkeyboard.h |  3 +-
 2 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/src/video/wayland/SDL_waylandkeyboard.c b/src/video/wayland/SDL_waylandkeyboard.c
index df1628cd5b820..6712f9d8c4bbc 100644
--- a/src/video/wayland/SDL_waylandkeyboard.c
+++ b/src/video/wayland/SDL_waylandkeyboard.c
@@ -58,7 +58,7 @@ bool Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_Prop
 
     if (internal->text_input_manager) {
         if (input && input->text_input) {
-            const SDL_Rect *rect = &input->text_input->cursor_rect;
+            const SDL_Rect *rect = &input->text_input->text_input_rect;
             enum zwp_text_input_v3_content_hint hint = ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE;
             enum zwp_text_input_v3_content_purpose purpose;
 
@@ -125,12 +125,21 @@ bool Wayland_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_Prop
             // Now that it's enabled, set the input properties
             zwp_text_input_v3_set_content_type(input->text_input->text_input, hint, purpose);
             if (!SDL_RectEmpty(rect)) {
-                // This gets reset on enable so we have to cache it
+                SDL_WindowData *wind = window->internal;
+                const SDL_Rect scaled_rect = {
+                    (int)SDL_floor(window->text_input_rect.x / wind->pointer_scale.x),
+                    (int)SDL_floor(window->text_input_rect.y / wind->pointer_scale.y),
+                    (int)SDL_ceil(window->text_input_rect.w / wind->pointer_scale.x),
+                    (int)SDL_ceil(window->text_input_rect.h / wind->pointer_scale.y)
+                };
+                const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / wind->pointer_scale.x);
+
+                // Clamp the x value so it doesn't run too far past the end of the text input area.
                 zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
-                                                       rect->x,
-                                                       rect->y,
-                                                       rect->w,
-                                                       rect->h);
+                                                       SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w),
+                                                       scaled_rect.y,
+                                                       1,
+                                                       scaled_rect.h);
             }
             zwp_text_input_v3_commit(input->text_input->text_input);
         }
@@ -174,13 +183,24 @@ bool Wayland_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
     if (internal->text_input_manager) {
         struct SDL_WaylandInput *input = internal->input;
         if (input && input->text_input) {
-            if (!SDL_RectsEqual(&window->text_input_rect, &input->text_input->cursor_rect)) {
-                SDL_copyp(&input->text_input->cursor_rect, &window->text_input_rect);
+            SDL_WindowData *wind = window->internal;
+            const SDL_Rect scaled_rect = {
+                (int)SDL_floor(window->text_input_rect.x / wind->pointer_scale.x),
+                (int)SDL_floor(window->text_input_rect.y / wind->pointer_scale.y),
+                (int)SDL_ceil(window->text_input_rect.w / wind->pointer_scale.x),
+                (int)SDL_ceil(window->text_input_rect.h / wind->pointer_scale.y)
+            };
+            const int scaled_cursor = (int)SDL_floor(window->text_input_cursor / wind->pointer_scale.x);
+            if (!SDL_RectsEqual(&scaled_rect, &input->text_input->text_input_rect) || scaled_cursor != input->text_input->text_input_cursor) {
+                SDL_copyp(&input->text_input->text_input_rect, &scaled_rect);
+                input->text_input->text_input_cursor = scaled_cursor;
+
+                // Clamp the x value so it doesn't run too far past the end of the text input area.
                 zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
-                                                       window->text_input_rect.x,
-                                                       window->text_input_rect.y,
-                                                       window->text_input_rect.w,
-                                                       window->text_input_rect.h);
+                                                       SDL_min(scaled_rect.x + scaled_cursor, scaled_rect.x + scaled_rect.w),
+                                                       scaled_rect.y,
+                                                       1,
+                                                       scaled_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 f570edb32fc37..a1ea076b7beb2 100644
--- a/src/video/wayland/SDL_waylandkeyboard.h
+++ b/src/video/wayland/SDL_waylandkeyboard.h
@@ -26,7 +26,8 @@
 typedef struct SDL_WaylandTextInput
 {
     struct zwp_text_input_v3 *text_input;
-    SDL_Rect cursor_rect;
+    SDL_Rect text_input_rect;
+    int text_input_cursor;
     bool has_preedit;
 } SDL_WaylandTextInput;