From a1f009d6ad41065210e94e5e72932edd1c27abe2 Mon Sep 17 00:00:00 2001 From: PavelSharp Date: Sat, 18 Oct 2025 02:03:43 +0300 Subject: [PATCH 1/4] fix clipboard UTF8 handling Changes: (1) length as byte count in copy callback (instead of glyph count) (2) fix nk_str_insert_text_char and nk_str_insert_str_char (3) correct UTF-8 cursor handling Fixes: https://github.com/Immediate-Mode-UI/Nuklear/issues/840 Fixes: https://github.com/Immediate-Mode-UI/Nuklear/issues/764 Obsoletes: https://github.com/Immediate-Mode-UI/Nuklear/pull/543 BREAKING CHANGE: If your custom backed has a workaround for this issue, it will break. --- clib.json | 2 +- nuklear.h | 33 +++++++++++++++++++-------------- src/CHANGELOG | 3 +++ src/nuklear_edit.c | 24 +++++++++++++----------- src/nuklear_string.c | 4 ++-- src/nuklear_text_editor.c | 2 +- 6 files changed, 39 insertions(+), 29 deletions(-) diff --git a/clib.json b/clib.json index e704fda77..7ba2ed8b7 100644 --- a/clib.json +++ b/clib.json @@ -1,6 +1,6 @@ { "name": "nuklear", - "version": "4.12.8", + "version": "4.13.1", "repo": "Immediate-Mode-UI/Nuklear", "description": "A small ANSI C gui toolkit", "keywords": ["gl", "ui", "toolkit"], diff --git a/nuklear.h b/nuklear.h index 700798b16..40cdfe43c 100644 --- a/nuklear.h +++ b/nuklear.h @@ -8931,12 +8931,12 @@ nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len) NK_API int nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len) { - return nk_str_insert_text_utf8(str, pos, text, len); + return nk_str_insert_at_rune(str, pos, text, len) ? len : 0; } NK_API int nk_str_insert_str_char(struct nk_str *str, int pos, const char *text) { - return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text)); + return nk_str_insert_text_char(str, pos, text, nk_strlen(text)); } NK_API int nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len) @@ -27155,7 +27155,7 @@ nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len) glyphs = nk_utf_len(ctext, len); if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) { nk_textedit_makeundo_insert(state, state->cursor, glyphs); - state->cursor += len; + state->cursor += glyphs; state->has_preferred_x = 0; return 1; } @@ -28114,17 +28114,19 @@ nk_do_edit(nk_flags *state, struct nk_command_buffer *out, int cut = nk_input_is_key_pressed(in, NK_KEY_CUT); if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD)) { - int glyph_len; - nk_rune unicode; - const char *text; - int b = edit->select_start; - int e = edit->select_end; - - int begin = NK_MIN(b, e); - int end = NK_MAX(b, e); - text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len); - if (edit->clip.copy) - edit->clip.copy(edit->clip.userdata, text, end - begin); + int begin = NK_MIN(edit->select_start, edit->select_end); + int end = NK_MAX(edit->select_start, edit->select_end); + + if (edit->clip.copy) { + int glyph_len; + nk_rune unicode; + const char *text_begin, *text_end; + text_begin = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len); + /*Reuse temporary variables (unicode, glyph_len)*/ + text_end = nk_str_at_const(&edit->string, end, &unicode, &glyph_len); + + edit->clip.copy(edit->clip.userdata, text_begin, text_end - text_begin); + } if (cut && !(flags & NK_EDIT_READ_ONLY)){ nk_textedit_cut(edit); cursor_follow = nk_true; @@ -30736,6 +30738,9 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args) /// - [y]: Minor version with non-breaking API and library changes /// - [z]: Patch version with no direct changes to the API /// +/// - 2025/10/18 (4.13.1) - Fix UTF-8 clipboard handling (copy/paste) +/// POSSIBLE BREAKING CHANGE: if your custom backend has a workaround +/// for this issue, this workaround may break now, so be aware /// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active' /// Add new updated demo: sdl3_renderer /// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default, diff --git a/src/CHANGELOG b/src/CHANGELOG index 8de53d80b..43e86a0f8 100644 --- a/src/CHANGELOG +++ b/src/CHANGELOG @@ -7,6 +7,9 @@ /// - [y]: Minor version with non-breaking API and library changes /// - [z]: Patch version with no direct changes to the API /// +/// - 2025/10/18 (4.13.1) - Fix UTF-8 clipboard handling (copy/paste) +/// POSSIBLE BREAKING CHANGE: if your custom backend has a workaround +/// for this issue, this workaround may break now, so be aware /// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active' /// Add new updated demo: sdl3_renderer /// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default, diff --git a/src/nuklear_edit.c b/src/nuklear_edit.c index ae5daed02..d7f460497 100644 --- a/src/nuklear_edit.c +++ b/src/nuklear_edit.c @@ -278,17 +278,19 @@ nk_do_edit(nk_flags *state, struct nk_command_buffer *out, int cut = nk_input_is_key_pressed(in, NK_KEY_CUT); if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD)) { - int glyph_len; - nk_rune unicode; - const char *text; - int b = edit->select_start; - int e = edit->select_end; - - int begin = NK_MIN(b, e); - int end = NK_MAX(b, e); - text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len); - if (edit->clip.copy) - edit->clip.copy(edit->clip.userdata, text, end - begin); + int begin = NK_MIN(edit->select_start, edit->select_end); + int end = NK_MAX(edit->select_start, edit->select_end); + + if (edit->clip.copy) { + int glyph_len; + nk_rune unicode; + const char *text_begin, *text_end; + text_begin = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len); + /*Reuse temporary variables (unicode, glyph_len)*/ + text_end = nk_str_at_const(&edit->string, end, &unicode, &glyph_len); + + edit->clip.copy(edit->clip.userdata, text_begin, text_end - text_begin); + } if (cut && !(flags & NK_EDIT_READ_ONLY)){ nk_textedit_cut(edit); cursor_follow = nk_true; diff --git a/src/nuklear_string.c b/src/nuklear_string.c index 583789391..40ee6f3b2 100644 --- a/src/nuklear_string.c +++ b/src/nuklear_string.c @@ -167,12 +167,12 @@ nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len) NK_API int nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len) { - return nk_str_insert_text_utf8(str, pos, text, len); + return nk_str_insert_at_rune(str, pos, text, len) ? len : 0; } NK_API int nk_str_insert_str_char(struct nk_str *str, int pos, const char *text) { - return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text)); + return nk_str_insert_text_char(str, pos, text, nk_strlen(text)); } NK_API int nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len) diff --git a/src/nuklear_text_editor.c b/src/nuklear_text_editor.c index 7534b8c58..082480ff1 100644 --- a/src/nuklear_text_editor.c +++ b/src/nuklear_text_editor.c @@ -355,7 +355,7 @@ nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len) glyphs = nk_utf_len(ctext, len); if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) { nk_textedit_makeundo_insert(state, state->cursor, glyphs); - state->cursor += len; + state->cursor += glyphs; state->has_preferred_x = 0; return 1; } From 5813fcbecdef924185b6ad0863538ae128d29a8d Mon Sep 17 00:00:00 2001 From: PavelSharp Date: Sat, 31 Jan 2026 14:31:38 +0300 Subject: [PATCH 2/4] demo/sdl3_renderer: switch to native Nuklear UTF8 clipboard support Co-authored-by: sleeptightAnsiC <91839286+sleeptightAnsiC@users.noreply.github.com> --- demo/sdl3_renderer/nuklear_sdl3_renderer.h | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/demo/sdl3_renderer/nuklear_sdl3_renderer.h b/demo/sdl3_renderer/nuklear_sdl3_renderer.h index 25698ea93..50760c2d5 100644 --- a/demo/sdl3_renderer/nuklear_sdl3_renderer.h +++ b/demo/sdl3_renderer/nuklear_sdl3_renderer.h @@ -319,20 +319,12 @@ nk_sdl_clipboard_paste(nk_handle usr, struct nk_text_edit *edit) char *text; int len; NK_UNUSED(usr); - /* this function returns empty string on failure, not NULL */ text = SDL_GetClipboardText(); NK_ASSERT(text); if (text[0] != '\0') { - /* FIXME: there is a bug in Nuklear that affects UTF8 clipboard handling - * "len" should be a buffer length, but due to bug it must be a glyph count - * see: https://github.com/Immediate-Mode-UI/Nuklear/pull/841 */ -#if 0 len = nk_strlen(text); -#else - len = SDL_utf8strlen(text); -#endif nk_textedit_paste(edit, text, len); } SDL_free(text); @@ -341,27 +333,13 @@ nk_sdl_clipboard_paste(nk_handle usr, struct nk_text_edit *edit) NK_INTERN void nk_sdl_clipboard_copy(nk_handle usr, const char *text, int len) { - const char *ptext; char *str; size_t buflen; - int i; struct nk_sdl* sdl = (struct nk_sdl*)usr.ptr; NK_ASSERT(sdl); if (len <= 0 || text == NULL) return; - /* FIXME: there is a bug in Nuklear that affects UTF8 clipboard handling - * "len" is expected to be a buffer length, but due to bug it actually is a glyph count - * see: https://github.com/Immediate-Mode-UI/Nuklear/pull/841 */ -#if 0 buflen = len + 1; - NK_UNUSED(ptext); -#else - ptext = text; - for (i = len; i > 0; i--) - (void)SDL_StepUTF8(&ptext, NULL); - buflen = (size_t)(ptext - text) + 1; -#endif - str = sdl->allocator.alloc(sdl->allocator.userdata, 0, buflen); if (!str) return; SDL_strlcpy(str, text, buflen); From 9c9179f022fc5b8010096685b707ddecfede713a Mon Sep 17 00:00:00 2001 From: PavelSharp <37598887+PavelSharp@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:43:29 +0300 Subject: [PATCH 3/4] refactor: add int cast to text_end - text_begin Co-authored-by: Rob Loach --- src/nuklear_edit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nuklear_edit.c b/src/nuklear_edit.c index d7f460497..6ef034c24 100644 --- a/src/nuklear_edit.c +++ b/src/nuklear_edit.c @@ -289,7 +289,7 @@ nk_do_edit(nk_flags *state, struct nk_command_buffer *out, /*Reuse temporary variables (unicode, glyph_len)*/ text_end = nk_str_at_const(&edit->string, end, &unicode, &glyph_len); - edit->clip.copy(edit->clip.userdata, text_begin, text_end - text_begin); + edit->clip.copy(edit->clip.userdata, text_begin, (int)(text_end - text_begin)); } if (cut && !(flags & NK_EDIT_READ_ONLY)){ nk_textedit_cut(edit); From 4e5d411a4fcf22f618dbdc962beb3ea80d117d66 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Mon, 30 Mar 2026 10:56:47 -0400 Subject: [PATCH 4/4] Rebuild nuklear.h --- nuklear.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuklear.h b/nuklear.h index e20765172..968441cf5 100644 --- a/nuklear.h +++ b/nuklear.h @@ -28209,7 +28209,7 @@ nk_do_edit(nk_flags *state, struct nk_command_buffer *out, /*Reuse temporary variables (unicode, glyph_len)*/ text_end = nk_str_at_const(&edit->string, end, &unicode, &glyph_len); - edit->clip.copy(edit->clip.userdata, text_begin, text_end - text_begin); + edit->clip.copy(edit->clip.userdata, text_begin, (int)(text_end - text_begin)); } if (cut && !(flags & NK_EDIT_READ_ONLY)){ nk_textedit_cut(edit);