From b3157722535db692d54b8fe7d26d07f94d49daf3 Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Fri, 26 Apr 2024 01:29:26 +0900 Subject: [PATCH libX11 5/7] Accept anon windows in XFilterEvent to update XIM state When input focuses are switched quickly with shortcut keys in a Java window, the focus is sometimes lost and the Window=0 is assigned in XFilterEvent() but the XKeyEvent was forwarded by a XIM serer(IBus) with XIM_FORWARD_EVENT -> XNextEvent() -> XFilterEvent() and the event needs to be forwarded to the XIM XKeyEvent press and release filters to update the XIM state with Window=0 likes _XimPendingFilter() and _XimUnfabricateSerial(). Closes: #205, #206 Fixes: 024d229f ("ximcp: Unmark to fabricate key events with XKeyEvent serial") Part-of: (cherry picked from commit 5a1e62d77b65ba148b1c6d1d22a81dc2b07e7d9e) --- modules/im/ximcp/imDefFlt.c | 34 ++++++++++++++++++++++++++++++---- src/FilterEv.c | 25 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/modules/im/ximcp/imDefFlt.c b/modules/im/ximcp/imDefFlt.c index ad8a272b..76d63e88 100644 --- a/modules/im/ximcp/imDefFlt.c +++ b/modules/im/ximcp/imDefFlt.c @@ -138,7 +138,8 @@ _XimPendingFilter( static Bool _XimProtoKeypressFilter( Xic ic, - XKeyEvent *ev) + XKeyEvent *ev, + Window w) { Xim im = (Xim)ic->core.im; @@ -147,6 +148,9 @@ _XimProtoKeypressFilter( _XimUnfabricateSerial(im, ev); return NOTFILTERD; } + /* w=0 is used for _XimIsFabricatedSerial() only */ + if (!w) + return NOTFILTERD; if (IS_NEGLECT_EVENT(ic, KeyPressMask)) return FILTERD; @@ -193,13 +197,14 @@ _XimFilterKeypress( XEvent *ev, XPointer client_data) { - return _XimProtoKeypressFilter((Xic)client_data, (XKeyEvent *)ev ); + return _XimProtoKeypressFilter((Xic)client_data, (XKeyEvent *)ev, w); } static Bool _XimProtoKeyreleaseFilter( Xic ic, - XKeyEvent *ev) + XKeyEvent *ev, + Window w) { Xim im = (Xim)ic->core.im; @@ -208,6 +213,9 @@ _XimProtoKeyreleaseFilter( _XimUnfabricateSerial(im, ev); return NOTFILTERD; } + /* w=0 is used for _XimIsFabricatedSerial() only */ + if (!w) + return NOTFILTERD; if (IS_NEGLECT_EVENT(ic, KeyReleaseMask)) return FILTERD; @@ -254,7 +262,7 @@ _XimFilterKeyrelease( XEvent *ev, XPointer client_data) { - return _XimProtoKeyreleaseFilter((Xic)client_data, (XKeyEvent *)ev); + return _XimProtoKeyreleaseFilter((Xic)client_data, (XKeyEvent *)ev, w); } static void @@ -263,6 +271,11 @@ _XimRegisterKeyPressFilter( { if (ic->core.focus_window) { if (!(ic->private.proto.registed_filter_event & KEYPRESS_MASK)) { + _XRegisterFilterByType (ic->core.im->core.display, + 0, + KeyPress, KeyPress, + _XimFilterKeypress, + (XPointer)ic); _XRegisterFilterByType (ic->core.im->core.display, ic->core.focus_window, KeyPress, KeyPress, @@ -280,6 +293,11 @@ _XimRegisterKeyReleaseFilter( { if (ic->core.focus_window) { if (!(ic->private.proto.registed_filter_event & KEYRELEASE_MASK)) { + _XRegisterFilterByType (ic->core.im->core.display, + 0, + KeyRelease, KeyRelease, + _XimFilterKeyrelease, + (XPointer)ic); _XRegisterFilterByType (ic->core.im->core.display, ic->core.focus_window, KeyRelease, KeyRelease, @@ -301,6 +319,10 @@ _XimUnregisterKeyPressFilter( ic->core.focus_window, _XimFilterKeypress, (XPointer)ic); + _XUnregisterFilter (ic->core.im->core.display, + 0, + _XimFilterKeypress, + (XPointer)ic); ic->private.proto.registed_filter_event &= ~KEYPRESS_MASK; } } @@ -317,6 +339,10 @@ _XimUnregisterKeyReleaseFilter( ic->core.focus_window, _XimFilterKeyrelease, (XPointer)ic); + _XUnregisterFilter (ic->core.im->core.display, + 0, + _XimFilterKeyrelease, + (XPointer)ic); ic->private.proto.registed_filter_event &= ~KEYRELEASE_MASK; } } diff --git a/src/FilterEv.c b/src/FilterEv.c index 0a48e548..07845bcc 100644 --- a/src/FilterEv.c +++ b/src/FilterEv.c @@ -100,6 +100,31 @@ XFilterEvent( } } } + for (p = ev->xany.display->im_filters; p != NULL; p = p->next) { + /* Java sometimes calls XFilterEvent() with window=0 and ev come from + * XNextEvent() when users type some keys quickly and switch multiple + * input focuses in a Java window with the keys. + * But XKeyEvent filters need to receive the event with window=0 for + * _XimPendingFilter() and _XimUnfabricateSerial() to clear the + * fowarded XKeyEvent with XIM_FORWARD_EVENT. + * + * The case of p->window == 0 is checkekd after all cases of p->window + * != 0 are checked because all input contexts share + * Display->im_filters but each input context has + * Xic->private.proto.registed_filter_event for the filters + * and same p->filter could be registerd to Display->im_filters twice + * with different p->window. + */ + if (p->window == 0 && window == 0) { + if ((mask & p->event_mask) || + (ev->type >= p->start_type && ev->type <= p->end_type)) { + UnlockDisplay(ev->xany.display); + ret = (*(p->filter))(ev->xany.display, p->window, ev, + p->client_data); + return(ret); + } + } + } UnlockDisplay(ev->xany.display); #endif return(False); -- 2.47.1