325 lines
11 KiB
Diff
325 lines
11 KiB
Diff
From 497f0c74230a65309e22ce5569060ce48310406b Mon Sep 17 00:00:00 2001
|
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
|
Date: Thu, 23 Mar 2023 13:07:30 +0900
|
|
Subject: [PATCH] client/x11: Fix Key typing order
|
|
|
|
ibus-x11 now also uses the hybrid process key events with
|
|
IBUS_ENABLE_SYNC_MODE=2 and it waits for the async API
|
|
with GSource and g_main_context_iteration() in xim_forward_event().
|
|
|
|
But g_main_context_iteration() calls gdk_event_source_dispatch()
|
|
and it can call another xim_forward_event() and the callbacks
|
|
of ibus_input_context_process_key_event_async() can be nested.
|
|
So if the forwarding API is called out of the callbacks of
|
|
ibus_input_context_process_key_event_async(), the key events
|
|
order is swapped due to the delayed return of
|
|
g_main_context_iteration().
|
|
|
|
To resolve this issue, the forwarding API should be called in
|
|
the callbacks of ibus_input_context_process_key_event_async().
|
|
|
|
Fixes: https://github.com/ibus/ibus/commit/506ac99
|
|
|
|
BUG=https://github.com/ibus/ibus/issues/2480
|
|
---
|
|
client/x11/main.c | 160 ++++++++++++++++++++++++----------------------
|
|
1 file changed, 83 insertions(+), 77 deletions(-)
|
|
|
|
diff --git a/client/x11/main.c b/client/x11/main.c
|
|
index 905fd2516..83d95cb75 100644
|
|
--- a/client/x11/main.c
|
|
+++ b/client/x11/main.c
|
|
@@ -2,7 +2,7 @@
|
|
/* vim:set et sts=4: */
|
|
/* ibus
|
|
* Copyright (C) 2007-2015 Peng Huang <shawn.p.huang@gmail.com>
|
|
- * Copyright (C) 2015-2022 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2015-2023 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
* Copyright (C) 2007-2015 Red Hat, Inc.
|
|
*
|
|
* main.c:
|
|
@@ -49,6 +49,8 @@
|
|
#include <getopt.h>
|
|
|
|
#define ESC_SEQUENCE_ISO10646_1 "\033%G"
|
|
+/* Wait for about 120 secs to return a key from async process-key-event. */
|
|
+#define MAX_WAIT_KEY_TIME 120000
|
|
|
|
#define LOG(level, fmt_args...) \
|
|
if (g_debug_level >= (level)) { \
|
|
@@ -461,11 +463,39 @@ xim_unset_ic_focus (XIMS xims, IMChangeFocusStruct *call_data)
|
|
|
|
}
|
|
|
|
+static void
|
|
+_xim_forward_key_event_done (X11IC *x11ic,
|
|
+ XEvent *event,
|
|
+ gboolean processed)
|
|
+{
|
|
+ IMForwardEventStruct fe;
|
|
+ if (processed) {
|
|
+ if (!x11ic->has_preedit_area) {
|
|
+ _xim_set_cursor_location (x11ic);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ g_assert (x11ic);
|
|
+ g_assert (event);
|
|
+
|
|
+ memset (&fe, 0, sizeof (fe));
|
|
+ fe.major_code = XIM_FORWARD_EVENT;
|
|
+ fe.icid = x11ic->icid;
|
|
+ fe.connect_id = x11ic->connect_id;
|
|
+ fe.sync_bit = 0;
|
|
+ fe.serial_number = 0L;
|
|
+ fe.event = *event;
|
|
+ IMForwardEvent (_xims, (XPointer) &fe);
|
|
+}
|
|
+
|
|
+
|
|
typedef struct {
|
|
- IMForwardEventStruct *pfe;
|
|
int count;
|
|
guint count_cb_id;
|
|
gboolean retval;
|
|
+ X11IC *x11ic;
|
|
+ CARD16 connect_id;
|
|
+ XEvent event;
|
|
} ProcessKeyEventReplyData;
|
|
|
|
static void
|
|
@@ -474,7 +504,7 @@ _process_key_event_done (GObject *object,
|
|
gpointer user_data)
|
|
{
|
|
IBusInputContext *context = (IBusInputContext *)object;
|
|
- IMForwardEventStruct *pfe = (IMForwardEventStruct*) user_data;
|
|
+ ProcessKeyEventReplyData *data = (ProcessKeyEventReplyData *)user_data;
|
|
|
|
GError *error = NULL;
|
|
gboolean retval = ibus_input_context_process_key_event_async_finish (
|
|
@@ -488,16 +518,15 @@ _process_key_event_done (GObject *object,
|
|
}
|
|
|
|
if (g_hash_table_lookup (_connections,
|
|
- GINT_TO_POINTER ((gint) pfe->connect_id))
|
|
+ GINT_TO_POINTER ((gint)data->connect_id))
|
|
== NULL) {
|
|
- g_slice_free (IMForwardEventStruct, pfe);
|
|
+ g_slice_free (ProcessKeyEventReplyData, data);
|
|
return;
|
|
}
|
|
|
|
- if (retval == FALSE) {
|
|
- IMForwardEvent (_xims, (XPointer) pfe);
|
|
- }
|
|
- g_slice_free (IMForwardEventStruct, pfe);
|
|
+ if (retval == FALSE)
|
|
+ _xim_forward_key_event_done (data->x11ic, &data->event, retval);
|
|
+ g_slice_free (ProcessKeyEventReplyData, data);
|
|
}
|
|
|
|
static void
|
|
@@ -518,6 +547,21 @@ _process_key_event_reply_done (GObject *object,
|
|
}
|
|
g_return_if_fail (data);
|
|
data->retval = retval;
|
|
+ if (g_hash_table_lookup (_connections,
|
|
+ GINT_TO_POINTER ((gint)data->connect_id))
|
|
+ == NULL) {
|
|
+ return;
|
|
+ }
|
|
+ /* _xim_forward_key_event_done() should be called in
|
|
+ * _process_key_event_reply_done() because g_main_context_iteration()
|
|
+ * can call another xim_forward_event() and xim_forward_event() can be
|
|
+ * nested and the first _process_key_event_reply_done() is returned
|
|
+ * at last with g_main_context_iteration() so
|
|
+ * if _xim_forward_key_event_done() is called out of
|
|
+ * _process_key_event_reply_done(), the key events order
|
|
+ * can be swapped.
|
|
+ */
|
|
+ _xim_forward_key_event_done (data->x11ic, &data->event, retval);
|
|
data->count = 0;
|
|
g_source_remove (data->count_cb_id);
|
|
}
|
|
@@ -529,9 +573,8 @@ _process_key_event_count_cb (gpointer user_data)
|
|
g_return_val_if_fail (data, G_SOURCE_REMOVE);
|
|
if (!data->count)
|
|
return G_SOURCE_REMOVE;
|
|
- /* Wait for about 10 secs. */
|
|
- if (data->count++ == 10000) {
|
|
- data->count = 0;
|
|
+ if (data->count++ == MAX_WAIT_KEY_TIME) {
|
|
+ g_warning ("Key event is not returned for %usecs.", MAX_WAIT_KEY_TIME);
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
return G_SOURCE_CONTINUE;
|
|
@@ -571,32 +614,13 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
|
|
event.keyval,
|
|
event.hardware_keycode - 8,
|
|
event.state);
|
|
- if (retval) {
|
|
- if (!x11ic->has_preedit_area) {
|
|
- _xim_set_cursor_location (x11ic);
|
|
- }
|
|
- return 1;
|
|
- }
|
|
-
|
|
- IMForwardEventStruct fe;
|
|
- memset (&fe, 0, sizeof (fe));
|
|
-
|
|
- fe.major_code = XIM_FORWARD_EVENT;
|
|
- fe.icid = x11ic->icid;
|
|
- fe.connect_id = x11ic->connect_id;
|
|
- fe.sync_bit = 0;
|
|
- fe.serial_number = 0L;
|
|
- fe.event = call_data->event;
|
|
-
|
|
- IMForwardEvent (_xims, (XPointer) &fe);
|
|
-
|
|
+ _xim_forward_key_event_done (x11ic, &call_data->event, retval);
|
|
retval = 1;
|
|
break;
|
|
}
|
|
case 2: {
|
|
GSource *source = g_timeout_source_new (1);
|
|
ProcessKeyEventReplyData *data = NULL;
|
|
- IMForwardEventStruct fe;
|
|
|
|
if (source)
|
|
data = g_slice_new0 (ProcessKeyEventReplyData);
|
|
@@ -610,11 +634,13 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
|
|
if (source)
|
|
g_source_destroy (source);
|
|
} else {
|
|
- CARD16 connect_id = x11ic->connect_id;
|
|
data->count = 1;
|
|
g_source_attach (source, NULL);
|
|
g_source_unref (source);
|
|
data->count_cb_id = g_source_get_id (source);
|
|
+ data->connect_id = call_data->connect_id;
|
|
+ data->x11ic = x11ic;
|
|
+ data->event = *((XEvent*)xevent);
|
|
ibus_input_context_process_key_event_async (
|
|
x11ic->context,
|
|
event.keyval,
|
|
@@ -626,7 +652,7 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
|
|
data);
|
|
g_source_set_callback (source, _process_key_event_count_cb,
|
|
data, NULL);
|
|
- while (data->count)
|
|
+ while (data->count > 0 && data->count < MAX_WAIT_KEY_TIME)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
if (source->ref_count > 0) {
|
|
/* g_source_get_id() could causes a SEGV */
|
|
@@ -634,46 +660,33 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
|
|
"issue in %p.", source);
|
|
}
|
|
retval = data->retval;
|
|
- g_slice_free (ProcessKeyEventReplyData, data);
|
|
-
|
|
- if (g_hash_table_lookup (_connections,
|
|
- GINT_TO_POINTER ((gint)connect_id))
|
|
- == NULL) {
|
|
+ if (data->count == 0) {
|
|
+ g_slice_free (ProcessKeyEventReplyData, data);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
- if (retval) {
|
|
- if (! x11ic->has_preedit_area) {
|
|
- _xim_set_cursor_location (x11ic);
|
|
- }
|
|
- return 1;
|
|
+ g_slice_free (ProcessKeyEventReplyData, data);
|
|
+ if (g_hash_table_lookup (_connections,
|
|
+ GINT_TO_POINTER ((gint)call_data->connect_id))
|
|
+ == NULL) {
|
|
+ return 1;
|
|
}
|
|
-
|
|
- memset (&fe, 0, sizeof (fe));
|
|
-
|
|
- fe.major_code = XIM_FORWARD_EVENT;
|
|
- fe.icid = x11ic->icid;
|
|
- fe.connect_id = x11ic->connect_id;
|
|
- fe.sync_bit = 0;
|
|
- fe.serial_number = 0L;
|
|
- fe.event = call_data->event;
|
|
-
|
|
- IMForwardEvent (_xims, (XPointer) &fe);
|
|
-
|
|
+ _xim_forward_key_event_done (x11ic, &call_data->event, retval);
|
|
retval = 1;
|
|
break;
|
|
}
|
|
default: {
|
|
- IMForwardEventStruct *pfe;
|
|
+ ProcessKeyEventReplyData *data;
|
|
|
|
- pfe = g_slice_new0 (IMForwardEventStruct);
|
|
- pfe->major_code = XIM_FORWARD_EVENT;
|
|
- pfe->icid = x11ic->icid;
|
|
- pfe->connect_id = x11ic->connect_id;
|
|
- pfe->sync_bit = 0;
|
|
- pfe->serial_number = 0L;
|
|
- pfe->event = call_data->event;
|
|
+ if (!(data = g_slice_new0 (ProcessKeyEventReplyData))) {
|
|
+ g_warning ("Cannot allocate async data");
|
|
+ _xim_forward_key_event_done (x11ic, &call_data->event, 0);
|
|
+ return 1;
|
|
+ }
|
|
+ data->connect_id = call_data->connect_id;
|
|
+ data->x11ic = x11ic;
|
|
+ data->event = call_data->event;
|
|
|
|
ibus_input_context_process_key_event_async (
|
|
x11ic->context,
|
|
@@ -683,7 +696,7 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
|
|
-1,
|
|
NULL,
|
|
_process_key_event_done,
|
|
- pfe);
|
|
+ data);
|
|
retval = 1;
|
|
}
|
|
}
|
|
@@ -962,11 +975,10 @@ _xim_forward_key_event (X11IC *x11ic,
|
|
guint keycode,
|
|
guint state)
|
|
{
|
|
- g_return_if_fail (x11ic != NULL);
|
|
-
|
|
- IMForwardEventStruct fe = {0};
|
|
XEvent xkp = {0};
|
|
|
|
+ g_return_if_fail (x11ic != NULL);
|
|
+
|
|
xkp.xkey.type = (state & IBUS_RELEASE_MASK) ? KeyRelease : KeyPress;
|
|
xkp.xkey.serial = 0L;
|
|
xkp.xkey.send_event = False;
|
|
@@ -975,20 +987,14 @@ _xim_forward_key_event (X11IC *x11ic,
|
|
xkp.xkey.window =
|
|
x11ic->focus_window ? x11ic->focus_window : x11ic->client_window;
|
|
xkp.xkey.subwindow = None;
|
|
- xkp.xkey.root = DefaultRootWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
|
|
+ xkp.xkey.root = DefaultRootWindow (
|
|
+ GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
|
|
|
|
xkp.xkey.time = 0;
|
|
xkp.xkey.state = state;
|
|
xkp.xkey.keycode = (keycode == 0) ? 0 : keycode + 8;
|
|
|
|
- fe.major_code = XIM_FORWARD_EVENT;
|
|
- fe.icid = x11ic->icid;
|
|
- fe.connect_id = x11ic->connect_id;
|
|
- fe.sync_bit = 0;
|
|
- fe.serial_number = 0L;
|
|
- fe.event = xkp;
|
|
-
|
|
- IMForwardEvent (_xims, (XPointer) & fe);
|
|
+ _xim_forward_key_event_done (x11ic, &xkp, FALSE);
|
|
}
|
|
|
|
static void
|