diff options
author | fujiwarat <takao.fujiwara1@gmail.com> | 2022-11-10 18:38:05 +0900 |
---|---|---|
committer | fujiwarat <takao.fujiwara1@gmail.com> | 2022-11-10 18:38:05 +0900 |
commit | 506ac9993d5166196b7c4e9bfa9fb0f9d3792ffa (patch) | |
tree | 23da7cd75cfef791be42b8e4e402eb390540d1fd | |
parent | cd621f8b82c80a174cd880cb27f27d7ccb9cb4d4 (diff) | |
download | ibus-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.c | 61 | ||||
-rw-r--r-- | client/x11/main.c | 157 | ||||
-rw-r--r-- | src/ibustypes.h | 1 |
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; /** |