[Concept,04/16] expo: Use a dedicated vidconsole-context for text input

Message ID 20260122041155.174721-5-sjg@u-boot.org
State New
Headers
Series expo: Add multiline editing support for textedit |

Commit Message

Simon Glass Jan. 22, 2026, 4:11 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Currently text-input objects (textline, textedit) use the default
vidconsole context (NULL). This causes the cursor state to be shared
with other vidconsole operations, leading to interference.

Add a dedicated vidconsole context (ctx) to struct scene_txtin and use
it for all vidconsole operations. The context is created when the
text-input is opened and disposed when the object is destroyed.

Also add scene_txtin_destroy() to properly clean up the text buffer and
vidconsole context when text-input objects are destroyed.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 boot/scene.c          |  3 +++
 boot/scene_internal.h | 10 ++++++++++
 boot/scene_txtin.c    | 37 ++++++++++++++++++++++++++++---------
 include/expo.h        |  2 ++
 4 files changed, 43 insertions(+), 9 deletions(-)
  

Patch

diff --git a/boot/scene.c b/boot/scene.c
index 7cef20dbb1b..1ea0d1b1c46 100644
--- a/boot/scene.c
+++ b/boot/scene.c
@@ -108,6 +108,9 @@  void scene_obj_destroy(struct scene_obj *obj)
 {
 	if (obj->type == SCENEOBJT_MENU)
 		scene_menu_destroy((struct scene_obj_menu *)obj);
+	else if (obj->type == SCENEOBJT_TEXTLINE ||
+		 obj->type == SCENEOBJT_TEXTEDIT)
+		scene_txtin_destroy(obj->scene, scene_obj_txtin(obj));
 	free(obj->name);
 	free(obj);
 }
