summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfujiwarat <takao.fujiwara1@gmail.com>2022-11-10 18:38:05 +0900
committerfujiwarat <takao.fujiwara1@gmail.com>2022-11-10 18:38:05 +0900
commit506ac9993d5166196b7c4e9bfa9fb0f9d3792ffa (patch)
tree23da7cd75cfef791be42b8e4e402eb390540d1fd
parentcd621f8b82c80a174cd880cb27f27d7ccb9cb4d4 (diff)
downloadibus-506ac9993d5166196b7c4e9bfa9fb0f9d3792ffa.tar.gz
client/x11: Implement new process_key_event for ibus-x11
The new process_key_event is ported from GTK4 to X11 because hangul maintainers wish to delete forward_key_event as much as possible and currently we could apply forward_key_event to the sync mode only and the new process_key_event is a new async key event process in X11 and hangul might disable forward_key_event by default. Now the definition of IBUS_CAP_SYNC_PROCESS_KEY_V2 capability is changed to set only if the sync mode. Also switch a heavy GMainLoop to the light GSource. Fixes: https://github.com/ibus/ibus/commit/c957c5f
-rw-r--r--client/gtk2/ibusimcontext.c61
-rw-r--r--client/x11/main.c157
-rw-r--r--src/ibustypes.h1
3 files changed, 184 insertions, 35 deletions
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
index 6e338157..1f3723e6 100644
--- a/client/gtk2/ibusimcontext.c
+++ b/client/gtk2/ibusimcontext.c
@@ -382,8 +382,9 @@ typedef struct {
} ProcessKeyEventData;
typedef struct {
- GMainLoop *loop;
- gboolean retval;
+ int count;
+ guint count_cb_id;
+ gboolean retval;
} ProcessKeyEventReplyData;
static void
@@ -453,7 +454,23 @@ _process_key_event_reply_done (GObject *object,
}
g_return_if_fail (data);
data->retval = retval;
- g_main_loop_quit (data->loop);
+ data->count = 0;
+ g_source_remove (data->count_cb_id);
+}
+
+static gboolean
+_process_key_event_count_cb (gpointer user_data)
+{
+ ProcessKeyEventReplyData *data = (ProcessKeyEventReplyData *)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;
+ return G_SOURCE_REMOVE;
+ }
+ return G_SOURCE_CONTINUE;
}
static gboolean
@@ -496,10 +513,10 @@ _process_key_event (IBusInputContext *context,
break;
}
case 2: {
- GMainLoop *loop = g_main_loop_new (NULL, TRUE);
+ GSource *source = g_timeout_source_new (1);
ProcessKeyEventReplyData *data = NULL;
- if (loop)
+ if (source)
data = g_slice_new0 (ProcessKeyEventReplyData);
if (!data) {
g_warning ("Cannot wait for the reply of the process key event.");
@@ -507,11 +524,14 @@ _process_key_event (IBusInputContext *context,
keyval,
keycode - 8,
state);
- if (loop)
- g_main_loop_quit (loop);
+ if (source)
+ g_source_destroy (source);
break;
}
- data->loop = loop;
+ data->count = 1;
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+ data->count_cb_id = g_source_get_id (source);
ibus_input_context_process_key_event_async (context,
keyval,
keycode - 8,
@@ -520,7 +540,14 @@ _process_key_event (IBusInputContext *context,
NULL,
_process_key_event_reply_done,
data);
- g_main_loop_run (loop);
+ g_source_set_callback (source, _process_key_event_count_cb, data, NULL);
+ while (data->count)
+ g_main_context_iteration (NULL, TRUE);
+ if (source->ref_count > 0) {
+ /* g_source_get_id() could causes a SEGV */
+ g_info ("Broken GSource.ref_count and maybe a timing issue in %p.",
+ source);
+ }
retval = data->retval;
g_slice_free (ProcessKeyEventReplyData, data);
break;
@@ -994,8 +1021,8 @@ ibus_im_context_init (GObject *obj)
#else
ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS;
#endif
- if (_use_sync_mode != 1)
- ibusimcontext->caps |= IBUS_CAP_SYNC_PROCESS_KEY;
+ if (_use_sync_mode == 1)
+ ibusimcontext->caps |= IBUS_CAP_SYNC_PROCESS_KEY_V2;
ibusimcontext->events_queue = g_queue_new ();
@@ -1338,7 +1365,7 @@ ibus_im_context_reset (GtkIMContext *context)
* IBus uses button-press-event instead until GTK is fixed.
* https://gitlab.gnome.org/GNOME/gtk/issues/1534
*/
- if (_use_sync_mode == 1)
+ if (_use_sync_mode != 0)
ibus_im_context_clear_preedit_text (ibusimcontext);
ibus_input_context_reset (ibusimcontext->ibuscontext);
}
@@ -1453,7 +1480,7 @@ ibus_im_context_set_client_window (GtkIMContext *context,
if (ibusimcontext->client_window) {
#if !GTK_CHECK_VERSION (3, 98, 4)
- if (ibusimcontext->use_button_press_event && _use_sync_mode != 1)
+ if (ibusimcontext->use_button_press_event && _use_sync_mode == 0)
_connect_button_press_event (ibusimcontext, FALSE);
#endif
g_object_unref (ibusimcontext->client_window);
@@ -1463,7 +1490,7 @@ ibus_im_context_set_client_window (GtkIMContext *context,
if (client != NULL) {
ibusimcontext->client_window = g_object_ref (client);
#if !GTK_CHECK_VERSION (3, 98, 4)
- if (!ibusimcontext->use_button_press_event && _use_sync_mode != 1)
+ if (!ibusimcontext->use_button_press_event && _use_sync_mode == 0)
_connect_button_press_event (ibusimcontext, TRUE);
#endif
}
@@ -2085,7 +2112,7 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext,
#if !GTK_CHECK_VERSION (3, 98, 4)
if (!ibusimcontext->use_button_press_event &&
mode == IBUS_ENGINE_PREEDIT_COMMIT &&
- _use_sync_mode != 1) {
+ _use_sync_mode == 0) {
if (ibusimcontext->client_window) {
_connect_button_press_event (ibusimcontext, TRUE);
}
@@ -2459,8 +2486,8 @@ _create_fake_input_context_done (IBusBus *bus,
NULL);
guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT;
- if (_use_sync_mode != 1)
- caps |= IBUS_CAP_SYNC_PROCESS_KEY;
+ if (_use_sync_mode == 1)
+ caps |= IBUS_CAP_SYNC_PROCESS_KEY_V2;
ibus_input_context_set_capabilities (_fake_context, caps);
/* focus in/out the fake context */
diff --git a/client/x11/main.c b/client/x11/main.c
index 6057cc03..905fd251 100644
--- a/client/x11/main.c
+++ b/client/x11/main.c
@@ -124,7 +124,7 @@ static gint g_debug_level = 0;
static IBusBus *_bus = NULL;
-static gboolean _use_sync_mode = TRUE;
+static char _use_sync_mode = 2;
static void
_xim_preedit_start (XIMS xims, const X11IC *x11ic)
@@ -331,6 +331,7 @@ xim_create_ic (XIMS xims, IMChangeICStruct *call_data)
{
static int base_icid = 1;
X11IC *x11ic;
+ guint32 capabilities = IBUS_CAP_FOCUS;
call_data->icid = base_icid ++;
@@ -375,12 +376,11 @@ xim_create_ic (XIMS xims, IMChangeICStruct *call_data)
G_CALLBACK (_context_disabled_cb), x11ic);
- if (x11ic->input_style & XIMPreeditCallbacks) {
- ibus_input_context_set_capabilities (x11ic->context, IBUS_CAP_FOCUS | IBUS_CAP_PREEDIT_TEXT);
- }
- else {
- ibus_input_context_set_capabilities (x11ic->context, IBUS_CAP_FOCUS);
- }
+ if (x11ic->input_style & XIMPreeditCallbacks)
+ capabilities |= IBUS_CAP_PREEDIT_TEXT;
+ if (_use_sync_mode == 1)
+ capabilities |= IBUS_CAP_SYNC_PROCESS_KEY_V2;
+ ibus_input_context_set_capabilities (x11ic->context, capabilities);
g_hash_table_insert (_x11_ic_table,
GINT_TO_POINTER (x11ic->icid), (gpointer)x11ic);
@@ -461,6 +461,13 @@ xim_unset_ic_focus (XIMS xims, IMChangeFocusStruct *call_data)
}
+typedef struct {
+ IMForwardEventStruct *pfe;
+ int count;
+ guint count_cb_id;
+ gboolean retval;
+} ProcessKeyEventReplyData;
+
static void
_process_key_event_done (GObject *object,
GAsyncResult *res,
@@ -493,6 +500,43 @@ _process_key_event_done (GObject *object,
g_slice_free (IMForwardEventStruct, pfe);
}
+static void
+_process_key_event_reply_done (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ IBusInputContext *context = (IBusInputContext *)object;
+ ProcessKeyEventReplyData *data = (ProcessKeyEventReplyData *)user_data;
+ GError *error = NULL;
+ gboolean retval = ibus_input_context_process_key_event_async_finish (
+ context,
+ res,
+ &error);
+ if (error != NULL) {
+ g_warning ("Process Key Event failed: %s.", error->message);
+ g_error_free (error);
+ }
+ g_return_if_fail (data);
+ data->retval = retval;
+ data->count = 0;
+ g_source_remove (data->count_cb_id);
+}
+
+static gboolean
+_process_key_event_count_cb (gpointer user_data)
+{
+ ProcessKeyEventReplyData *data = (ProcessKeyEventReplyData *)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;
+ return G_SOURCE_REMOVE;
+ }
+ return G_SOURCE_CONTINUE;
+}
+
static int
xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
{
@@ -520,14 +564,15 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
event.state |= IBUS_RELEASE_MASK;
}
- if (_use_sync_mode) {
+ switch (_use_sync_mode) {
+ case 1: {
retval = ibus_input_context_process_key_event (
x11ic->context,
event.keyval,
event.hardware_keycode - 8,
event.state);
if (retval) {
- if (! x11ic->has_preedit_area) {
+ if (!x11ic->has_preedit_area) {
_xim_set_cursor_location (x11ic);
}
return 1;
@@ -546,8 +591,80 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
IMForwardEvent (_xims, (XPointer) &fe);
retval = 1;
+ break;
}
- else {
+ case 2: {
+ GSource *source = g_timeout_source_new (1);
+ ProcessKeyEventReplyData *data = NULL;
+ IMForwardEventStruct fe;
+
+ if (source)
+ data = g_slice_new0 (ProcessKeyEventReplyData);
+ if (!data) {
+ g_warning ("Cannot wait for the reply of the process key event.");
+ retval = ibus_input_context_process_key_event (
+ x11ic->context,
+ event.keyval,
+ event.hardware_keycode - 8,
+ event.state);
+ 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);
+ ibus_input_context_process_key_event_async (
+ x11ic->context,
+ event.keyval,
+ event.hardware_keycode - 8,
+ event.state,
+ -1,
+ NULL,
+ _process_key_event_reply_done,
+ data);
+ g_source_set_callback (source, _process_key_event_count_cb,
+ data, NULL);
+ while (data->count)
+ g_main_context_iteration (NULL, TRUE);
+ if (source->ref_count > 0) {
+ /* g_source_get_id() could causes a SEGV */
+ g_info ("Broken GSource.ref_count and maybe a timing "
+ "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) {
+ return 1;
+ }
+ }
+
+ if (retval) {
+ if (! x11ic->has_preedit_area) {
+ _xim_set_cursor_location (x11ic);
+ }
+ 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);
+
+ retval = 1;
+ break;
+ }
+ default: {
IMForwardEventStruct *pfe;
pfe = g_slice_new0 (IMForwardEventStruct);
@@ -569,6 +686,7 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
pfe);
retval = 1;
}
+ }
return retval;
}
@@ -1026,23 +1144,26 @@ _context_disabled_cb (IBusInputContext *context,
_xim_preedit_end (_xims, x11ic);
}
-static gboolean
-_get_boolean_env(const gchar *name,
- gboolean defval)
+static char
+_get_char_env (const gchar *name,
+ char defval)
{
const gchar *value = g_getenv (name);
if (value == NULL)
- return defval;
+ return defval;
if (g_strcmp0 (value, "") == 0 ||
g_strcmp0 (value, "0") == 0 ||
g_strcmp0 (value, "false") == 0 ||
g_strcmp0 (value, "False") == 0 ||
- g_strcmp0 (value, "FALSE") == 0)
- return FALSE;
+ g_strcmp0 (value, "FALSE") == 0) {
+ return 0;
+ } else if (!g_strcmp0 (value, "2")) {
+ return 2;
+ }
- return TRUE;
+ return 1;
}
static void
@@ -1059,7 +1180,7 @@ _init_ibus (void)
G_CALLBACK (_bus_disconnected_cb), NULL);
/* https://github.com/ibus/ibus/issues/1713 */
- _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", TRUE);
+ _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 2);
}
static void
diff --git a/src/ibustypes.h b/src/ibustypes.h
index a8eee319..ba2a0010 100644
--- a/src/ibustypes.h
+++ b/src/ibustypes.h
@@ -124,6 +124,7 @@ typedef enum {
IBUS_CAP_SURROUNDING_TEXT = 1 << 5,
IBUS_CAP_OSK = 1 << 6,
IBUS_CAP_SYNC_PROCESS_KEY = 1 << 7,
+ IBUS_CAP_SYNC_PROCESS_KEY_V2 = IBUS_CAP_SYNC_PROCESS_KEY,
} IBusCapabilite;
/**