[PATCH] WINGs: avoid splitting UTF-8 characters when wrapping text

Skip to first unread message

david.m...@gmail.com

unread,
Apr 3, 2026, 4:17:55 PM (3 days ago) Apr 3
to Window Maker Development
This patch is to split UTF-8 word by characters and not byte.
Issue reported at https://github.com/window-maker/wmaker/issues/65

Moved the existing UTF-8 functions from wtextfield.c to WINGsP.h to
be available to all modules.
---
 WINGs/WINGs/WINGsP.h.in | 31 +++++++++++++++++++++++++++++++
 WINGs/wmisc.c           | 11 +++++++----
 WINGs/wtextfield.c      | 29 -----------------------------
 3 files changed, 38 insertions(+), 33 deletions(-)

diff --git a/WINGs/WINGs/WINGsP.h.in b/WINGs/WINGs/WINGsP.h.in
index 2c36b269..02d288f3 100644
--- a/WINGs/WINGs/WINGsP.h.in
+++ b/WINGs/WINGs/WINGsP.h.in
@@ -686,6 +686,37 @@ void W_BroadcastMessage(W_View *targetParent, XEvent *event);
 
 void W_DispatchMessage(W_View *target, XEvent *event);
 
+/* ---[ UTF-8 helpers ]--------------------------------------------------- */
+
+static inline int oneUTF8CharBackward(const char *str, int len)
+{
+ const unsigned char *ustr = (const unsigned char *)str;
+ int pos = 0;
+
+ while (len-- > 0 && ustr[--pos] >= 0x80 && ustr[pos] <= 0xbf) ;
+ return pos;
+}
+
+static inline int oneUTF8CharForward(const char *str, int len)
+{
+ const unsigned char *ustr = (const unsigned char *)str;
+ int pos = 0;
+
+ while (len-- > 0 && ustr[++pos] >= 0x80 && ustr[pos] <= 0xbf) ;
+ return pos;
+}
+
+// find the beginning of the UTF8 char pointed by str
+static inline int seekUTF8CharStart(const char *str, int len)
+{
+ const unsigned char *ustr = (const unsigned char *)str;
+ int pos = 0;
+
+ while (len-- > 0 && ustr[pos] >= 0x80 && ustr[pos] <= 0xbf)
+ --pos;
+ return pos;
+}
+
 
 #ifdef __cplusplus
 }
diff --git a/WINGs/wmisc.c b/WINGs/wmisc.c
index ba4c8a6a..e14ad176 100644
--- a/WINGs/wmisc.c
+++ b/WINGs/wmisc.c
@@ -122,11 +122,14 @@ static int fitText(const char *text, WMFont * font, int width, int wrap)
  word1 = word2;
  }
 
- for (i = word1; i < word2; i++) {
- w = WMWidthOfString(font, text, i);
- if (w > width) {
+ /* Advance character by character (not byte by byte) */
+ i = word1;
+ while (i < word2) {
+ int next_i = i + oneUTF8CharForward(text + i, word2 - i);
+ w = WMWidthOfString(font, text, next_i);
+ if (w > width)
  break;
- }
+ i = next_i;
  }
 
  /* keep words complete if possible */
diff --git a/WINGs/wtextfield.c b/WINGs/wtextfield.c
index 52b577e5..4d25a3e5 100644
--- a/WINGs/wtextfield.c
+++ b/WINGs/wtextfield.c
@@ -122,35 +122,6 @@ static WMSelectionProcs selectionHandler = {
 #define TEXT_WIDTH2(tPtr, start, end) (WMWidthOfString((tPtr)->font, \
     &((tPtr)->text[(start)]), (end) - (start)))
 
-static inline int oneUTF8CharBackward(const char *str, int len)
-{
- const unsigned char *ustr = (const unsigned char *)str;
- int pos = 0;
-
- while (len-- > 0 && ustr[--pos] >= 0x80 && ustr[pos] <= 0xbf) ;
- return pos;
-}
-
-static inline int oneUTF8CharForward(const char *str, int len)
-{
- const unsigned char *ustr = (const unsigned char *)str;
- int pos = 0;
-
- while (len-- > 0 && ustr[++pos] >= 0x80 && ustr[pos] <= 0xbf) ;
- return pos;
-}
-
-// find the beginning of the UTF8 char pointed by str
-static inline int seekUTF8CharStart(const char *str, int len)
-{
- const unsigned char *ustr = (const unsigned char *)str;
- int pos = 0;
-
- while (len-- > 0 && ustr[pos] >= 0x80 && ustr[pos] <= 0xbf)
- --pos;
- return pos;
-}
-
 static void normalizeRange(TextField * tPtr, WMRange * range)
 {
  if (range->position < 0 && range->count < 0)
--
2.43.0
0001-WINGs-avoid-splitting-UTF-8-characters-when-wrapping.patch

Carlos R. Mafra

unread,
Apr 4, 2026, 10:40:55 AM (2 days ago) Apr 4
to wmake...@googlegroups.com
On Fri, 3 Apr 2026 at 13:17:55 -0700, david.m...@gmail.com wrote:
> This patch is to split UTF-8 word by characters and not byte.
> Issue reported at https://github.com/window-maker/wmaker/issues/65
>
> Moved the existing UTF-8 functions from wtextfield.c to WINGsP.h to
> be available to all modules.
> ---
> WINGs/WINGs/WINGsP.h.in | 31 +++++++++++++++++++++++++++++++
> WINGs/wmisc.c | 11 +++++++----
> WINGs/wtextfield.c | 29 -----------------------------
> 3 files changed, 38 insertions(+), 33 deletions(-)

Hi David,

Thanks for the patch!

But I think it would be better to split this patch into two:

one moving the functions to WINGsP.h (so no risk of regression)
and the other fixing the issue.

That way the patches are smaller and only the second patch involves
changing something. It is easier to debug this way, if needed.

Could you do that? I'm sorry to ask for additional work!

Best, Carlos


david.m...@gmail.com

unread,
Apr 4, 2026, 2:17:24 PM (2 days ago) Apr 4
to Window Maker Development
Sure, so disregard this patch I will split it in two. 

Carlos R. Mafra

unread,
Apr 4, 2026, 4:35:25 PM (2 days ago) Apr 4
to wmake...@googlegroups.com
Thanks!
Reply all
Reply to author
Forward
0 new messages