Download raw body.
Proper UTF-8 support for cwm(1) menu search (PING)
On Tue, Dec 23, 2025 at 01:09:23PM +0100, Walter Alejandro Iglesias wrote:
> Currently UTF-8 support in in cwm(1) menu search is incomplete. Dead
> keys don't work as expected, for example, 'aacute' will print first the
> tilde, then the 'a' by separate. This is because cwm uses
> XLookupString(3) which handles keyboard input for Latin-1.
>
> There is no direct way to replace that function for
> Xutf8LookupString(3). I had to add XIM and XIC definitions.
>
> In case anyone is concerned about portability to systems that still
> support Latin-1. I compiled the Debian version with my patch and tested
> it with the en_US.ISO-8859-15 locale, it works perfectly.
>
Index: menu.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/menu.c,v
diff -u -p -u -p -r1.110 menu.c
--- menu.c 15 Oct 2022 16:06:07 -0000 1.110
+++ menu.c 23 Dec 2025 10:59:04 -0000
@@ -65,7 +65,7 @@ struct menu_ctx {
void (*match)(struct menu_q *, struct menu_q *, char *);
void (*print)(struct menu *, int);
};
-static struct menu *menu_handle_key(XEvent *, struct menu_ctx *,
+static struct menu *menu_handle_key(XIC, XEvent *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static void menu_handle_move(struct menu_ctx *,
struct menu_q *, int, int);
@@ -77,7 +77,8 @@ static void menu_draw_entry(struct me
int, int);
static int menu_calc_entry(struct menu_ctx *, int, int);
static struct menu *menu_complete_path(struct menu_ctx *);
-static int menu_keycode(XKeyEvent *, enum ctltype *, char *);
+static int menu_keycode(XIC, XKeyEvent *, enum ctltype *,
+ char *);
struct menu *
menu_filter(struct screen_ctx *sc, struct menu_q *menuq, const char *prompt,
@@ -124,6 +125,12 @@ menu_filter(struct screen_ctx *sc, struc
XSelectInput(X_Dpy, mc.win, MENUMASK);
XMapRaised(X_Dpy, mc.win);
+ XIM im = XOpenIM(X_Dpy, NULL, NULL, NULL);
+ XIC ic = XCreateIC(im, XNInputStyle,
+ XIMPreeditNothing | XIMStatusNothing,
+ XNClientWindow, mc.win, NULL);
+ XSetICFocus(ic);
+
if (XGrabPointer(X_Dpy, mc.win, False, MENUGRABMASK,
GrabModeAsync, GrabModeAsync, None, Conf.cursor[CF_QUESTION],
CurrentTime) != GrabSuccess) {
@@ -144,12 +151,15 @@ menu_filter(struct screen_ctx *sc, struc
XWindowEvent(X_Dpy, mc.win, MENUMASK, &e);
+ if (XFilterEvent(&e, None))
+ continue;
+
switch (e.type) {
case KeyPress:
- if ((mi = menu_handle_key(&e, &mc, menuq, &resultq))
- != NULL)
+ if ((mi = menu_handle_key(ic, &e, &mc, menuq,
+ &resultq)) != NULL)
goto out;
- /* FALLTHROUGH */
+ /* FALLTHROUGH */
case Expose:
menu_draw(&mc, menuq, &resultq);
break;
@@ -217,8 +227,8 @@ menu_complete_path(struct menu_ctx *mc)
}
static struct menu *
-menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
- struct menu_q *resultq)
+menu_handle_key(XIC ic, XEvent *e, struct menu_ctx *mc,
+ struct menu_q *menuq, struct menu_q *resultq)
{
struct menu *mi;
enum ctltype ctl;
@@ -227,7 +237,7 @@ menu_handle_key(XEvent *e, struct menu_c
int clen, i;
wchar_t wc;
- if (menu_keycode(&e->xkey, &ctl, chr) < 0)
+ if (menu_keycode(ic, &e->xkey, &ctl, chr) < 0)
return NULL;
switch (ctl) {
@@ -501,9 +511,11 @@ menu_calc_entry(struct menu_ctx *mc, int
}
static int
-menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr)
+menu_keycode(XIC ic, XKeyEvent *ev, enum ctltype *ctl, char *chr)
{
- KeySym ks;
+ KeySym ks;
+ Status status;
+ size_t len = sizeof(chr);
*ctl = CTL_NONE;
chr[0] = '\0';
@@ -582,7 +594,10 @@ menu_keycode(XKeyEvent *ev, enum ctltype
if (*ctl != CTL_NONE)
return 0;
- if (XLookupString(ev, chr, 32, &ks, NULL) < 0)
+ len = Xutf8LookupString(ic, ev, chr, len - 1, &ks, &status);
+ chr[len] = 0;
+
+ if (status == XBufferOverflow)
return -1;
return 0;
--
Walter
Proper UTF-8 support for cwm(1) menu search (PING)