diff --git a/0001-ximcp-Unmark-to-fabricate-key-events-with-XKeyEvent-.patch b/0001-ximcp-Unmark-to-fabricate-key-events-with-XKeyEvent-.patch new file mode 100644 index 0000000..6670e50 --- /dev/null +++ b/0001-ximcp-Unmark-to-fabricate-key-events-with-XKeyEvent-.patch @@ -0,0 +1,200 @@ +From a91e5a5e6fca25f23c7dd24c6694ab1b80b6030e Mon Sep 17 00:00:00 2001 +From: Takao Fujiwara +Date: Fri, 12 Apr 2024 10:21:41 +0900 +Subject: [PATCH libX11 1/7] ximcp: Unmark to fabricate key events with + XKeyEvent serial + +_XimProtoKeypressFilter() and _XimProtoKeyreleaseFilter() can +receive XKeyEvent from both the typing on the keyboard and the +callback of XIM_FORWARD_EVENT. + +If the filter functions unmark to fabricate XKeyEvent from the typing +on the keyboard during receiving XKeyEvent from the callback of +XIM_FORWARD_EVENT with typing keys very quickly likes an bar code +scanner (or evemu-play), XIM server cannot receive some key events and +it causes the key typing order to get scrambled. + +Now XIM client saves the serial in XKeyEvent and the filter functions +unmark to fabricate XKeyEvent from the callback of XIM_FORWARD_EVENT +only. + +This and 024d229f are same patches but the regression issues will be +fixed by the later patches. + +Closes: #198 +Fixes: 024d229f ("ximcp: Unmark to fabricate key events with XKeyEvent serial") +Part-of: +(cherry picked from commit 13e9ac4d458069c81d795f6b4842814d30431b4b) +--- + modules/im/ximcp/imDefFlt.c | 8 ++--- + modules/im/ximcp/imDefIm.c | 1 + + modules/im/ximcp/imDefLkup.c | 58 ++++++++++++++++++++++++++++++++---- + src/xlibi18n/XimintP.h | 17 +++++++++++ + 4 files changed, 75 insertions(+), 9 deletions(-) + +diff --git a/modules/im/ximcp/imDefFlt.c b/modules/im/ximcp/imDefFlt.c +index f89d2cb0..a7948df8 100644 +--- a/modules/im/ximcp/imDefFlt.c ++++ b/modules/im/ximcp/imDefFlt.c +@@ -142,9 +142,9 @@ _XimProtoKeypressFilter( + { + Xim im = (Xim)ic->core.im; + +- if ((ev->keycode == 0) || IS_FABRICATED(im)) { ++ if ((ev->keycode == 0) || _XimIsFabricatedSerial(im, ev->serial)) { + _XimPendingFilter(ic); +- UNMARK_FABRICATED(im); ++ _XimUnfabricateSerial(im, ev->serial); + return NOTFILTERD; + } + +@@ -203,9 +203,9 @@ _XimProtoKeyreleaseFilter( + { + Xim im = (Xim)ic->core.im; + +- if (IS_FABRICATED(im)) { ++ if (_XimIsFabricatedSerial(im, ev->serial)) { + _XimPendingFilter(ic); +- UNMARK_FABRICATED(im); ++ _XimUnfabricateSerial(im, ev->serial); + return NOTFILTERD; + } + +diff --git a/modules/im/ximcp/imDefIm.c b/modules/im/ximcp/imDefIm.c +index ccdf14c1..a231a0ac 100644 +--- a/modules/im/ximcp/imDefIm.c ++++ b/modules/im/ximcp/imDefIm.c +@@ -430,6 +430,7 @@ _XimPreConnect( + return False; + + im->private.proto.im_window = im_window; ++ im->private.proto.fabricated_serial = 0; + return True; + } + +diff --git a/modules/im/ximcp/imDefLkup.c b/modules/im/ximcp/imDefLkup.c +index 18289a80..a6923d5b 100644 +--- a/modules/im/ximcp/imDefLkup.c ++++ b/modules/im/ximcp/imDefLkup.c +@@ -351,6 +351,54 @@ _XimForwardEvent( + return _XimForwardEventCore(ic, ev, sync); + } + ++Bool ++_XimFabricateSerial( ++ Xim im, ++ unsigned long serial) ++{ ++ if (!serial) ++ return False; ++ if (serial == im->private.proto.fabricated_serial) { ++ fprintf(stderr, "%s,%d: The key event is already fabricated.\n", __FILE__, __LINE__); ++ return False; ++ } ++ if (im->private.proto.fabricated_serial) ++ fprintf(stderr, "%s,%d: Tried to fabricate a wrong key event.\n", __FILE__, __LINE__); ++ ++ MARK_FABRICATED(im); ++ im->private.proto.fabricated_serial = serial; ++ return True; ++} ++ ++Bool ++_XimUnfabricateSerial( ++ Xim im, ++ unsigned long serial) ++{ ++ if (!serial) ++ return False; ++ if (!im->private.proto.fabricated_serial) { ++ fprintf(stderr, "%s,%d: The key event is already unfabricated.\n", __FILE__, __LINE__); ++ return False; ++ } ++ if (serial != im->private.proto.fabricated_serial) ++ fprintf(stderr, "%s,%d: Tried to unfabricate a wrong key event.\n", __FILE__, __LINE__); ++ ++ im->private.proto.fabricated_serial = 0; ++ UNMARK_FABRICATED(im); ++ return True; ++} ++ ++Bool ++_XimIsFabricatedSerial( ++ Xim im, ++ unsigned long serial) ++{ ++ if (!serial) ++ return False; ++ return (serial == im->private.proto.fabricated_serial); ++} ++ + static void + _XimProcEvent( + Display *d, +@@ -365,7 +413,7 @@ _XimProcEvent( + ev->xany.serial |= serial << 16; + ev->xany.send_event = False; + ev->xany.display = d; +- MARK_FABRICATED(ic->core.im); ++ _XimFabricateSerial((Xim)ic->core.im, ev->xany.serial); + return; + } + +@@ -727,10 +775,6 @@ _XimCommitRecv( + + (void)_XimRespSyncReply(ic, flag); + +- if (ic->private.proto.registed_filter_event +- & (KEYPRESS_MASK | KEYRELEASE_MASK)) +- MARK_FABRICATED(im); +- + bzero(&ev, sizeof(ev)); /* uninitialized : found when running kterm under valgrind */ + + ev.type = KeyPress; +@@ -742,6 +786,10 @@ _XimCommitRecv( + + ev.time = 0L; + ev.serial = LastKnownRequestProcessed(im->core.display); ++ ++ if (ic->private.proto.registed_filter_event ++ & (KEYPRESS_MASK | KEYRELEASE_MASK)) ++ _XimFabricateSerial(im, ev.serial); + /* FIXME : + I wish there were COMMENTs (!) about the data passed around. + */ +diff --git a/src/xlibi18n/XimintP.h b/src/xlibi18n/XimintP.h +index 14a7e6d5..7f5b107a 100644 +--- a/src/xlibi18n/XimintP.h ++++ b/src/xlibi18n/XimintP.h +@@ -149,6 +149,8 @@ typedef struct _XimProtoPrivateRec { + XimTransRegDispatcher register_dispatcher; + XimTransCallDispatcher call_dispatcher; + XPointer spec; ++ ++ unsigned long fabricated_serial; + } XimProtoPrivateRec; + + /* +@@ -307,4 +309,19 @@ typedef struct _XicProtoPrivateRec { + #define XIM_MAXIMNAMELEN 64 + #define XIM_MAXLCNAMELEN 64 + ++Bool ++_XimFabricateSerial( ++ Xim im, ++ unsigned long serial); ++ ++Bool ++_XimUnfabricateSerial( ++ Xim im, ++ unsigned long serial); ++ ++Bool ++_XimIsFabricatedSerial( ++ Xim im, ++ unsigned long serial); ++ + #endif /* _XIMINTP_H */ +-- +2.47.1 + diff --git a/0002-imDefLkup-Commit-first-info-in-XimCommitInfo.patch b/0002-imDefLkup-Commit-first-info-in-XimCommitInfo.patch new file mode 100644 index 0000000..48b6711 --- /dev/null +++ b/0002-imDefLkup-Commit-first-info-in-XimCommitInfo.patch @@ -0,0 +1,158 @@ +From a1037538b74e4016c3a1c2ebef9b1836811ed687 Mon Sep 17 00:00:00 2001 +From: Takao Fujiwara +Date: Fri, 12 Apr 2024 10:21:43 +0900 +Subject: [PATCH libX11 2/7] imDefLkup: Commit first info in XimCommitInfo + +Xic.private.proto.commit_info can receive multiple XimCommitInfo +when typing keys very quickly like an bar code scanner (or evemu-play) +and the first info in XimCommitInfo should be committed to keep +the typing key order. + +This and 041b5291 are same patches but the regression issues will be +fixed by the later patches. + +Closes: #198 +Fixes: 041b5291 ("imDefLkup: Commit first info in XimCommitInfo") +Part-of: +(cherry picked from commit c7790072657f9fdbe8cda031776617088c5f11db) +--- + modules/im/ximcp/imDefLkup.c | 60 +++++++++++++++++++++++++++++------- + 1 file changed, 49 insertions(+), 11 deletions(-) + +diff --git a/modules/im/ximcp/imDefLkup.c b/modules/im/ximcp/imDefLkup.c +index a6923d5b..31205e6b 100644 +--- a/modules/im/ximcp/imDefLkup.c ++++ b/modules/im/ximcp/imDefLkup.c +@@ -650,18 +650,29 @@ _XimRegCommitInfo( + } + + static void +-_XimUnregCommitInfo( +- Xic ic) ++_XimUnregRealCommitInfo( ++ Xic ic, ++ Bool reverse) + { + XimCommitInfo info; ++ XimCommitInfo prev_info = NULL; + +- if (!(info = ic->private.proto.commit_info)) ++ info = ic->private.proto.commit_info; ++ while (reverse && info) { ++ if (!info->next) ++ break; ++ prev_info = info; ++ info = info->next; ++ } ++ if (!info) + return; + +- + Xfree(info->string); + Xfree(info->keysym); +- ic->private.proto.commit_info = info->next; ++ if (prev_info) ++ prev_info->next = info->next; ++ else ++ ic->private.proto.commit_info = info->next; + Xfree(info); + + /* +@@ -679,6 +690,20 @@ _XimUnregCommitInfo( + return; + } + ++static void ++_XimUnregCommitInfo( ++ Xic ic) ++{ ++ _XimUnregRealCommitInfo(ic, False); ++} ++ ++static void ++_XimUnregFirstCommitInfo( ++ Xic ic) ++{ ++ _XimUnregRealCommitInfo(ic, True); ++} ++ + void + _XimFreeCommitInfo( + Xic ic) +@@ -688,6 +713,19 @@ _XimFreeCommitInfo( + return; + } + ++static XimCommitInfo ++_XimFirstCommitInfo( ++ Xic ic) ++{ ++ XimCommitInfo info = ic->private.proto.commit_info; ++ while (info) { ++ if (!info->next) ++ break; ++ info = info->next; ++ } ++ return info; ++} ++ + static Bool + _XimProcKeySym( + Xic ic, +@@ -1082,7 +1120,7 @@ _XimProtoMbLookupString( + state = &tmp_state; + + if ((ev->type == KeyPress) && (ev->keycode == 0)) { /* Filter function */ +- if (!(info = ic->private.proto.commit_info)) { ++ if (!(info = _XimFirstCommitInfo(ic))) { + *state = XLookupNone; + return 0; + } +@@ -1098,7 +1136,7 @@ _XimProtoMbLookupString( + else + *state = XLookupKeySym; + } +- _XimUnregCommitInfo(ic); ++ _XimUnregFirstCommitInfo(ic); + + } else if (ev->type == KeyPress) { + ret = _XimLookupMBText(ic, ev, buffer, bytes, keysym, NULL); +@@ -1145,7 +1183,7 @@ _XimProtoWcLookupString( + state = &tmp_state; + + if (ev->type == KeyPress && ev->keycode == 0) { /* Filter function */ +- if (!(info = ic->private.proto.commit_info)) { ++ if (!(info = _XimFirstCommitInfo(ic))) { + *state = XLookupNone; + return 0; + } +@@ -1161,7 +1199,7 @@ _XimProtoWcLookupString( + else + *state = XLookupKeySym; + } +- _XimUnregCommitInfo(ic); ++ _XimUnregFirstCommitInfo(ic); + + } else if (ev->type == KeyPress) { + ret = _XimLookupWCText(ic, ev, buffer, bytes, keysym, NULL); +@@ -1208,7 +1246,7 @@ _XimProtoUtf8LookupString( + state = &tmp_state; + + if (ev->type == KeyPress && ev->keycode == 0) { /* Filter function */ +- if (!(info = ic->private.proto.commit_info)) { ++ if (!(info = _XimFirstCommitInfo(ic))) { + *state = XLookupNone; + return 0; + } +@@ -1224,7 +1262,7 @@ _XimProtoUtf8LookupString( + else + *state = XLookupKeySym; + } +- _XimUnregCommitInfo(ic); ++ _XimUnregFirstCommitInfo(ic); + + } else if (ev->type == KeyPress) { + ret = _XimLookupUTF8Text(ic, ev, buffer, bytes, keysym, NULL); +-- +2.47.1 + diff --git a/0003-imDefLkup-Mark-and-unmark-fabricated-with-serial-0.patch b/0003-imDefLkup-Mark-and-unmark-fabricated-with-serial-0.patch new file mode 100644 index 0000000..98d3a04 --- /dev/null +++ b/0003-imDefLkup-Mark-and-unmark-fabricated-with-serial-0.patch @@ -0,0 +1,65 @@ +From ed53956985d37c57fcd3587c642ee7ebf653d1af Mon Sep 17 00:00:00 2001 +From: Takao Fujiwara +Date: Fri, 12 Apr 2024 10:50:33 +0900 +Subject: [PATCH libX11 3/7] imDefLkup: Mark and unmark fabricated with serial + 0 + +GTK2 applications with GTK_IM_MODULE=xim sets the serial number 0 +to the XKeyEvent and the previous _XimFabricateSerial() logic did +not work for the applications. +Now the API marks to fabricate with the serial 0. + +Closes: #205 +Fixes: 024d229f ("ximcp: Unmark to fabricate key events with XKeyEvent serial") +Part-of: +(cherry picked from commit 1181abd6ffede3ac5663a3a3d4ee66aef1fa553b) +--- + modules/im/ximcp/imDefLkup.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/modules/im/ximcp/imDefLkup.c b/modules/im/ximcp/imDefLkup.c +index 31205e6b..53cf1f87 100644 +--- a/modules/im/ximcp/imDefLkup.c ++++ b/modules/im/ximcp/imDefLkup.c +@@ -356,8 +356,11 @@ _XimFabricateSerial( + Xim im, + unsigned long serial) + { +- if (!serial) +- return False; ++ /* GTK2 XIM module sets serial=0. */ ++ if (!serial) { ++ MARK_FABRICATED(im); ++ return True; ++ } + if (serial == im->private.proto.fabricated_serial) { + fprintf(stderr, "%s,%d: The key event is already fabricated.\n", __FILE__, __LINE__); + return False; +@@ -375,8 +378,11 @@ _XimUnfabricateSerial( + Xim im, + unsigned long serial) + { +- if (!serial) +- return False; ++ /* GTK2 XIM module sets serial=0. */ ++ if (!serial) { ++ UNMARK_FABRICATED(im); ++ return True; ++ } + if (!im->private.proto.fabricated_serial) { + fprintf(stderr, "%s,%d: The key event is already unfabricated.\n", __FILE__, __LINE__); + return False; +@@ -394,8 +400,9 @@ _XimIsFabricatedSerial( + Xim im, + unsigned long serial) + { ++ /* GTK2 XIM module sets serial=0. */ + if (!serial) +- return False; ++ return IS_FABRICATED(im); + return (serial == im->private.proto.fabricated_serial); + } + +-- +2.47.1 + diff --git a/0004-ximcp-Add-fabricated_time-in-XimProtoPrivate-for-tim.patch b/0004-ximcp-Add-fabricated_time-in-XimProtoPrivate-for-tim.patch new file mode 100644 index 0000000..fd31753 --- /dev/null +++ b/0004-ximcp-Add-fabricated_time-in-XimProtoPrivate-for-tim.patch @@ -0,0 +1,216 @@ +From 24f2fdba4e5162ebcb011ce41104fb195b163169 Mon Sep 17 00:00:00 2001 +From: Takao Fujiwara +Date: Fri, 26 Apr 2024 00:49:14 +0900 +Subject: [PATCH libX11 4/7] ximcp: Add fabricated_time in XimProtoPrivate for + timeout + +When users type keys quickly, some applications using Steam or Java +do not call XNextEvent() for a key event but _XimFilterKeypress() +and _XimFilterKeyrelease() expect to receive the key events +forwarded by input methods. + +Now fabricated_time Time value is added to XimProtoPrivate to check +the timeout value. + +Closes: #205 +Fixes: 024d229f ("ximcp: Unmark to fabricate key events with XKeyEvent serial") +Part-of: +(cherry picked from commit 5a14178c7cc408f425fe298aeade3dee749b1ca1) +--- + modules/im/ximcp/imDefFlt.c | 8 +++--- + modules/im/ximcp/imDefIm.c | 2 ++ + modules/im/ximcp/imDefLkup.c | 48 ++++++++++++++++++++++++++---------- + src/xlibi18n/XimintP.h | 10 +++++--- + 4 files changed, 47 insertions(+), 21 deletions(-) + +diff --git a/modules/im/ximcp/imDefFlt.c b/modules/im/ximcp/imDefFlt.c +index a7948df8..ad8a272b 100644 +--- a/modules/im/ximcp/imDefFlt.c ++++ b/modules/im/ximcp/imDefFlt.c +@@ -142,9 +142,9 @@ _XimProtoKeypressFilter( + { + Xim im = (Xim)ic->core.im; + +- if ((ev->keycode == 0) || _XimIsFabricatedSerial(im, ev->serial)) { ++ if ((ev->keycode == 0) || _XimIsFabricatedSerial(im, ev)) { + _XimPendingFilter(ic); +- _XimUnfabricateSerial(im, ev->serial); ++ _XimUnfabricateSerial(im, ev); + return NOTFILTERD; + } + +@@ -203,9 +203,9 @@ _XimProtoKeyreleaseFilter( + { + Xim im = (Xim)ic->core.im; + +- if (_XimIsFabricatedSerial(im, ev->serial)) { ++ if (_XimIsFabricatedSerial(im, ev)) { + _XimPendingFilter(ic); +- _XimUnfabricateSerial(im, ev->serial); ++ _XimUnfabricateSerial(im, ev); + return NOTFILTERD; + } + +diff --git a/modules/im/ximcp/imDefIm.c b/modules/im/ximcp/imDefIm.c +index a231a0ac..7eba0b34 100644 +--- a/modules/im/ximcp/imDefIm.c ++++ b/modules/im/ximcp/imDefIm.c +@@ -431,6 +431,8 @@ _XimPreConnect( + + im->private.proto.im_window = im_window; + im->private.proto.fabricated_serial = 0; ++ im->private.proto.fabricated_time = 0; ++ im->private.proto.enable_fabricated_order = True; + return True; + } + +diff --git a/modules/im/ximcp/imDefLkup.c b/modules/im/ximcp/imDefLkup.c +index 53cf1f87..6b2d27dc 100644 +--- a/modules/im/ximcp/imDefLkup.c ++++ b/modules/im/ximcp/imDefLkup.c +@@ -354,14 +354,14 @@ _XimForwardEvent( + Bool + _XimFabricateSerial( + Xim im, +- unsigned long serial) ++ XKeyEvent *event) + { + /* GTK2 XIM module sets serial=0. */ +- if (!serial) { ++ if (!event->serial || !im->private.proto.enable_fabricated_order) { + MARK_FABRICATED(im); + return True; + } +- if (serial == im->private.proto.fabricated_serial) { ++ if (event->serial == im->private.proto.fabricated_serial) { + fprintf(stderr, "%s,%d: The key event is already fabricated.\n", __FILE__, __LINE__); + return False; + } +@@ -369,17 +369,18 @@ _XimFabricateSerial( + fprintf(stderr, "%s,%d: Tried to fabricate a wrong key event.\n", __FILE__, __LINE__); + + MARK_FABRICATED(im); +- im->private.proto.fabricated_serial = serial; ++ im->private.proto.fabricated_serial = event->serial; ++ im->private.proto.fabricated_time = event->time; + return True; + } + + Bool + _XimUnfabricateSerial( + Xim im, +- unsigned long serial) ++ XKeyEvent *event) + { + /* GTK2 XIM module sets serial=0. */ +- if (!serial) { ++ if (!event->serial || !im->private.proto.enable_fabricated_order) { + UNMARK_FABRICATED(im); + return True; + } +@@ -387,10 +388,11 @@ _XimUnfabricateSerial( + fprintf(stderr, "%s,%d: The key event is already unfabricated.\n", __FILE__, __LINE__); + return False; + } +- if (serial != im->private.proto.fabricated_serial) ++ if (event->serial != im->private.proto.fabricated_serial) + fprintf(stderr, "%s,%d: Tried to unfabricate a wrong key event.\n", __FILE__, __LINE__); + + im->private.proto.fabricated_serial = 0; ++ im->private.proto.fabricated_time = 0; + UNMARK_FABRICATED(im); + return True; + } +@@ -398,12 +400,32 @@ _XimUnfabricateSerial( + Bool + _XimIsFabricatedSerial( + Xim im, +- unsigned long serial) ++ XKeyEvent *event) + { + /* GTK2 XIM module sets serial=0. */ +- if (!serial) +- return IS_FABRICATED(im); +- return (serial == im->private.proto.fabricated_serial); ++ if (!event->serial || !im->private.proto.enable_fabricated_order) ++ return IS_FABRICATED(im) ? True : False; ++ if (event->serial == im->private.proto.fabricated_serial) ++ return True; ++ if (!im->private.proto.fabricated_serial) ++ return False; ++ /* Rotate time */ ++ if (event->time < im->private.proto.fabricated_time) { ++ if (event->time >= 1000) ++ im->private.proto.fabricated_time = 0; ++ } else if (event->time - im->private.proto.fabricated_time > 1000) { ++ fprintf(stderr, ++ "%s,%d: The application disposed a key event with %ld serial.\n", ++ __FILE__, __LINE__, ++ im->private.proto.fabricated_serial); ++ im->private.proto.enable_fabricated_order = False; ++ if (IS_FABRICATED(im)) { ++ if (event->serial) ++ im->private.proto.fabricated_serial = event->serial; ++ return True; ++ } ++ } ++ return False; + } + + static void +@@ -420,7 +442,7 @@ _XimProcEvent( + ev->xany.serial |= serial << 16; + ev->xany.send_event = False; + ev->xany.display = d; +- _XimFabricateSerial((Xim)ic->core.im, ev->xany.serial); ++ _XimFabricateSerial((Xim)ic->core.im, &ev->xkey); + return; + } + +@@ -834,7 +856,7 @@ _XimCommitRecv( + + if (ic->private.proto.registed_filter_event + & (KEYPRESS_MASK | KEYRELEASE_MASK)) +- _XimFabricateSerial(im, ev.serial); ++ _XimFabricateSerial(im, &ev); + /* FIXME : + I wish there were COMMENTs (!) about the data passed around. + */ +diff --git a/src/xlibi18n/XimintP.h b/src/xlibi18n/XimintP.h +index 7f5b107a..715800c7 100644 +--- a/src/xlibi18n/XimintP.h ++++ b/src/xlibi18n/XimintP.h +@@ -150,7 +150,9 @@ typedef struct _XimProtoPrivateRec { + XimTransCallDispatcher call_dispatcher; + XPointer spec; + +- unsigned long fabricated_serial; ++ unsigned long fabricated_serial; ++ Time fabricated_time; ++ Bool enable_fabricated_order; + } XimProtoPrivateRec; + + /* +@@ -312,16 +314,16 @@ typedef struct _XicProtoPrivateRec { + Bool + _XimFabricateSerial( + Xim im, +- unsigned long serial); ++ XKeyEvent *event); + + Bool + _XimUnfabricateSerial( + Xim im, +- unsigned long serial); ++ XKeyEvent *event); + + Bool + _XimIsFabricatedSerial( + Xim im, +- unsigned long serial); ++ XKeyEvent *event); + + #endif /* _XIMINTP_H */ +-- +2.47.1 + diff --git a/0005-Accept-anon-windows-in-XFilterEvent-to-update-XIM-st.patch b/0005-Accept-anon-windows-in-XFilterEvent-to-update-XIM-st.patch new file mode 100644 index 0000000..147cf6e --- /dev/null +++ b/0005-Accept-anon-windows-in-XFilterEvent-to-update-XIM-st.patch @@ -0,0 +1,168 @@ +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 + diff --git a/0006-ximcp-Unmark-fabricated-with-serial-0-and-Xic-commit.patch b/0006-ximcp-Unmark-fabricated-with-serial-0-and-Xic-commit.patch new file mode 100644 index 0000000..23c29db --- /dev/null +++ b/0006-ximcp-Unmark-fabricated-with-serial-0-and-Xic-commit.patch @@ -0,0 +1,82 @@ +From 546a51348322d83a57fd9b8c1e42b44fbe970368 Mon Sep 17 00:00:00 2001 +From: Takao Fujiwara +Date: Fri, 26 Apr 2024 01:29:34 +0900 +Subject: [PATCH libX11 6/7] ximcp: Unmark fabricated with serial 0 and Xic + commit_info + +GTK2 XIM resets the XKeyEvent serial to 0 even if _XimCommitRecv() +sets the serial so now checks if the events are sent with +Xic->private.proto.commit_info. + +Closes: !246 +Part-of: +(cherry picked from commit 898746f9b1fb384d6d24ed827c836ec8a0b3da3b) +--- + modules/im/ximcp/imDefFlt.c | 4 ++-- + modules/im/ximcp/imDefLkup.c | 12 +++++++++++- + src/xlibi18n/XimintP.h | 1 + + 3 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/modules/im/ximcp/imDefFlt.c b/modules/im/ximcp/imDefFlt.c +index 76d63e88..3dfbf8cd 100644 +--- a/modules/im/ximcp/imDefFlt.c ++++ b/modules/im/ximcp/imDefFlt.c +@@ -145,7 +145,7 @@ _XimProtoKeypressFilter( + + if ((ev->keycode == 0) || _XimIsFabricatedSerial(im, ev)) { + _XimPendingFilter(ic); +- _XimUnfabricateSerial(im, ev); ++ _XimUnfabricateSerial(im, ic, ev); + return NOTFILTERD; + } + /* w=0 is used for _XimIsFabricatedSerial() only */ +@@ -210,7 +210,7 @@ _XimProtoKeyreleaseFilter( + + if (_XimIsFabricatedSerial(im, ev)) { + _XimPendingFilter(ic); +- _XimUnfabricateSerial(im, ev); ++ _XimUnfabricateSerial(im, ic, ev); + return NOTFILTERD; + } + /* w=0 is used for _XimIsFabricatedSerial() only */ +diff --git a/modules/im/ximcp/imDefLkup.c b/modules/im/ximcp/imDefLkup.c +index 6b2d27dc..326339fe 100644 +--- a/modules/im/ximcp/imDefLkup.c ++++ b/modules/im/ximcp/imDefLkup.c +@@ -377,10 +377,20 @@ _XimFabricateSerial( + Bool + _XimUnfabricateSerial( + Xim im, ++ Xic ic, + XKeyEvent *event) + { ++ if (!im->private.proto.enable_fabricated_order) { ++ UNMARK_FABRICATED(im); ++ return True; ++ } + /* GTK2 XIM module sets serial=0. */ +- if (!event->serial || !im->private.proto.enable_fabricated_order) { ++ if (!event->serial) { ++ /* _XimCommitRecv() sets event->serial and call _XimFabricateSerial() ++ * but GTK2 XIM always reset event->serial=0 with XFilterEvent(). ++ */ ++ if (ic && ic->private.proto.commit_info) ++ im->private.proto.fabricated_serial = 0; + UNMARK_FABRICATED(im); + return True; + } +diff --git a/src/xlibi18n/XimintP.h b/src/xlibi18n/XimintP.h +index 715800c7..fe52231e 100644 +--- a/src/xlibi18n/XimintP.h ++++ b/src/xlibi18n/XimintP.h +@@ -319,6 +319,7 @@ _XimFabricateSerial( + Bool + _XimUnfabricateSerial( + Xim im, ++ Xic ic, + XKeyEvent *event); + + Bool +-- +2.47.1 + diff --git a/0007-imDefIm-Add-LIBX11_ENABLE_FABRICATED_ORDER-env.patch b/0007-imDefIm-Add-LIBX11_ENABLE_FABRICATED_ORDER-env.patch new file mode 100644 index 0000000..6a80930 --- /dev/null +++ b/0007-imDefIm-Add-LIBX11_ENABLE_FABRICATED_ORDER-env.patch @@ -0,0 +1,58 @@ +From 9abd669f8826909a715e9b19531fd687800ce44c Mon Sep 17 00:00:00 2001 +From: Takao Fujiwara +Date: Fri, 26 Apr 2024 01:29:39 +0900 +Subject: [PATCH libX11 7/7] imDefIm: Add LIBX11_ENABLE_FABRICATED_ORDER env + +If an XIM application does not return the XKeyEvent from XNextEvent() +to XFilterEvent(), a timeout is reached and the behavior is fallen +back to the previous one with a warning messsage and we can ask +the application to send the XKeyEvent to XFilterEvent() but also +libX11 provides LIBX11_ENABLE_FABRICATED_ORDER environment variable. +If the application runs with LIBX11_ENABLE_FABRICATED_ORDER=0, the +previous behavior is available until the application is fixed. + +Closes: !246 +Part-of: +(cherry picked from commit 90b8fc65da1e773b0091a50be46b23609591e8b7) +--- + modules/im/ximcp/imDefIm.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/modules/im/ximcp/imDefIm.c b/modules/im/ximcp/imDefIm.c +index 7eba0b34..f42aa92c 100644 +--- a/modules/im/ximcp/imDefIm.c ++++ b/modules/im/ximcp/imDefIm.c +@@ -63,6 +63,8 @@ PERFORMANCE OF THIS SOFTWARE. + #include "Ximint.h" + + #include ++#include ++#include + + int + _XimCheckDataSize( +@@ -400,6 +402,7 @@ _XimPreConnect( + Atom *atoms; + Window im_window = 0; + register int i; ++ const char *env_enable_fabricated_order; + + if((imserver = XInternAtom(display, XIM_SERVERS, True)) == (Atom)None) + return False; +@@ -433,6 +436,13 @@ _XimPreConnect( + im->private.proto.fabricated_serial = 0; + im->private.proto.fabricated_time = 0; + im->private.proto.enable_fabricated_order = True; ++ env_enable_fabricated_order = getenv("LIBX11_ENABLE_FABRICATED_ORDER"); ++ if (env_enable_fabricated_order && *env_enable_fabricated_order) { ++ if (!strncasecmp(env_enable_fabricated_order, "0", 2) || ++ !strncasecmp(env_enable_fabricated_order, "false", 6)) { ++ im->private.proto.enable_fabricated_order = False; ++ } ++ } + return True; + } + +-- +2.47.1 + diff --git a/libX11.spec b/libX11.spec index 1aca733..45a65a3 100644 --- a/libX11.spec +++ b/libX11.spec @@ -5,7 +5,7 @@ Summary: Core X11 protocol client library Name: libX11 Version: 1.7.0 -Release: 10%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} +Release: 11%{?gitdate:.%{gitdate}git%{gitversion}}%{?dist} License: MIT URL: http://www.x.org @@ -36,6 +36,15 @@ Patch9: 0001-CVE-2023-43787-Integer-overflow-in-XCreateImage-lead.patch # https://issues.redhat.com/browse/RHEL-58298 Patch10: 0001-imDefLkup-verify-that-a-pointer-isn-t-NULL-before-us.patch +# https://issues.redhat.com/browse/RHEL-69791 +Patch11: 0001-ximcp-Unmark-to-fabricate-key-events-with-XKeyEvent-.patch +Patch12: 0002-imDefLkup-Commit-first-info-in-XimCommitInfo.patch +Patch13: 0003-imDefLkup-Mark-and-unmark-fabricated-with-serial-0.patch +Patch14: 0004-ximcp-Add-fabricated_time-in-XimProtoPrivate-for-tim.patch +Patch15: 0005-Accept-anon-windows-in-XFilterEvent-to-update-XIM-st.patch +Patch16: 0006-ximcp-Unmark-fabricated-with-serial-0-and-Xic-commit.patch +Patch17: 0007-imDefIm-Add-LIBX11_ENABLE_FABRICATED_ORDER-env.patch + BuildRequires: make BuildRequires: xorg-x11-util-macros >= 1.11 BuildRequires: pkgconfig(xproto) >= 7.0.15 @@ -138,6 +147,9 @@ make %{?_smp_mflags} check %{_mandir}/man5/*.5* %changelog +* Fri Dec 13 2024 Olivier Fourdan - 1.7.0-11 +- Backport fixes for XIM input sometimes jumbled (RHEL-69791) + * Fri Sep 13 2024 José Expósito - 1.7.0-10 - Backport NULL check to avoid a crash Resolves: https://issues.redhat.com/browse/RHEL-58298