Download raw body.
Proper UTF-8 support for cwm(1) menu search
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