From aff8feb7c59044017c8d1b73872ec01d42fc51b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net>
Date: Sun, 29 Sep 2024 17:23:09 -0400
Subject: [PATCH] Have the IC focus follow the X11 focus

Basically, If we get a FocusOut, call XUnsetICFocus(), and if we
get a FocusIn, call XSetICFocus().  Since we're doing this, don't
call XSetICFocus() unconditionally at start, wait for the server
to send us the initial FocusIn instead.

The only bit I'm not sure of is if I got the times to ignor
messages right... see here:
https://tronche.com/gui/x/xlib/events/input-focus/normal-and-grabbed.html
If you want to check my work.

May fix the focus follows mouse issue reported by Cyan.
---
 src/conio/x_cio.c    |  4 ++++
 src/conio/x_events.c | 30 +++++++++++++++++++++++++++---
 src/conio/x_events.h |  1 +
 3 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/src/conio/x_cio.c b/src/conio/x_cio.c
index 9a1ad5c1c1..51a8daabd5 100644
--- a/src/conio/x_cio.c
+++ b/src/conio/x_cio.c
@@ -446,6 +446,10 @@ int x_initciolib(int mode)
 		xp_dlclose(dl);
 		return(-1);
 	}
+	if((x11.XUnsetICFocus=xp_dlsym(dl,XUnsetICFocus))==NULL) {
+		xp_dlclose(dl);
+		return(-1);
+	}
 	if((x11.XFilterEvent=xp_dlsym(dl,XFilterEvent))==NULL) {
 		xp_dlclose(dl);
 		return(-1);
diff --git a/src/conio/x_events.c b/src/conio/x_events.c
index f057eee8dd..bbf33d2c3c 100644
--- a/src/conio/x_events.c
+++ b/src/conio/x_events.c
@@ -1069,9 +1069,10 @@ static int init_window()
 	gcv.graphics_exposures = False;
 	gc=x11.XCreateGC(dpy, win, GCFunction | GCForeground | GCBackground | GCGraphicsExposures, &gcv);
 
-	x11.XSelectInput(dpy, win, KeyReleaseMask | KeyPressMask |
-		     ExposureMask | ButtonPressMask | PropertyChangeMask
-		     | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
+	x11.XSelectInput(dpy, win, KeyReleaseMask | KeyPressMask
+		     | ExposureMask | ButtonPressMask | PropertyChangeMask
+		     | ButtonReleaseMask | PointerMotionMask
+		     | StructureNotifyMask | FocusChangeMask);
 
 	x11.XStoreName(dpy, win, "SyncConsole");
 	Atom protos[2];
@@ -1732,6 +1733,29 @@ x11_event(XEvent *ev)
 				expose_rect(ev->xexpose.x, ev->xexpose.y, ev->xexpose.width, ev->xexpose.height);
 			break;
 
+		/* Focus Events */
+		case FocusIn:
+		case FocusOut:
+			{
+				if (ev->xfocus.mode == NotifyGrab)
+					break;
+				if (ev->xfocus.mode == NotifyUngrab)
+					break;
+				if (ev->xfocus.detail == NotifyInferior)
+					break;
+				if (ev->xfocus.detail == NotifyPointer)
+					break;
+				if (ev->type == FocusIn) {
+					if (ic)
+						x11.XSetICFocus(ic);
+				}
+				else {
+					if (ic)
+						x11.XUnsetICFocus(ic);
+				}
+				break;
+			}
+
 		/* Copy/Paste events */
 		case SelectionClear:
 			{
diff --git a/src/conio/x_events.h b/src/conio/x_events.h
index 524327bb34..51b5b3cd22 100644
--- a/src/conio/x_events.h
+++ b/src/conio/x_events.h
@@ -105,6 +105,7 @@ struct x11 {
 	XIC (*XCreateIC)(XIM im, ...);
 	int (*XwcLookupString)(XIC ic, XKeyPressedEvent *event, wchar_t *buffer_return, int wchars_buffer, KeySym *keysym_return, Status *status_return);
 	void (*XSetICFocus)(XIC ic);
+	void (*XUnsetICFocus)(XIC ic);
 	Bool (*XFilterEvent)(XEvent *event, Window w);
 	Cursor (*XCreateFontCursor)(Display *display, unsigned int shape);
 	int (*XDefineCursor)(Display *display, Window w, Cursor cursor);
-- 
GitLab