Subject: Bug#747537: wip patch (Re: mupdf: unable to enter non-ascii characters while searching)

From: "Yuriy M. Kaminskiy" <[email-masked]>
Date: Wed, 23 Oct 2019 16:47:40 +0300

Control: tags -1 upstream patch
thanks

Incomplete patch for mupdf-x11 1.15 attached (works with utf-8 locales; there are display problems in some non-utf-8 locales - it is possible to input [ascii and non-ascii] symbols, but search string and prompt is invisible); XKB (tested with cyrillic keyboard layout) and IM input seems works (tested with LANG=ja_JP.UTF-8 and uim/anthy).
From: Yuriy M. Kaminskiy <[email-masked]>
Date: Wed, 04 Jul 2018 22:19:10 +0000
Subject: X11: add basic support for i18n in search

Index: mupdf-1.15.0+ds1/platform/x11/x11_main.c
===================================================================
--- mupdf-1.15.0+ds1.orig/platform/x11/x11_main.c
+++ mupdf-1.15.0+ds1/platform/x11/x11_main.c
@@ -18,6 +18,10 @@
 #include <unistd.h>
 #include <signal.h>
 
+#ifdef X_HAVE_UTF8_STRING
+#include <locale.h>
+#endif
+
 #define mupdf_icon_bitmap_16_width 16
 #define mupdf_icon_bitmap_16_height 16
 static unsigned char mupdf_icon_bitmap_16_bits[] = {
@@ -69,6 +73,11 @@ void windrawstringxor(pdfapp_t *app, int
 void cleanup(pdfapp_t *app);
 
 static Display *xdpy;
+#ifdef X_HAVE_UTF8_STRING
+static XIM xim;
+static XIC xic;
+static XFontSet xfs;
+#endif
 static Atom XA_CLIPBOARD;
 static Atom XA_TARGETS;
 static Atom XA_TIMESTAMP;
@@ -202,6 +211,70 @@ static void winopen(void)
 	if (!xdpy)
 		fz_throw(gapp.ctx, FZ_ERROR_GENERIC, "cannot open display");
 
+#ifdef X_HAVE_UTF8_STRING
+	if (XSupportsLocale())
+       	{
+		char **missing_charset_list = NULL;
+		int missing_charset_count = 0;
+		char *def_string = NULL;
+		char *fontlist = NULL;
+		int i;
+
+		XSetLocaleModifiers("");
+		xim = XOpenIM(xdpy, NULL, "mupdf", "MuPDF");
+		if (!xim)
+		{
+			fprintf(stderr, "warning: unable to open IM, fallback to @im=none\n");
+			XSetLocaleModifiers("@im=none");
+			xim = XOpenIM(xdpy, NULL, "mupdf", "MuPDF");
+		}
+		if (!xim)
+		{
+			fprintf(stderr, "warning: unable to open IM\n");
+		}
+		if (fontlist == NULL)
+		{
+			fontlist =
+				"-*-Fixed-Medium-R-Normal-*-13-*-*-*-*-*" ","
+				"-*-*-Medium-R-*-*-13-*-*-*-*-*";
+		}
+		xfs = XCreateFontSet(xdpy, fontlist,
+				&missing_charset_list, &missing_charset_count,
+			       	&def_string);
+		if (!xfs)
+		{
+			fprintf(stderr, "warning: unable to open fontset %s\n",
+					fontlist);
+		}
+#if 0 /* DEBUG */
+		else
+		{
+			XFontStruct **fonts = NULL;
+			char **fontNames = NULL;
+			int numFonts = XFontsOfFontSet(xfs, &fonts, &fontNames);
+
+			fprintf(stderr, "base font: %s\n", XBaseFontNameListOfFontSet(xfs));
+			fprintf(stderr, "locale: %s\n", XLocaleOfFontSet(xfs));
+			for (i = 0; i < numFonts; i++)
+				fprintf(stderr, "font%d: %s, asc: %d, desc: %d\n", i, fontNames[i], fonts[i]->ascent, fonts[i]->descent);
+		}
+		if (missing_charset_count)
+		{
+			for(i = 0; i < missing_charset_count; i++)
+				fprintf(stderr, "warning: missing charset: %s\n",
+					       	missing_charset_list[i]);
+		}
+		if (def_string)
+			fprintf(stderr, "warning: missing characters will be replaced with '%s'\n", def_string);
+#endif
+		if (missing_charset_list)
+			XFreeStringList(missing_charset_list);
+	}
+       	else
+	{
+		fprintf(stderr, "warning: locale is not supported by X\n");
+	}
+#endif
 	XA_CLIPBOARD = XInternAtom(xdpy, "CLIPBOARD", False);
 	XA_TARGETS = XInternAtom(xdpy, "TARGETS", False);
 	XA_TIMESTAMP = XInternAtom(xdpy, "TIMESTAMP", False);
@@ -238,6 +311,17 @@ static void winopen(void)
 		fz_throw(gapp.ctx, FZ_ERROR_GENERIC, "cannot create window");
 
 	XSetWindowColormap(xdpy, xwin, ximage_get_colormap());
+#ifdef X_HAVE_UTF8_STRING
+	if (xim)
+       	{
+		xic = XCreateIC(xim, XNInputStyle,
+				XIMPreeditNothing | XIMStatusNothing,
+				XNClientWindow, xwin,
+				XNFocusWindow, xwin,
+				NULL );
+		XSetICFocus(xic);
+	}
+#endif
 	XSelectInput(xdpy, xwin,
 		StructureNotifyMask | ExposureMask | KeyPressMask |
 		PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
@@ -362,6 +446,11 @@ void cleanup(pdfapp_t *app)
 
 	XFreeGC(xdpy, xgc);
 
+#ifdef X_HAVE_UTF8_STRING
+	if (xic) XDestroyIC(xic);
+	if (xim) XCloseIM(xim);
+	if (xfs) XFreeFontSet(xdpy, xfs);
+#endif
 	XCloseDisplay(xdpy);
 
 	fz_drop_context(ctx);
@@ -437,6 +526,10 @@ void winresize(pdfapp_t *app, int w, int
 		while (1)
 		{
 			XNextEvent(xdpy, &xevt);
+#ifdef X_HAVE_UTF8_STRING
+			if (XFilterEvent(&xevt, xwin))
+				continue;
+#endif
 			if (xevt.type == ConfigureNotify)
 			{
 				width = xevt.xconfigure.width;
@@ -624,6 +717,11 @@ void windrawstringxor(pdfapp_t *app, int
 
 	XSetForeground(xdpy, xgc, WhitePixel(xdpy, DefaultScreen(xdpy)));
 
+#ifdef X_HAVE_UTF8_STRING
+	if (xfs)
+		Xutf8DrawString(xdpy, xwin, xfs, xgc, x, y, s, strlen(s));
+	else
+#endif
 	XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s));
 	XFlush(xdpy);
 
@@ -635,6 +733,11 @@ void windrawstringxor(pdfapp_t *app, int
 void windrawstring(pdfapp_t *app, int x, int y, char *s)
 {
 	XSetForeground(xdpy, xgc, BlackPixel(xdpy, DefaultScreen(xdpy)));
+#ifdef X_HAVE_UTF8_STRING
+	if (xfs)
+		Xutf8DrawString(xdpy, xwin, xfs, xgc, x, y, s, strlen(s));
+	else
+#endif
 	XDrawString(xdpy, xwin, xgc, x, y, s, strlen(s));
 }
 
@@ -869,6 +972,9 @@ int main(int argc, char **argv)
 	struct timeval *timeout;
 	struct timeval tmo_advance_delay;
 
+#ifdef X_HAVE_UTF8_STRING
+	setlocale(LC_CTYPE, "");
+#endif
 	ctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT);
 	if (!ctx)
 	{
@@ -940,8 +1046,18 @@ int main(int argc, char **argv)
 		{
 			XNextEvent(xdpy, &xevt);
 
+#ifdef X_HAVE_UTF8_STRING
+			if (XFilterEvent(&xevt, xwin))
+				continue;
+#endif
 			switch (xevt.type)
 			{
+#ifdef X_HAVE_UTF8_STRING
+			case MappingNotify:
+				XRefreshKeyboardMapping(&xevt.xmapping);
+				break;
+#endif
+
 			case Expose:
 				dirty = 1;
 				break;
@@ -959,6 +1075,11 @@ int main(int argc, char **argv)
 				break;
 
 			case KeyPress:
+#ifdef X_HAVE_UTF8_STRING
+				if (xic)
+					len = Xutf8LookupString(xic, &xevt.xkey, buf, sizeof buf, &keysym, NULL);
+				else
+#endif
 				len = XLookupString(&xevt.xkey, buf, sizeof buf, &keysym, NULL);
 
 				if (!gapp.issearching)
@@ -999,8 +1120,12 @@ int main(int argc, char **argv)
 					}
 				if (xevt.xkey.state & ControlMask && keysym == XK_c)
 					docopy(&gapp, XA_CLIPBOARD);
-				else if (len)
-					onkey(buf[0], xevt.xkey.state);
+				else
+				{
+					unsigned char *p = (unsigned char *)buf;
+					while (len-- > 0)
+						onkey(*p++, xevt.xkey.state);
+				}
 
 				onmouse(oldx, oldy, 0, 0, 0);