diff --git a/boot/scene_internal.h b/boot/scene_internal.h
index 71cbc85c358..3c22b10c2f4 100644
--- a/boot/scene_internal.h
+++ b/boot/scene_internal.h
@@ -521,6 +521,16 @@  void scene_menu_calc_bbox(struct scene_obj_menu *menu,
  */
 int scene_txtin_init(struct scene_txtin *tin, uint size, uint line_chars);
 
+/**
+ * scene_txtin_destroy() - Destroy a text-input object's resources
+ *
+ * Frees memory allocated for the text buffer and vidconsole context
+ *
+ * @scn: Scene containing the object
+ * @tin: Text-input info to destroy
+ */
+void scene_txtin_destroy(struct scene *scn, struct scene_txtin *tin);
+
 /**
  * scene_txtin_arrange() - Arrange common parts of a text-input object
  *
diff --git a/boot/scene_txtin.c b/boot/scene_txtin.c
index 1dfa3a02a6a..457d782b4cf 100644
--- a/boot/scene_txtin.c
+++ b/boot/scene_txtin.c
@@ -14,6 +14,7 @@ 
 #include <menu.h>
 #include <video_console.h>
 #include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/string.h>
 #include "scene_internal.h"
 
@@ -30,6 +31,13 @@  int scene_txtin_init(struct scene_txtin *tin, uint size, uint line_chars)
 	return 0;
 }
 
+void scene_txtin_destroy(struct scene *scn, struct scene_txtin *tin)
+{
+	abuf_uninit(&tin->buf);
+	if (tin->ctx && scn->expo->cons)
+		vidconsole_ctx_dispose(scn->expo->cons, tin->ctx);
+}
+
 int scene_txtin_arrange(struct scene *scn, struct expo_arrange_info *arr,
 			struct scene_obj *obj, struct scene_txtin *tin)
 {
@@ -66,6 +74,7 @@  int scene_txtin_render_deps(struct scene *scn, struct scene_obj *obj,
 	struct cli_line_state *cls = &tin->cls;
 	const bool open = obj->flags & SCENEOF_OPEN;
 	struct udevice *cons = scn->expo->cons;
+	void *ctx = tin->ctx;
 	uint i;
 
 	/* if open, render the edit text on top of the background */
@@ -75,16 +84,16 @@  int scene_txtin_render_deps(struct scene *scn, struct scene_obj *obj,
 		ret = vidconsole_entry_restore(cons, &scn->entry_save);
 		if (ret)
 			return log_msg_ret("sav", ret);
-		scene_render_obj(scn, tin->edit_id, NULL);
+		scene_render_obj(scn, tin->edit_id, ctx);
 
 		/* move cursor back to the correct position */
 		for (i = cls->num; i < cls->eol_num; i++)
-			vidconsole_put_char(cons, NULL, '\b');
+			vidconsole_put_char(cons, ctx, '\b');
 		ret = vidconsole_entry_save(cons, &scn->entry_save);
 		if (ret)
 			return log_msg_ret("sav", ret);
 
-		vidconsole_show_cursor(cons, NULL);
+		vidconsole_show_cursor(cons, ctx);
 	}
 
 	return 0;
@@ -101,15 +110,16 @@  int scene_txtin_render_deps(struct scene *scn, struct scene_obj *obj,
  */
 static void scene_txtin_putch(struct cli_line_state *cls, int ch)
 {
+	struct scene_txtin *tin = container_of(cls, struct scene_txtin, cls);
 	struct scene *scn = cls->priv;
 
-	vidconsole_put_char(scn->expo->cons, NULL, ch);
+	vidconsole_put_char(scn->expo->cons, tin->ctx, ch);
 }
 
 void scene_txtin_close(struct scene *scn, struct scene_txtin *tin)
 {
 	/* cursor is not needed now */
-	vidconsole_readline_end(scn->expo->cons, NULL);
+	vidconsole_readline_end(scn->expo->cons, tin->ctx);
 }
 
 int scene_txtin_open(struct scene *scn, struct scene_obj *obj,
@@ -118,8 +128,17 @@  int scene_txtin_open(struct scene *scn, struct scene_obj *obj,
 	struct cli_line_state *cls = &tin->cls;
 	struct udevice *cons = scn->expo->cons;
 	struct scene_obj_txt *txt;
+	void *ctx;
 	int ret;
 
+	ctx = tin->ctx;
+	if (!ctx) {
+		ret = vidconsole_ctx_new(cons, &ctx);
+		if (ret)
+			return log_msg_ret("ctx", ret);
+		tin->ctx = ctx;
+	}
+
 	/* Copy the text into the scene buffer in case the edit is cancelled */
 	memcpy(abuf_data(&scn->buf), abuf_data(&tin->buf),
 	       abuf_size(&scn->buf));
@@ -129,8 +148,8 @@  int scene_txtin_open(struct scene *scn, struct scene_obj *obj,
 	if (!txt)
 		return log_msg_ret("cur", -ENOENT);
 
-	vidconsole_set_cursor_pos(cons, NULL, txt->obj.bbox.x0, txt->obj.bbox.y0);
-	vidconsole_entry_start(cons, NULL);
+	vidconsole_set_cursor_pos(cons, ctx, txt->obj.bbox.x0, txt->obj.bbox.y0);
+	vidconsole_entry_start(cons, ctx);
 	cli_cread_init(cls, abuf_data(&tin->buf), tin->line_chars);
 	cls->insert = true;
 	cls->putch = scene_txtin_putch;
@@ -141,7 +160,7 @@  int scene_txtin_open(struct scene *scn, struct scene_obj *obj,
 		return log_msg_ret("sav", ret);
 
 	/* make sure the cursor is visible */
-	vidconsole_readline_start(cons, NULL, true);
+	vidconsole_readline_start(cons, ctx, true);
 
 	return 0;
 }
@@ -180,7 +199,7 @@  int scene_txtin_send_key(struct scene_obj *obj, struct scene_txtin *tin,
 			memcpy(abuf_data(&tin->buf), abuf_data(&scn->buf),
 			       abuf_size(&scn->buf));
 
-			scene_txtin_close(scn, NULL);
+			scene_txtin_close(scn, tin);
 		} else {
 			event->type = EXPOACT_QUIT;
 			log_debug("menu quit\n");
diff --git a/include/expo.h b/include/expo.h
index afaf1e8d107..adbe02922ab 100644
--- a/include/expo.h
+++ b/include/expo.h
@@ -509,6 +509,7 @@  struct scene_menitem {
  * @edit_id: ID of the editable text object (not string ID)
  * @line_chars: Nominal number of characters in a line
  * @buf: Text buffer containing current text
+ * @ctx: Vidconsole context for this text-input object
  * @cls: CLI line state for text editing
  */
 struct scene_txtin {
@@ -516,6 +517,7 @@  struct scene_txtin {
 	uint edit_id;
 	uint line_chars;
 	struct abuf buf;
+	void *ctx;
 	struct cli_line_state cls;
 };