3254 lines
122 KiB
Diff
3254 lines
122 KiB
Diff
|
From 5cfe838715097d61b50da55f80bcff2c698ca885 Mon Sep 17 00:00:00 2001
|
||
|
From: Changwoo Ryu <cwryu@debian.org>
|
||
|
Date: Fri, 18 Feb 2022 09:07:02 +0900
|
||
|
Subject: [PATCH] client/gtk2/ibusimcontext: Fix forward key keycode for GTK4
|
||
|
|
||
|
When a keycode is provided (!= 0) for a forwarded key event, convert it to a
|
||
|
GTK keycode before passing it to gtk_im_context_filter_key().
|
||
|
|
||
|
Also free GdkKeymapKey after gdk_display_map_keyval() is called.
|
||
|
|
||
|
BUG=https://github.com/ibus/ibus/issues/2380
|
||
|
BUG=https://github.com/ibus/ibus/issues/2382
|
||
|
---
|
||
|
client/gtk2/ibusimcontext.c | 5 ++++-
|
||
|
1 file changed, 4 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
|
||
|
index c2df3a87..a5e5e792 100644
|
||
|
--- a/client/gtk2/ibusimcontext.c
|
||
|
+++ b/client/gtk2/ibusimcontext.c
|
||
|
@@ -1945,7 +1945,9 @@ _ibus_context_forward_key_event_cb (IBusInputContext *ibuscontext,
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
int group = 0;
|
||
|
g_return_if_fail (GTK_IS_IM_CONTEXT (ibusimcontext));
|
||
|
- if (keycode == 0 && ibusimcontext->client_window) {
|
||
|
+ if (keycode != 0) {
|
||
|
+ keycode += 8; // to GTK keycode
|
||
|
+ } else if (ibusimcontext->client_window) {
|
||
|
GdkDisplay *display =
|
||
|
gtk_widget_get_display (ibusimcontext->client_window);
|
||
|
GdkKeymapKey *keys = NULL;
|
||
|
@@ -1953,6 +1955,7 @@ _ibus_context_forward_key_event_cb (IBusInputContext *ibuscontext,
|
||
|
if (gdk_display_map_keyval (display, keyval, &keys, &n_keys)) {
|
||
|
keycode = keys->keycode;
|
||
|
group = keys->group;
|
||
|
+ g_free (keys);
|
||
|
} else {
|
||
|
g_warning ("Failed to parse keycode from keyval %x", keyval);
|
||
|
}
|
||
|
--
|
||
|
2.37.3
|
||
|
|
||
|
From 8711dc83225a7fade3ba67ab796ecb03b38406ff Mon Sep 17 00:00:00 2001
|
||
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
||
|
Date: Fri, 20 May 2022 20:54:58 +0900
|
||
|
Subject: [PATCH] client/gtk2/ibusimcontext: keycode - 8 for gtk3 keycode
|
||
|
generation
|
||
|
|
||
|
Since IBus keycode subtracts 8 from Linux keycode, keycodes from
|
||
|
gdk_keymap_get_entries_for_keyval() also have to be subtracted 8.
|
||
|
The keycodes will add 8 when they bring back the GDK event loop.
|
||
|
---
|
||
|
client/gtk2/ibusimcontext.c | 7 +++++--
|
||
|
1 file changed, 5 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
|
||
|
index a5e5e792..07835a24 100644
|
||
|
--- a/client/gtk2/ibusimcontext.c
|
||
|
+++ b/client/gtk2/ibusimcontext.c
|
||
|
@@ -2,8 +2,8 @@
|
||
|
/* vim:set et sts=4: */
|
||
|
/* ibus - The Input Bus
|
||
|
* Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
|
||
|
- * Copyright (C) 2015-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
||
|
- * Copyright (C) 2008-2021 Red Hat, Inc.
|
||
|
+ * Copyright (C) 2015-2022 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
||
|
+ * Copyright (C) 2008-2022 Red Hat, Inc.
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
@@ -1980,6 +1980,9 @@ _ibus_context_forward_key_event_cb (IBusInputContext *ibuscontext,
|
||
|
keycode = keys->keycode;
|
||
|
else
|
||
|
g_warning ("Failed to parse keycode from keyval %x", keyval);
|
||
|
+ /* _create_gdk_event() will add 8 to keycode. */
|
||
|
+ if (keycode != 0)
|
||
|
+ keycode -= 8;
|
||
|
}
|
||
|
GdkEventKey *event = _create_gdk_event (ibusimcontext, keyval, keycode, state);
|
||
|
gdk_event_put ((GdkEvent *)event);
|
||
|
--
|
||
|
2.37.3
|
||
|
|
||
|
From 3e5fab4991f4e2e22b56cf57d4dfb779a1d1977c Mon Sep 17 00:00:00 2001
|
||
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
||
|
Date: Fri, 20 May 2022 20:54:59 +0900
|
||
|
Subject: [PATCH] client/gtk2: Revert CCedilla change for pt-BR
|
||
|
|
||
|
gtk_im_context_simple_add_table() is deprecated in GTK4.
|
||
|
I decide to delete gtk_im_context_simple_add_table() here because
|
||
|
the change 03c9e591430c62354bbf26ef7bd4a2e6acfb7c8f is no longer needed
|
||
|
because IBusEngineSimple has implemented to load pt_br compose key
|
||
|
by locale.
|
||
|
|
||
|
Fixes: 03c9e591430c62354bbf26ef7bd4a2e6acfb7c8f
|
||
|
|
||
|
BUG=chromium-os:11421
|
||
|
BUG=http://codereview.appspot.com/3989060
|
||
|
---
|
||
|
client/gtk2/ibusimcontext.c | 31 -------------------------------
|
||
|
1 file changed, 31 deletions(-)
|
||
|
|
||
|
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
|
||
|
index 07835a24..c7f23293 100644
|
||
|
--- a/client/gtk2/ibusimcontext.c
|
||
|
+++ b/client/gtk2/ibusimcontext.c
|
||
|
@@ -874,33 +874,6 @@ ibus_im_context_class_fini (IBusIMContextClass *class)
|
||
|
g_bus_unwatch_name (_daemon_name_watch_id);
|
||
|
}
|
||
|
|
||
|
-/* Copied from gtk+2.0-2.20.1/modules/input/imcedilla.c to fix crosbug.com/11421.
|
||
|
- * Overwrite the original Gtk+'s compose table in gtk+-2.x.y/gtk/gtkimcontextsimple.c. */
|
||
|
-
|
||
|
-/* The difference between this and the default input method is the handling
|
||
|
- * of C+acute - this method produces C WITH CEDILLA rather than C WITH ACUTE.
|
||
|
- * For languages that use CCedilla and not acute, this is the preferred mapping,
|
||
|
- * and is particularly important for pt_BR, where the us-intl keyboard is
|
||
|
- * used extensively.
|
||
|
- */
|
||
|
-static guint16 cedilla_compose_seqs[] = {
|
||
|
-#ifdef DEPRECATED_GDK_KEYSYMS
|
||
|
- GDK_dead_acute, GDK_C, 0, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_dead_acute, GDK_c, 0, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_Multi_key, GDK_apostrophe, GDK_C, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_Multi_key, GDK_apostrophe, GDK_c, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_Multi_key, GDK_C, GDK_apostrophe, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_Multi_key, GDK_c, GDK_apostrophe, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
|
||
|
-#else
|
||
|
- GDK_KEY_dead_acute, GDK_KEY_C, 0, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_KEY_dead_acute, GDK_KEY_c, 0, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_KEY_Multi_key, GDK_KEY_apostrophe, GDK_KEY_C, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_KEY_Multi_key, GDK_KEY_apostrophe, GDK_KEY_c, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_KEY_Multi_key, GDK_KEY_C, GDK_KEY_apostrophe, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */
|
||
|
- GDK_KEY_Multi_key, GDK_KEY_c, GDK_KEY_apostrophe, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */
|
||
|
-#endif
|
||
|
-};
|
||
|
-
|
||
|
static void
|
||
|
ibus_im_context_init (GObject *obj)
|
||
|
{
|
||
|
@@ -936,10 +909,6 @@ ibus_im_context_init (GObject *obj)
|
||
|
|
||
|
// Create slave im context
|
||
|
ibusimcontext->slave = gtk_im_context_simple_new ();
|
||
|
- gtk_im_context_simple_add_table (GTK_IM_CONTEXT_SIMPLE (ibusimcontext->slave),
|
||
|
- cedilla_compose_seqs,
|
||
|
- 4,
|
||
|
- G_N_ELEMENTS (cedilla_compose_seqs) / (4 + 2));
|
||
|
|
||
|
g_signal_connect (ibusimcontext->slave,
|
||
|
"commit",
|
||
|
--
|
||
|
2.37.3
|
||
|
|
||
|
From b94f0c1cea5d0e423fef3bcc13b23f212f04c930 Mon Sep 17 00:00:00 2001
|
||
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
||
|
Date: Thu, 7 Jul 2022 08:13:57 +0900
|
||
|
Subject: [PATCH] src: Add IBUS_CAP_OSK to IBusCapabilite
|
||
|
|
||
|
Some IMEs' behavior is different between the on-screen keyboard and
|
||
|
the direct physical keyboard and this flag is useful for the IMEs.
|
||
|
|
||
|
Also fix src/ibusaccelgroup.c for gtkdoc-mkhtml.
|
||
|
If the API comment of IBusCapabilite is updated, XML & HTML files
|
||
|
are rebuilt and gtk-doc-1.33.2 no longer accepts HTML tags in
|
||
|
the comments.
|
||
|
|
||
|
diff --git a/src/ibusaccelgroup.c b/src/ibusaccelgroup.c
|
||
|
index ef2d3976..aec1c7e4 100644
|
||
|
--- a/src/ibusaccelgroup.c
|
||
|
+++ b/src/ibusaccelgroup.c
|
||
|
@@ -267,14 +267,14 @@ is_keycode (const gchar *string)
|
||
|
* modifier mask, %NULL
|
||
|
*
|
||
|
* Parses a string representing an accelerator. The format looks like
|
||
|
- * “<Control>a” or “<Shift><Alt>F1” or “<Release>z” (the last one is
|
||
|
- * for key release).
|
||
|
+ * “<Control>a” or “<Shift><Alt>F1” or “<Release%gt;z”
|
||
|
+ * (the last one is for key release).
|
||
|
*
|
||
|
* The parser is fairly liberal and allows lower or upper case, and also
|
||
|
- * abbreviations such as “<Ctl>” and “<Ctrl>”. Key names are parsed using
|
||
|
- * gdk_keyval_from_name(). For character keys the name is not the symbol,
|
||
|
- * but the lowercase name, e.g. one would use “<Ctrl>minus” instead of
|
||
|
- * “<Ctrl>-”.
|
||
|
+ * abbreviations such as “<Ctl>” and “<Ctrl>”. Key names are
|
||
|
+ * parsed using gdk_keyval_from_name(). For character keys the name is not the
|
||
|
+ * symbol, but the lowercase name, e.g. one would use “<Ctrl>minus”
|
||
|
+ * instead of “<Ctrl>-”.
|
||
|
*
|
||
|
* If the parse fails, @accelerator_key and @accelerator_mods will
|
||
|
* be set to 0 (zero).
|
||
|
@@ -403,7 +403,7 @@ out:
|
||
|
*
|
||
|
* Converts an accelerator keyval and modifier mask into a string
|
||
|
* parseable by gtk_accelerator_parse(). For example, if you pass in
|
||
|
- * #IBUS_KEY_q and #IBUS_CONTROL_MASK, this function returns “<Control>q”.
|
||
|
+ * #IBUS_KEY_q and #IBUS_CONTROL_MASK, this function returns “<Control>q”.
|
||
|
*
|
||
|
* If you need to display accelerators in the user interface,
|
||
|
* see gtk_accelerator_get_label().
|
||
|
diff --git a/src/ibustypes.h b/src/ibustypes.h
|
||
|
index 990659ac..60bcb92b 100644
|
||
|
--- a/src/ibustypes.h
|
||
|
+++ b/src/ibustypes.h
|
||
|
@@ -108,6 +108,7 @@ typedef enum
|
||
|
* @IBUS_CAP_PROPERTY: UI is capable to have property.
|
||
|
* @IBUS_CAP_SURROUNDING_TEXT: Client can provide surround text,
|
||
|
* or IME can handle surround text.
|
||
|
+ * @IBUS_CAP_OSK: UI is owned by on-screen keyboard.
|
||
|
*
|
||
|
* Capability flags of UI.
|
||
|
*/
|
||
|
@@ -118,6 +119,7 @@ typedef enum {
|
||
|
IBUS_CAP_FOCUS = 1 << 3,
|
||
|
IBUS_CAP_PROPERTY = 1 << 4,
|
||
|
IBUS_CAP_SURROUNDING_TEXT = 1 << 5,
|
||
|
+ IBUS_CAP_OSK = 1 << 6,
|
||
|
} IBusCapabilite;
|
||
|
|
||
|
/**
|
||
|
--
|
||
|
2.37.3
|
||
|
|
||
|
From c957c5f6ba07074a8fb56c978c27873c1cfe0783 Mon Sep 17 00:00:00 2001
|
||
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
||
|
Date: Tue, 19 Jul 2022 22:58:24 +0900
|
||
|
Subject: [PATCH] client/gtk2: Implement new process_key_event for GTK4
|
||
|
|
||
|
|
||
|
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
|
||
|
index c7f23293..bc14df00 100644
|
||
|
--- a/client/gtk2/ibusimcontext.c
|
||
|
+++ b/client/gtk2/ibusimcontext.c
|
||
|
@@ -111,13 +111,13 @@ static guint _signal_delete_surrounding_id = 0;
|
||
|
static guint _signal_retrieve_surrounding_id = 0;
|
||
|
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
-static gboolean _use_sync_mode = TRUE;
|
||
|
+static char _use_sync_mode = 2;
|
||
|
#else
|
||
|
static const gchar *_no_snooper_apps = NO_SNOOPER_APPS;
|
||
|
static gboolean _use_key_snooper = ENABLE_SNOOPER;
|
||
|
static guint _key_snooper_id = 0;
|
||
|
|
||
|
-static gboolean _use_sync_mode = FALSE;
|
||
|
+static char _use_sync_mode = 0;
|
||
|
#endif
|
||
|
|
||
|
static const gchar *_discard_password_apps = "";
|
||
|
@@ -375,12 +375,15 @@ ibus_im_context_commit_event (IBusIMContext *ibusimcontext,
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
-struct _ProcessKeyEventData {
|
||
|
+typedef struct {
|
||
|
GdkEvent *event;
|
||
|
IBusIMContext *ibusimcontext;
|
||
|
-};
|
||
|
+} ProcessKeyEventData;
|
||
|
|
||
|
-typedef struct _ProcessKeyEventData ProcessKeyEventData;
|
||
|
+typedef struct {
|
||
|
+ GMainLoop *loop;
|
||
|
+ gboolean retval;
|
||
|
+} ProcessKeyEventReplyData;
|
||
|
|
||
|
static void
|
||
|
_process_key_event_done (GObject *object,
|
||
|
@@ -395,12 +398,12 @@ _process_key_event_done (GObject *object,
|
||
|
IBusIMContext *ibusimcontext = data->ibusimcontext;
|
||
|
#endif
|
||
|
GError *error = NULL;
|
||
|
+ gboolean retval;
|
||
|
|
||
|
g_slice_free (ProcessKeyEventData, data);
|
||
|
- gboolean retval = ibus_input_context_process_key_event_async_finish (
|
||
|
- context,
|
||
|
- res,
|
||
|
- &error);
|
||
|
+ retval = ibus_input_context_process_key_event_async_finish (context,
|
||
|
+ res,
|
||
|
+ &error);
|
||
|
|
||
|
if (error != NULL) {
|
||
|
g_warning ("Process Key Event failed: %s.", error->message);
|
||
|
@@ -431,6 +434,27 @@ _process_key_event_done (GObject *object,
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
+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;
|
||
|
+ g_main_loop_quit (data->loop);
|
||
|
+}
|
||
|
+
|
||
|
static gboolean
|
||
|
_process_key_event (IBusInputContext *context,
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
@@ -462,13 +486,45 @@ _process_key_event (IBusInputContext *context,
|
||
|
#endif
|
||
|
keycode = hardware_keycode;
|
||
|
|
||
|
- if (_use_sync_mode) {
|
||
|
+ switch (_use_sync_mode) {
|
||
|
+ case 1: {
|
||
|
retval = ibus_input_context_process_key_event (context,
|
||
|
+ keyval,
|
||
|
+ keycode - 8,
|
||
|
+ state);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case 2: {
|
||
|
+ GMainLoop *loop = g_main_loop_new (NULL, TRUE);
|
||
|
+ ProcessKeyEventReplyData *data = NULL;
|
||
|
+
|
||
|
+ if (loop)
|
||
|
+ 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 (context,
|
||
|
+ keyval,
|
||
|
+ keycode - 8,
|
||
|
+ state);
|
||
|
+ if (loop)
|
||
|
+ g_main_loop_quit (loop);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ data->loop = loop;
|
||
|
+ ibus_input_context_process_key_event_async (context,
|
||
|
keyval,
|
||
|
keycode - 8,
|
||
|
- state);
|
||
|
+ state,
|
||
|
+ -1,
|
||
|
+ NULL,
|
||
|
+ _process_key_event_reply_done,
|
||
|
+ data);
|
||
|
+ g_main_loop_run (loop);
|
||
|
+ retval = data->retval;
|
||
|
+ g_slice_free (ProcessKeyEventReplyData, data);
|
||
|
+ break;
|
||
|
}
|
||
|
- else {
|
||
|
+ default: {
|
||
|
ProcessKeyEventData *data = g_slice_new0 (ProcessKeyEventData);
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
data->event = gdk_event_ref (event);
|
||
|
@@ -487,6 +543,7 @@ _process_key_event (IBusInputContext *context,
|
||
|
|
||
|
retval = TRUE;
|
||
|
}
|
||
|
+ }
|
||
|
|
||
|
/* GTK4 does not provide gtk_key_snooper_install() and also
|
||
|
* GtkIMContextClass->filter_keypress() cannot send the updated
|
||
|
@@ -676,24 +733,47 @@ _key_snooper_cb (GtkWidget *widget,
|
||
|
#endif
|
||
|
|
||
|
static gboolean
|
||
|
-_get_boolean_env(const gchar *name,
|
||
|
- gboolean defval)
|
||
|
+_get_boolean_env (const gchar *name,
|
||
|
+ gboolean 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 FALSE;
|
||
|
+ }
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
+static char
|
||
|
+_get_char_env (const gchar *name,
|
||
|
+ char defval)
|
||
|
+{
|
||
|
+ const gchar *value = g_getenv (name);
|
||
|
+
|
||
|
+ if (value == NULL)
|
||
|
+ 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 0;
|
||
|
+ } else if (!g_strcmp0 (value, "2")) {
|
||
|
+ return 2;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+
|
||
|
static void
|
||
|
daemon_name_appeared (GDBusConnection *connection,
|
||
|
const gchar *name,
|
||
|
@@ -777,11 +857,11 @@ ibus_im_context_class_init (IBusIMContextClass *class)
|
||
|
g_assert (_signal_retrieve_surrounding_id != 0);
|
||
|
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
- _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", TRUE);
|
||
|
+ _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 2);
|
||
|
#else
|
||
|
_use_key_snooper = !_get_boolean_env ("IBUS_DISABLE_SNOOPER",
|
||
|
!(ENABLE_SNOOPER));
|
||
|
- _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", FALSE);
|
||
|
+ _use_sync_mode = (char)_get_char_env ("IBUS_ENABLE_SYNC_MODE", 0);
|
||
|
#endif
|
||
|
_use_discard_password = _get_boolean_env ("IBUS_DISCARD_PASSWORD", FALSE);
|
||
|
|
||
|
@@ -904,6 +984,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;
|
||
|
|
||
|
ibusimcontext->events_queue = g_queue_new ();
|
||
|
|
||
|
@@ -1246,7 +1328,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)
|
||
|
+ if (_use_sync_mode == 1)
|
||
|
ibus_im_context_clear_preedit_text (ibusimcontext);
|
||
|
ibus_input_context_reset (ibusimcontext->ibuscontext);
|
||
|
}
|
||
|
@@ -1361,7 +1443,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)
|
||
|
+ if (ibusimcontext->use_button_press_event && _use_sync_mode != 1)
|
||
|
_connect_button_press_event (ibusimcontext, FALSE);
|
||
|
#endif
|
||
|
g_object_unref (ibusimcontext->client_window);
|
||
|
@@ -1371,7 +1453,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)
|
||
|
+ if (!ibusimcontext->use_button_press_event && _use_sync_mode != 1)
|
||
|
_connect_button_press_event (ibusimcontext, TRUE);
|
||
|
#endif
|
||
|
}
|
||
|
@@ -1993,7 +2075,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) {
|
||
|
+ _use_sync_mode != 1) {
|
||
|
if (ibusimcontext->client_window) {
|
||
|
_connect_button_press_event (ibusimcontext, TRUE);
|
||
|
}
|
||
|
@@ -2200,6 +2282,8 @@ _create_input_context_done (IBusBus *bus,
|
||
|
static void
|
||
|
_create_input_context (IBusIMContext *ibusimcontext)
|
||
|
{
|
||
|
+ gchar *prgname = g_strdup (g_get_prgname());
|
||
|
+ gchar *client_name;
|
||
|
IDEBUG ("%s", __FUNCTION__);
|
||
|
|
||
|
g_assert (ibusimcontext->ibuscontext == NULL);
|
||
|
@@ -2208,11 +2292,24 @@ _create_input_context (IBusIMContext *ibusimcontext)
|
||
|
|
||
|
ibusimcontext->cancellable = g_cancellable_new ();
|
||
|
|
||
|
+ if (!prgname)
|
||
|
+ prgname = g_strdup_printf ("(%d)", getpid ());
|
||
|
+ client_name = g_strdup_printf ("%s:%s",
|
||
|
+#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
+ "gtk4-im",
|
||
|
+#elif GTK_CHECK_VERSION (2, 91, 0)
|
||
|
+ "gtk3-im",
|
||
|
+#else
|
||
|
+ "gtk-im",
|
||
|
+#endif
|
||
|
+ prgname);
|
||
|
+ g_free (prgname);
|
||
|
ibus_bus_create_input_context_async (_bus,
|
||
|
- "gtk-im", -1,
|
||
|
+ client_name, -1,
|
||
|
ibusimcontext->cancellable,
|
||
|
(GAsyncReadyCallback)_create_input_context_done,
|
||
|
g_object_ref (ibusimcontext));
|
||
|
+ g_free (client_name);
|
||
|
}
|
||
|
|
||
|
/* Callback functions for slave context */
|
||
|
@@ -2329,6 +2426,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;
|
||
|
ibus_input_context_set_capabilities (_fake_context, caps);
|
||
|
|
||
|
/* focus in/out the fake context */
|
||
|
diff --git a/src/ibustypes.h b/src/ibustypes.h
|
||
|
index 60bcb92b..a8eee319 100644
|
||
|
--- a/src/ibustypes.h
|
||
|
+++ b/src/ibustypes.h
|
||
|
@@ -109,6 +109,9 @@ typedef enum
|
||
|
* @IBUS_CAP_SURROUNDING_TEXT: Client can provide surround text,
|
||
|
* or IME can handle surround text.
|
||
|
* @IBUS_CAP_OSK: UI is owned by on-screen keyboard.
|
||
|
+ * @IBUS_CAP_SYNC_PROCESS_KEY: Asynchronous process key events are not
|
||
|
+ * supported and the ibus_engine_forward_key_event() should not be
|
||
|
+ * used for the return value of #IBusEngine::process_key_event().
|
||
|
*
|
||
|
* Capability flags of UI.
|
||
|
*/
|
||
|
@@ -120,6 +123,7 @@ typedef enum {
|
||
|
IBUS_CAP_PROPERTY = 1 << 4,
|
||
|
IBUS_CAP_SURROUNDING_TEXT = 1 << 5,
|
||
|
IBUS_CAP_OSK = 1 << 6,
|
||
|
+ IBUS_CAP_SYNC_PROCESS_KEY = 1 << 7,
|
||
|
} IBusCapabilite;
|
||
|
|
||
|
/**
|
||
|
--
|
||
|
2.41.0
|
||
|
|
||
|
From 506ac9993d5166196b7c4e9bfa9fb0f9d3792ffa Mon Sep 17 00:00:00 2001
|
||
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
||
|
Date: Thu, 10 Nov 2022 18:38:05 +0900
|
||
|
Subject: [PATCH] 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
|
||
|
---
|
||
|
client/gtk2/ibusimcontext.c | 61 ++++++++++----
|
||
|
client/x11/main.c | 157 +++++++++++++++++++++++++++++++-----
|
||
|
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;
|
||
|
|
||
|
/**
|
||
|
--
|
||
|
2.41.0
|
||
|
|
||
|
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 905fd251..83d95cb7 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-2021 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:
|
||
|
@@ -48,6 +48,9 @@
|
||
|
|
||
|
#include <getopt.h>
|
||
|
|
||
|
+/* 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)) { \
|
||
|
g_debug (fmt_args); \
|
||
|
@@ -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
|
||
|
--
|
||
|
2.41.0
|
||
|
|
||
|
From 8f706d160631f1ffdbfa16543a38b9d5f91c16ad Mon Sep 17 00:00:00 2001
|
||
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
||
|
Date: Thu, 23 Mar 2023 13:07:38 +0900
|
||
|
Subject: [PATCH] util/IMdkit: Disable while loop before call
|
||
|
ForwardEventMessageProc()
|
||
|
|
||
|
Seems ProcessQueue() had a wrong XFree() with async process-key-event.
|
||
|
Fixes: https://github.com/ibus/ibus/commit/506ac99
|
||
|
|
||
|
BUG=https://github.com/ibus/ibus/issues/2484
|
||
|
---
|
||
|
util/IMdkit/i18nPtHdr.c | 9 +++------
|
||
|
1 file changed, 3 insertions(+), 6 deletions(-)
|
||
|
|
||
|
diff --git a/util/IMdkit/i18nPtHdr.c b/util/IMdkit/i18nPtHdr.c
|
||
|
index 8dc52714..ec20e322 100644
|
||
|
--- a/util/IMdkit/i18nPtHdr.c
|
||
|
+++ b/util/IMdkit/i18nPtHdr.c
|
||
|
@@ -1747,11 +1747,13 @@ static void ProcessQueue (XIMS ims, CARD16 connect_id)
|
||
|
XimProtoHdr *hdr = (XimProtoHdr *) client->pending->p;
|
||
|
unsigned char *p1 = (unsigned char *) (hdr + 1);
|
||
|
IMProtocol call_data;
|
||
|
+ XIMPending *old = client->pending;
|
||
|
|
||
|
call_data.major_code = hdr->major_opcode;
|
||
|
call_data.any.minor_code = hdr->minor_opcode;
|
||
|
call_data.any.connect_id = connect_id;
|
||
|
|
||
|
+ client->pending = old->next;
|
||
|
switch (hdr->major_opcode)
|
||
|
{
|
||
|
case XIM_FORWARD_EVENT:
|
||
|
@@ -1760,12 +1762,7 @@ static void ProcessQueue (XIMS ims, CARD16 connect_id)
|
||
|
}
|
||
|
/*endswitch*/
|
||
|
XFree (hdr);
|
||
|
- {
|
||
|
- XIMPending *old = client->pending;
|
||
|
-
|
||
|
- client->pending = old->next;
|
||
|
- XFree (old);
|
||
|
- }
|
||
|
+ XFree (old);
|
||
|
}
|
||
|
/*endwhile*/
|
||
|
return;
|
||
|
--
|
||
|
2.41.0
|
||
|
|
||
|
From 38f09c657fd5713e39f698aae43a09a07574f1a6 Mon Sep 17 00:00:00 2001
|
||
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
||
|
Date: Wed, 12 Jul 2023 07:50:22 +0900
|
||
|
Subject: [PATCH] src: Fix sync ibus_input_context_process_key_event()
|
||
|
|
||
|
The synchronous "ProcessKeyEvent" D-Bus method cannot receive
|
||
|
"CommitText" and "ForwardKeyEvent" D-Bus signals during calling the method.
|
||
|
To resolve the issue, now
|
||
|
ibus_input_context_set_post_process_key_event() and
|
||
|
ibus_input_context_post_process_key_event() are added newly.
|
||
|
|
||
|
ibus_input_context_post_process_key_event() retries "CommitText" and
|
||
|
"ForwardKeyEvent" D-Bus signals during calling the "ProcessKeyEvent" D-Bus
|
||
|
method and ibus-daemon does not handle those signals.
|
||
|
|
||
|
"Since: 1.5.00" is added in header files to available APIs before 1.5.29
|
||
|
is released. Will think later how to convert the version comments together
|
||
|
when the new version 1.5.29 is committed.
|
||
|
|
||
|
BUG=https://github.com/ibus/ibus/issues/2486
|
||
|
---
|
||
|
bus/inputcontext.c | 252 ++++++++++++++++++++++++++++++++----
|
||
|
client/gtk2/ibusimcontext.c | 225 ++++++++++++++++++++++----------
|
||
|
src/ibusinputcontext.c | 162 +++++++++++++++++++++--
|
||
|
src/ibusinputcontext.h | 36 +++++-
|
||
|
4 files changed, 567 insertions(+), 108 deletions(-)
|
||
|
|
||
|
diff --git a/bus/inputcontext.c b/bus/inputcontext.c
|
||
|
index 8aded5d8..4d1fb041 100644
|
||
|
--- a/bus/inputcontext.c
|
||
|
+++ b/bus/inputcontext.c
|
||
|
@@ -31,6 +31,8 @@
|
||
|
#include "marshalers.h"
|
||
|
#include "types.h"
|
||
|
|
||
|
+#define MAX_SYNC_DATA 30
|
||
|
+
|
||
|
struct _SetEngineByDescData {
|
||
|
/* context related to the data */
|
||
|
BusInputContext *context;
|
||
|
@@ -46,6 +48,11 @@ struct _SetEngineByDescData {
|
||
|
};
|
||
|
typedef struct _SetEngineByDescData SetEngineByDescData;
|
||
|
|
||
|
+typedef struct _SyncForwardingData {
|
||
|
+ gchar key;
|
||
|
+ IBusText *text;
|
||
|
+} SyncForwardingData;
|
||
|
+
|
||
|
struct _BusInputContext {
|
||
|
IBusService parent;
|
||
|
|
||
|
@@ -99,6 +106,9 @@ struct _BusInputContext {
|
||
|
|
||
|
BusPanelProxy *emoji_extension;
|
||
|
gboolean is_extension_lookup_table;
|
||
|
+ GQueue *queue_during_process_key_event;
|
||
|
+ gboolean use_post_process_key_event;
|
||
|
+ gboolean processing_key_event;
|
||
|
};
|
||
|
|
||
|
struct _BusInputContextClass {
|
||
|
@@ -156,6 +166,15 @@ static void bus_input_context_service_method_call
|
||
|
const gchar *method_name,
|
||
|
GVariant *parameters,
|
||
|
GDBusMethodInvocation *invocation);
|
||
|
+static GVariant *
|
||
|
+ bus_input_context_service_get_property
|
||
|
+ (IBusService *service,
|
||
|
+ GDBusConnection *connection,
|
||
|
+ const gchar *sender,
|
||
|
+ const gchar *object_path,
|
||
|
+ const gchar *interface_name,
|
||
|
+ const gchar *property_name,
|
||
|
+ GError **error);
|
||
|
static gboolean bus_input_context_service_set_property
|
||
|
(IBusService *service,
|
||
|
GDBusConnection *connection,
|
||
|
@@ -214,8 +233,21 @@ static const gchar introspection_xml[] =
|
||
|
"<node>"
|
||
|
" <interface name='org.freedesktop.IBus.InputContext'>"
|
||
|
/* properties */
|
||
|
+ " <property name='PostProcessKeyEvent' type='(a(yv))' access='read'>\n"
|
||
|
+ " <annotation name='org.gtk.GDBus.Since'\n"
|
||
|
+ " value='1.5.29' />\n"
|
||
|
+ " <annotation name='org.gtk.GDBus.DocString'\n"
|
||
|
+ " value='Stability: Unstable' />\n"
|
||
|
+ " </property>\n"
|
||
|
" <property name='ContentType' type='(uu)' access='write' />"
|
||
|
" <property name='ClientCommitPreedit' type='(b)' access='write' />\n"
|
||
|
+ " <property name='EffectivePostProcessKeyEvent' type='(b)' \n"
|
||
|
+ " access='write'>\n"
|
||
|
+ " <annotation name='org.gtk.GDBus.Since'\n"
|
||
|
+ " value='1.5.29' />\n"
|
||
|
+ " <annotation name='org.gtk.GDBus.DocString'\n"
|
||
|
+ " value='Stability: Unstable' />\n"
|
||
|
+ " </property>\n"
|
||
|
/* methods */
|
||
|
" <method name='ProcessKeyEvent'>"
|
||
|
" <arg direction='in' type='u' name='keyval' />"
|
||
|
@@ -348,6 +380,8 @@ bus_input_context_class_init (BusInputContextClass *class)
|
||
|
/* override the parent class's implementation. */
|
||
|
IBUS_SERVICE_CLASS (class)->service_method_call =
|
||
|
bus_input_context_service_method_call;
|
||
|
+ IBUS_SERVICE_CLASS (class)->service_get_property =
|
||
|
+ bus_input_context_service_get_property;
|
||
|
IBUS_SERVICE_CLASS (class)->service_set_property =
|
||
|
bus_input_context_service_set_property;
|
||
|
/* register the xml so that bus_ibus_impl_service_method_call will be called on a method call defined in the xml (e.g. 'FocusIn'.) */
|
||
|
@@ -782,6 +816,11 @@ bus_input_context_property_changed (BusInputContext *context,
|
||
|
}
|
||
|
|
||
|
|
||
|
+typedef struct _PanelProcessKeyEventData {
|
||
|
+ GDBusMethodInvocation *invocation;
|
||
|
+ BusInputContext *context;
|
||
|
+} PanelProcessKeyEventData;
|
||
|
+
|
||
|
/**
|
||
|
* _panel_process_key_event_cb:
|
||
|
*
|
||
|
@@ -789,14 +828,21 @@ bus_input_context_property_changed (BusInputContext *context,
|
||
|
* bus_panel_proxy_process_key_event() is finished.
|
||
|
*/
|
||
|
static void
|
||
|
-_panel_process_key_event_cb (GObject *source,
|
||
|
- GAsyncResult *res,
|
||
|
- GDBusMethodInvocation *invocation)
|
||
|
+_panel_process_key_event_cb (GObject *source,
|
||
|
+ GAsyncResult *res,
|
||
|
+ PanelProcessKeyEventData *data)
|
||
|
{
|
||
|
GError *error = NULL;
|
||
|
GVariant *value = g_dbus_proxy_call_finish ((GDBusProxy *)source,
|
||
|
res,
|
||
|
&error);
|
||
|
+ GDBusMethodInvocation *invocation;
|
||
|
+ BusInputContext *context;
|
||
|
+
|
||
|
+ g_assert (data);
|
||
|
+ invocation = data->invocation;
|
||
|
+ context = data->context;
|
||
|
+ g_slice_free (PanelProcessKeyEventData, data);
|
||
|
if (value != NULL) {
|
||
|
g_dbus_method_invocation_return_value (invocation, value);
|
||
|
g_variant_unref (value);
|
||
|
@@ -805,6 +851,7 @@ _panel_process_key_event_cb (GObject *source,
|
||
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||
|
g_error_free (error);
|
||
|
}
|
||
|
+ context->processing_key_event = FALSE;
|
||
|
}
|
||
|
|
||
|
typedef struct _ProcessKeyEventData ProcessKeyEventData;
|
||
|
@@ -841,21 +888,27 @@ _ic_process_key_event_reply_cb (GObject *source,
|
||
|
gboolean retval = FALSE;
|
||
|
g_variant_get (value, "(b)", &retval);
|
||
|
if (context->emoji_extension && !retval) {
|
||
|
+ PanelProcessKeyEventData *pdata =
|
||
|
+ g_slice_new (PanelProcessKeyEventData);
|
||
|
+ pdata->invocation = invocation;
|
||
|
+ pdata->context = context;
|
||
|
bus_panel_proxy_process_key_event (context->emoji_extension,
|
||
|
keyval,
|
||
|
keycode,
|
||
|
modifiers,
|
||
|
(GAsyncReadyCallback)
|
||
|
_panel_process_key_event_cb,
|
||
|
- invocation);
|
||
|
+ pdata);
|
||
|
} else {
|
||
|
g_dbus_method_invocation_return_value (invocation, value);
|
||
|
+ context->processing_key_event = FALSE;
|
||
|
}
|
||
|
g_variant_unref (value);
|
||
|
}
|
||
|
else {
|
||
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||
|
g_error_free (error);
|
||
|
+ context->processing_key_event = FALSE;
|
||
|
}
|
||
|
|
||
|
g_object_unref (context);
|
||
|
@@ -877,6 +930,8 @@ _ic_process_key_event (BusInputContext *context,
|
||
|
guint keycode = 0;
|
||
|
guint modifiers = 0;
|
||
|
|
||
|
+ if (context->use_post_process_key_event)
|
||
|
+ context->processing_key_event = TRUE;
|
||
|
g_variant_get (parameters, "(uuu)", &keyval, &keycode, &modifiers);
|
||
|
if (G_UNLIKELY (!context->has_focus)) {
|
||
|
/* workaround: set focus if context does not have focus */
|
||
|
@@ -1372,17 +1427,109 @@ bus_input_context_service_method_call (IBusService *service,
|
||
|
g_return_if_reached ();
|
||
|
}
|
||
|
|
||
|
-static void
|
||
|
+/**
|
||
|
+ * _ic_get_post_process_key_event:
|
||
|
+ *
|
||
|
+ * Implement the "PostProcessKeyEvent" get property of the
|
||
|
+ * org.freedesktop.IBus.InputContext interface because currently the Gio
|
||
|
+ * D-Bus method calls don't support multiple nested tuples likes
|
||
|
+ * G_VARIANT_TYPE ("((ba(yv)))")) in "ProcessKeyEvent" D-Bus method
|
||
|
+ * So these post events are separated from the return value "b" of
|
||
|
+ * the "ProcessKeyEvent" D-Bus method call.
|
||
|
+ */
|
||
|
+static GVariant *
|
||
|
+_ic_get_post_process_key_event (BusInputContext *context,
|
||
|
+ GDBusConnection *connection,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ const char *error_message = NULL;
|
||
|
+ GVariantBuilder array;
|
||
|
+ SyncForwardingData *data;
|
||
|
+
|
||
|
+ do {
|
||
|
+ if (!BUS_IS_INPUT_CONTEXT (context)) {
|
||
|
+ error_message = "BusInputContext is freed";
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (context->processing_key_event) {
|
||
|
+ error_message = "Another ProcessKeyEvent is called.";
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ g_variant_builder_init (&array, G_VARIANT_TYPE ("a(yv)"));
|
||
|
+ while ((data =
|
||
|
+ g_queue_pop_head (context->queue_during_process_key_event))) {
|
||
|
+ GVariant *variant = ibus_serializable_serialize_object (
|
||
|
+ IBUS_SERIALIZABLE (data->text));
|
||
|
+ g_variant_builder_add (&array, "(yv)", data->key, variant);
|
||
|
+ g_object_unref (data->text);
|
||
|
+ g_slice_free (SyncForwardingData, data);
|
||
|
+ }
|
||
|
+ } while (FALSE);
|
||
|
+ if (error_message) {
|
||
|
+ g_set_error (error,
|
||
|
+ G_DBUS_ERROR,
|
||
|
+ G_DBUS_ERROR_FAILED,
|
||
|
+ "%s", error_message);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ return g_variant_builder_end (&array);
|
||
|
+}
|
||
|
+
|
||
|
+static GVariant *
|
||
|
+bus_input_context_service_get_property (IBusService *service,
|
||
|
+ GDBusConnection *connection,
|
||
|
+ const gchar *sender,
|
||
|
+ const gchar *object_path,
|
||
|
+ const gchar *interface_name,
|
||
|
+ const gchar *property_name,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+ static const struct {
|
||
|
+ const char *property_name;
|
||
|
+ GVariant * (* property_callback) (BusInputContext *,
|
||
|
+ GDBusConnection *,
|
||
|
+ GError **);
|
||
|
+ } properties [] = {
|
||
|
+ { "PostProcessKeyEvent", _ic_get_post_process_key_event },
|
||
|
+ };
|
||
|
+
|
||
|
+ if (error)
|
||
|
+ *error = NULL;
|
||
|
+ if (g_strcmp0 (interface_name, IBUS_INTERFACE_INPUT_CONTEXT) != 0) {
|
||
|
+ return IBUS_SERVICE_CLASS (bus_input_context_parent_class)->
|
||
|
+ service_get_property (
|
||
|
+ service, connection, sender, object_path,
|
||
|
+ interface_name, property_name,
|
||
|
+ error);
|
||
|
+ }
|
||
|
+ for (i = 0; i < G_N_ELEMENTS (properties); i++) {
|
||
|
+ if (g_strcmp0 (properties[i].property_name, property_name) == 0) {
|
||
|
+ return properties[i].property_callback ((BusInputContext *)service,
|
||
|
+ connection,
|
||
|
+ error);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ g_set_error (error,
|
||
|
+ G_DBUS_ERROR,
|
||
|
+ G_DBUS_ERROR_FAILED,
|
||
|
+ "service_get_property received an unknown property: %s",
|
||
|
+ property_name ? property_name : "(null)");
|
||
|
+ g_return_val_if_reached (NULL);
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
_ic_set_content_type (BusInputContext *context,
|
||
|
- GVariant *value)
|
||
|
+ GVariant *value,
|
||
|
+ GError **error)
|
||
|
{
|
||
|
guint purpose = 0;
|
||
|
guint hints = 0;
|
||
|
+ gboolean retval = TRUE;
|
||
|
|
||
|
g_variant_get (value, "(uu)", &purpose, &hints);
|
||
|
if (purpose != context->purpose || hints != context->hints) {
|
||
|
- GError *error;
|
||
|
- gboolean retval;
|
||
|
|
||
|
context->purpose = purpose;
|
||
|
context->hints = hints;
|
||
|
@@ -1400,24 +1547,30 @@ _ic_set_content_type (BusInputContext *context,
|
||
|
context->hints);
|
||
|
}
|
||
|
|
||
|
- error = NULL;
|
||
|
retval = bus_input_context_property_changed (context,
|
||
|
"ContentType",
|
||
|
value,
|
||
|
- &error);
|
||
|
- if (!retval) {
|
||
|
- g_warning ("Failed to emit PropertiesChanged signal: %s",
|
||
|
- error->message);
|
||
|
- g_error_free (error);
|
||
|
- }
|
||
|
+ error);
|
||
|
}
|
||
|
+ return retval;
|
||
|
}
|
||
|
|
||
|
-static void
|
||
|
+static gboolean
|
||
|
_ic_set_client_commit_preedit (BusInputContext *context,
|
||
|
- GVariant *value)
|
||
|
+ GVariant *value,
|
||
|
+ GError **error)
|
||
|
{
|
||
|
g_variant_get (value, "(b)", &context->client_commit_preedit);
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+_ic_set_use_post_process_key_event (BusInputContext *context,
|
||
|
+ GVariant *value,
|
||
|
+ GError **error)
|
||
|
+{
|
||
|
+ g_variant_get (value, "(b)", &context->use_post_process_key_event);
|
||
|
+ return TRUE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
@@ -1384,6 +1548,18 @@ bus_input_context_service_set_property (
|
||
|
GVariant *value,
|
||
|
GError **error)
|
||
|
{
|
||
|
+ int i;
|
||
|
+ static const struct {
|
||
|
+ const char *property_name;
|
||
|
+ gboolean (* property_callback) (BusInputContext *,
|
||
|
+ GVariant *,
|
||
|
+ GError **);
|
||
|
+ } properties [] = {
|
||
|
+ { "ContentType", _ic_set_content_type },
|
||
|
+ { "ClientCommitPreedit", _ic_set_client_commit_preedit },
|
||
|
+ { "EffectivePostProcessKeyEvent", _ic_set_use_post_process_key_event },
|
||
|
+ };
|
||
|
+
|
||
|
if (g_strcmp0 (interface_name, IBUS_INTERFACE_INPUT_CONTEXT) != 0) {
|
||
|
return IBUS_SERVICE_CLASS (bus_input_context_parent_class)->
|
||
|
service_set_property (service,
|
||
|
@@ -1401,13 +1566,12 @@ bus_input_context_service_set_property (
|
||
|
|
||
|
g_return_val_if_fail (BUS_IS_INPUT_CONTEXT (service), FALSE);
|
||
|
|
||
|
- if (g_strcmp0 (property_name, "ContentType") == 0) {
|
||
|
- _ic_set_content_type (BUS_INPUT_CONTEXT (service), value);
|
||
|
- return TRUE;
|
||
|
- }
|
||
|
- if (g_strcmp0 (property_name, "ClientCommitPreedit") == 0) {
|
||
|
- _ic_set_client_commit_preedit (BUS_INPUT_CONTEXT (service), value);
|
||
|
- return TRUE;
|
||
|
+ for (i = 0; i < G_N_ELEMENTS (properties); i++) {
|
||
|
+ if (g_strcmp0 (properties[i].property_name, property_name) == 0) {
|
||
|
+ return properties[i].property_callback ((BusInputContext *) service,
|
||
|
+ value,
|
||
|
+ error);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
g_return_val_if_reached (FALSE);
|
||
|
@@ -2094,7 +2258,23 @@ _engine_forward_key_event_cb (BusEngineProxy *engine,
|
||
|
g_assert (BUS_IS_INPUT_CONTEXT (context));
|
||
|
|
||
|
g_assert (context->engine == engine);
|
||
|
+ g_assert (context->queue_during_process_key_event);
|
||
|
|
||
|
+ if (context->processing_key_event && g_queue_get_length (
|
||
|
+ context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
+ SyncForwardingData *data;
|
||
|
+ IBusText *text = ibus_text_new_from_printf ("%u,%u,%u",
|
||
|
+ keyval, keycode, state);
|
||
|
+ if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
+ == MAX_SYNC_DATA) {
|
||
|
+ g_warning ("Exceed max number of post process_key_event data");
|
||
|
+ }
|
||
|
+ data = g_slice_new (SyncForwardingData);
|
||
|
+ data->key = 'f';
|
||
|
+ data->text = text;
|
||
|
+ g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
+ return;
|
||
|
+ }
|
||
|
bus_input_context_emit_signal (context,
|
||
|
"ForwardKeyEvent",
|
||
|
g_variant_new ("(uuu)", keyval, keycode, state),
|
||
|
@@ -2455,6 +2634,7 @@ bus_input_context_new (BusConnection *connection,
|
||
|
|
||
|
/* it is a fake input context, just need process hotkey */
|
||
|
context->fake = (strncmp (client, "fake", 4) == 0);
|
||
|
+ context->queue_during_process_key_event = g_queue_new ();
|
||
|
|
||
|
if (connection) {
|
||
|
g_object_ref_sink (connection);
|
||
|
@@ -2938,11 +3118,17 @@ bus_input_context_set_content_type (BusInputContext *context,
|
||
|
guint hints)
|
||
|
{
|
||
|
GVariant *value;
|
||
|
+ GError *error = NULL;
|
||
|
|
||
|
g_assert (BUS_IS_INPUT_CONTEXT (context));
|
||
|
|
||
|
value = g_variant_ref_sink (g_variant_new ("(uu)", purpose, hints));
|
||
|
- _ic_set_content_type (context, value);
|
||
|
+ _ic_set_content_type (context, value, &error);
|
||
|
+ if (error) {
|
||
|
+ g_warning ("Failed to emit PropertiesChanged signal: %s",
|
||
|
+ error->message);
|
||
|
+ g_error_free (error);
|
||
|
+ }
|
||
|
g_variant_unref (value);
|
||
|
}
|
||
|
|
||
|
@@ -2952,12 +3138,24 @@ bus_input_context_commit_text_use_extension (BusInputContext *context,
|
||
|
gboolean use_extension)
|
||
|
{
|
||
|
g_assert (BUS_IS_INPUT_CONTEXT (context));
|
||
|
+ g_assert (context->queue_during_process_key_event);
|
||
|
|
||
|
if (text == text_empty || text == NULL)
|
||
|
return;
|
||
|
|
||
|
if (use_extension && context->emoji_extension) {
|
||
|
bus_panel_proxy_commit_text_received (context->emoji_extension, text);
|
||
|
+ } else if (context->processing_key_event && g_queue_get_length (
|
||
|
+ context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
+ SyncForwardingData *data;
|
||
|
+ if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
+ == MAX_SYNC_DATA) {
|
||
|
+ g_warning ("Exceed max number of sync process_key_event data");
|
||
|
+ }
|
||
|
+ data = g_slice_new (SyncForwardingData);
|
||
|
+ data->key = 'c';
|
||
|
+ data->text = g_object_ref (text);
|
||
|
+ g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
} else {
|
||
|
GVariant *variant = ibus_serializable_serialize (
|
||
|
(IBusSerializable *)text);
|
||
|
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
|
||
|
index ea8270bb..7ccc129d 100644
|
||
|
--- a/client/gtk2/ibusimcontext.c
|
||
|
+++ b/client/gtk2/ibusimcontext.c
|
||
|
@@ -111,7 +111,7 @@ static guint _signal_delete_surrounding_id = 0;
|
||
|
static guint _signal_retrieve_surrounding_id = 0;
|
||
|
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
-static char _use_sync_mode = 2;
|
||
|
+static char _use_sync_mode = 1;
|
||
|
#else
|
||
|
static const gchar *_no_snooper_apps = NO_SNOOPER_APPS;
|
||
|
static gboolean _use_key_snooper = ENABLE_SNOOPER;
|
||
|
@@ -386,6 +386,7 @@ typedef struct {
|
||
|
gboolean retval;
|
||
|
} ProcessKeyEventReplyData;
|
||
|
|
||
|
+
|
||
|
static void
|
||
|
_process_key_event_done (GObject *object,
|
||
|
GAsyncResult *res,
|
||
|
@@ -435,6 +436,7 @@ _process_key_event_done (GObject *object,
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
+
|
||
|
static void
|
||
|
_process_key_event_reply_done (GObject *object,
|
||
|
GAsyncResult *res,
|
||
|
@@ -457,6 +459,7 @@ _process_key_event_reply_done (GObject *object,
|
||
|
g_source_remove (data->count_cb_id);
|
||
|
}
|
||
|
|
||
|
+
|
||
|
static gboolean
|
||
|
_process_key_event_count_cb (gpointer user_data)
|
||
|
{
|
||
|
@@ -472,6 +475,101 @@ _process_key_event_count_cb (gpointer user_data)
|
||
|
return G_SOURCE_CONTINUE;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+static gboolean
|
||
|
+_process_key_event_sync (IBusInputContext *context,
|
||
|
+ guint keyval,
|
||
|
+ guint keycode,
|
||
|
+ guint state)
|
||
|
+{
|
||
|
+ gboolean retval;
|
||
|
+
|
||
|
+ g_assert (IBUS_IS_INPUT_CONTEXT (context));
|
||
|
+ retval = ibus_input_context_process_key_event (context,
|
||
|
+ keyval,
|
||
|
+ keycode - 8,
|
||
|
+ state);
|
||
|
+ ibus_input_context_post_process_key_event (context);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static gboolean
|
||
|
+_process_key_event_async (IBusInputContext *context,
|
||
|
+ guint keyval,
|
||
|
+ guint keycode,
|
||
|
+ guint state,
|
||
|
+ GdkEvent *event,
|
||
|
+ IBusIMContext *ibusimcontext)
|
||
|
+{
|
||
|
+ ProcessKeyEventData *data = g_slice_new0 (ProcessKeyEventData);
|
||
|
+
|
||
|
+ g_assert (event);
|
||
|
+ if (!data) {
|
||
|
+ g_warning ("Cannot allocate async data");
|
||
|
+ return _process_key_event_sync (context, keyval, keycode, state);
|
||
|
+ }
|
||
|
+#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
+ data->event = gdk_event_ref (event);
|
||
|
+#else
|
||
|
+ data->event = gdk_event_copy (event);
|
||
|
+#endif
|
||
|
+ data->ibusimcontext = ibusimcontext;
|
||
|
+ ibus_input_context_process_key_event_async (context,
|
||
|
+ keyval,
|
||
|
+ keycode - 8,
|
||
|
+ state,
|
||
|
+ -1,
|
||
|
+ NULL,
|
||
|
+ _process_key_event_done,
|
||
|
+ data);
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static gboolean
|
||
|
+_process_key_event_hybrid_async (IBusInputContext *context,
|
||
|
+ guint keyval,
|
||
|
+ guint keycode,
|
||
|
+ guint state)
|
||
|
+{
|
||
|
+ GSource *source = g_timeout_source_new (1);
|
||
|
+ ProcessKeyEventReplyData *data = NULL;
|
||
|
+ gboolean retval = FALSE;
|
||
|
+
|
||
|
+ if (source)
|
||
|
+ data = g_slice_new0 (ProcessKeyEventReplyData);
|
||
|
+ if (!data) {
|
||
|
+ g_warning ("Cannot wait for the reply of the process key event.");
|
||
|
+ retval = _process_key_event_sync (context, keyval, keycode, state);
|
||
|
+ if (source)
|
||
|
+ g_source_destroy (source);
|
||
|
+ return retval;
|
||
|
+ }
|
||
|
+ 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,
|
||
|
+ 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);
|
||
|
+ /* #2498 Checking source->ref_count might cause Nautilus hang up
|
||
|
+ */
|
||
|
+ retval = data->retval;
|
||
|
+ g_slice_free (ProcessKeyEventReplyData, data);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
static gboolean
|
||
|
_process_key_event (IBusInputContext *context,
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
@@ -505,70 +603,20 @@ _process_key_event (IBusInputContext *context,
|
||
|
|
||
|
switch (_use_sync_mode) {
|
||
|
case 1: {
|
||
|
- retval = ibus_input_context_process_key_event (context,
|
||
|
- keyval,
|
||
|
- keycode - 8,
|
||
|
- state);
|
||
|
+ retval = _process_key_event_sync (context, keyval, keycode, state);
|
||
|
break;
|
||
|
}
|
||
|
case 2: {
|
||
|
- GSource *source = g_timeout_source_new (1);
|
||
|
- ProcessKeyEventReplyData *data = NULL;
|
||
|
-
|
||
|
- 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 (context,
|
||
|
- keyval,
|
||
|
- keycode - 8,
|
||
|
- state);
|
||
|
- if (source)
|
||
|
- g_source_destroy (source);
|
||
|
- break;
|
||
|
- }
|
||
|
- 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,
|
||
|
- 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);
|
||
|
+ retval = _process_key_event_hybrid_async (context,
|
||
|
+ keyval, keycode, state);
|
||
|
break;
|
||
|
}
|
||
|
default: {
|
||
|
- ProcessKeyEventData *data = g_slice_new0 (ProcessKeyEventData);
|
||
|
-#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
- data->event = gdk_event_ref (event);
|
||
|
-#else
|
||
|
- data->event = gdk_event_copy ((GdkEvent *)event);
|
||
|
-#endif
|
||
|
- data->ibusimcontext = ibusimcontext;
|
||
|
- ibus_input_context_process_key_event_async (context,
|
||
|
- keyval,
|
||
|
- keycode - 8,
|
||
|
- state,
|
||
|
- -1,
|
||
|
- NULL,
|
||
|
- _process_key_event_done,
|
||
|
- data);
|
||
|
-
|
||
|
- retval = TRUE;
|
||
|
+ retval = _process_key_event_async (context,
|
||
|
+ keyval, keycode, state,
|
||
|
+ (GdkEvent *)event,
|
||
|
+ ibusimcontext);
|
||
|
+ break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -877,7 +925,55 @@ ibus_im_context_class_init (IBusIMContextClass *class)
|
||
|
g_assert (_signal_retrieve_surrounding_id != 0);
|
||
|
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
- _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 2);
|
||
|
+ /* IBus GtkIMModule, QtIMModlue, ibus-x11, ibus-wayland are called as
|
||
|
+ * IBus clients.
|
||
|
+ * Each GTK application, each QT application, Xorg server, Wayland
|
||
|
+ * comppsitor are called as IBus event owners here.
|
||
|
+ *
|
||
|
+ * The IBus client processes the key events between the IBus event owner
|
||
|
+ * and the IBus daemon and the procedure step is to:
|
||
|
+ *
|
||
|
+ * receive the key event from the IBus event owner and forward the
|
||
|
+ * event to the IBus daemon with the "ProcessKeyEvent" D-Bus method at
|
||
|
+ * first,
|
||
|
+ *
|
||
|
+ * receive the return value from the IBus daemon with the "ProessKeyEvent"
|
||
|
+ * D-Bus method and forward the value to the IBus event owner secondly and
|
||
|
+ * the return value includes if the key event is processed normally or not.
|
||
|
+ *
|
||
|
+ * The procedure behavior can be changed by the "IBUS_ENABLE_SYNC_MODE"
|
||
|
+ * environment variable with the synchronous procedure or asynchronous
|
||
|
+ * one and value is:
|
||
|
+ *
|
||
|
+ * 1: Synchronous process key event:
|
||
|
+ * Wait for the return of the IBus "ProcessKeyEvent" D-Bus method
|
||
|
+ * synchronously and forward the return value to the IBus event owner
|
||
|
+ * synchronously.
|
||
|
+ * 0: Asynchronous process key event:
|
||
|
+ * Return to the IBus event owner as the key event is processed normally
|
||
|
+ * at first as soon as the IBus client receives the event from the
|
||
|
+ * IBus event owner and also forward the event to the IBus daemon with
|
||
|
+ * the "ProcessKeyEvent" D-Bus method and wait for the return value of
|
||
|
+ * the D-Bus method *asynchronously*.
|
||
|
+ * If the return value indicates the key event is disposed by IBus,
|
||
|
+ * the IBus client does not perform anything. Otherwise the IBus client
|
||
|
+ * forwards the key event with the gdk_event_put() in GTK3,
|
||
|
+ * gtk_im_context_filter_key() in GTK4, IMForwardEvent() in XIM API.
|
||
|
+ * 2: Hybrid asynchronous process key event:
|
||
|
+ * Wait for the return of the IBus "ProcessKeyEvent" D-Bus method
|
||
|
+ * *asynchronously* with a GSource loop and forward the return value
|
||
|
+ * to the IBus event owner synchronously. So IBus clients perform
|
||
|
+ * virtually synchronously to cover problems of IBus synchronous APIs.
|
||
|
+ *
|
||
|
+ * The purpose of the asynchronous process is that each IBus input
|
||
|
+ * method can process the key events without D-Bus timeout and also
|
||
|
+ * the IBus synchronous process has a problem that the IBus
|
||
|
+ * "ProcessKeyEvent" D-Bus method cannot send the commit-text and
|
||
|
+ * forwar-key-event D-Bus signals until the D-Bus method is finished.
|
||
|
+ *
|
||
|
+ * Relative issues: #1713, #2486
|
||
|
+ */
|
||
|
+ _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 1);
|
||
|
#else
|
||
|
_use_key_snooper = !_get_boolean_env ("IBUS_DISABLE_SNOOPER",
|
||
|
!(ENABLE_SNOOPER));
|
||
|
@@ -1004,8 +1100,6 @@ 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_V2;
|
||
|
|
||
|
ibusimcontext->events_queue = g_queue_new ();
|
||
|
|
||
|
@@ -2235,6 +2329,8 @@ _create_input_context_done (IBusBus *bus,
|
||
|
}
|
||
|
else {
|
||
|
ibus_input_context_set_client_commit_preedit (context, TRUE);
|
||
|
+ if (_use_sync_mode == 1)
|
||
|
+ ibus_input_context_set_post_process_key_event (context, TRUE);
|
||
|
ibusimcontext->ibuscontext = context;
|
||
|
|
||
|
g_signal_connect (ibusimcontext->ibuscontext,
|
||
|
@@ -2489,9 +2585,8 @@ _create_fake_input_context_done (IBusBus *bus,
|
||
|
G_CALLBACK (_ibus_fake_context_destroy_cb),
|
||
|
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_V2;
|
||
|
+ guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS
|
||
|
+ | IBUS_CAP_SURROUNDING_TEXT;
|
||
|
ibus_input_context_set_capabilities (_fake_context, caps);
|
||
|
|
||
|
/* focus in/out the fake context */
|
||
|
diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c
|
||
|
index 28ae04ad..def23b25 100644
|
||
|
--- a/src/ibusinputcontext.c
|
||
|
+++ b/src/ibusinputcontext.c
|
||
|
@@ -2,7 +2,7 @@
|
||
|
/* vim:set et sts=4: */
|
||
|
/* ibus - The Input Bus
|
||
|
* Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
|
||
|
- * Copyright (C) 2018-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
||
|
+ * Copyright (C) 2018-2023 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
||
|
* Copyright (C) 2008-2019 Red Hat, Inc.
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
@@ -1190,14 +1190,14 @@ ibus_input_context_set_content_type (IBusInputContext *context,
|
||
|
g_assert (IBUS_IS_INPUT_CONTEXT (context));
|
||
|
|
||
|
cached_content_type =
|
||
|
- g_dbus_proxy_get_cached_property ((GDBusProxy *) context,
|
||
|
+ g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
|
||
|
"ContentType");
|
||
|
content_type = g_variant_new ("(uu)", purpose, hints);
|
||
|
|
||
|
g_variant_ref_sink (content_type);
|
||
|
- if (cached_content_type == NULL ||
|
||
|
+ if (!cached_content_type ||
|
||
|
!g_variant_equal (content_type, cached_content_type)) {
|
||
|
- g_dbus_proxy_call ((GDBusProxy *) context,
|
||
|
+ g_dbus_proxy_call ((GDBusProxy *)context,
|
||
|
"org.freedesktop.DBus.Properties.Set",
|
||
|
g_variant_new ("(ssv)",
|
||
|
IBUS_INTERFACE_INPUT_CONTEXT,
|
||
|
@@ -1209,9 +1209,13 @@ ibus_input_context_set_content_type (IBusInputContext *context,
|
||
|
NULL, /* callback */
|
||
|
NULL /* user_data */
|
||
|
);
|
||
|
+ /* Need to update the cache by manual since there is a timing issue. */
|
||
|
+ g_dbus_proxy_set_cached_property ((GDBusProxy *)context,
|
||
|
+ "ContentType",
|
||
|
+ content_type);
|
||
|
}
|
||
|
|
||
|
- if (cached_content_type != NULL)
|
||
|
+ if (cached_content_type)
|
||
|
g_variant_unref (cached_content_type);
|
||
|
g_variant_unref (content_type);
|
||
|
}
|
||
|
@@ -1324,19 +1328,20 @@ void
|
||
|
ibus_input_context_set_client_commit_preedit (IBusInputContext *context,
|
||
|
gboolean client_commit)
|
||
|
{
|
||
|
- GVariant *cached_content_type;
|
||
|
+ GVariant *cached_var_client_commit;
|
||
|
GVariant *var_client_commit;
|
||
|
|
||
|
g_assert (IBUS_IS_INPUT_CONTEXT (context));
|
||
|
|
||
|
- cached_content_type =
|
||
|
- g_dbus_proxy_get_cached_property ((GDBusProxy *) context,
|
||
|
+ cached_var_client_commit =
|
||
|
+ g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
|
||
|
"ClientCommitPreedit");
|
||
|
var_client_commit = g_variant_new ("(b)", client_commit);
|
||
|
|
||
|
g_variant_ref_sink (var_client_commit);
|
||
|
- if (cached_content_type == NULL) {
|
||
|
- g_dbus_proxy_call ((GDBusProxy *) context,
|
||
|
+ if (!cached_var_client_commit ||
|
||
|
+ !g_variant_equal (var_client_commit, cached_var_client_commit)) {
|
||
|
+ g_dbus_proxy_call ((GDBusProxy *)context,
|
||
|
"org.freedesktop.DBus.Properties.Set",
|
||
|
g_variant_new ("(ssv)",
|
||
|
IBUS_INTERFACE_INPUT_CONTEXT,
|
||
|
@@ -1348,13 +1353,146 @@ ibus_input_context_set_client_commit_preedit (IBusInputContext *context,
|
||
|
NULL, /* callback */
|
||
|
NULL /* user_data */
|
||
|
);
|
||
|
+ /* Need to update the cache by manual since there is a timing issue. */
|
||
|
+ g_dbus_proxy_set_cached_property ((GDBusProxy *)context,
|
||
|
+ "ClientCommitPreedit",
|
||
|
+ var_client_commit);
|
||
|
}
|
||
|
|
||
|
- if (cached_content_type != NULL)
|
||
|
- g_variant_unref (cached_content_type);
|
||
|
+ if (cached_var_client_commit)
|
||
|
+ g_variant_unref (cached_var_client_commit);
|
||
|
g_variant_unref (var_client_commit);
|
||
|
}
|
||
|
|
||
|
+void
|
||
|
+ibus_input_context_set_post_process_key_event (IBusInputContext *context,
|
||
|
+ gboolean enable)
|
||
|
+{
|
||
|
+ GVariant *cached_var_post;
|
||
|
+ GVariant *var_post;
|
||
|
+
|
||
|
+ g_assert (IBUS_IS_INPUT_CONTEXT (context));
|
||
|
+
|
||
|
+ cached_var_post =
|
||
|
+ g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
|
||
|
+ "EffectivePostProcessKeyEvent");
|
||
|
+ var_post = g_variant_new ("(b)", enable);
|
||
|
+ g_variant_ref_sink (var_post);
|
||
|
+ if (!cached_var_post ||
|
||
|
+ !g_variant_equal (var_post, cached_var_post)) {
|
||
|
+ g_dbus_proxy_call ((GDBusProxy *)context,
|
||
|
+ "org.freedesktop.DBus.Properties.Set",
|
||
|
+ g_variant_new ("(ssv)",
|
||
|
+ IBUS_INTERFACE_INPUT_CONTEXT,
|
||
|
+ "EffectivePostProcessKeyEvent",
|
||
|
+ var_post),
|
||
|
+ G_DBUS_CALL_FLAGS_NONE,
|
||
|
+ -1,
|
||
|
+ NULL, /* cancellable */
|
||
|
+ NULL, /* callback */
|
||
|
+ NULL /* user_data */
|
||
|
+ );
|
||
|
+ /* Need to update the cache by manual since there is a timing issue. */
|
||
|
+ g_dbus_proxy_set_cached_property ((GDBusProxy *)context,
|
||
|
+ "EffectivePostProcessKeyEvent",
|
||
|
+ var_post);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (cached_var_post)
|
||
|
+ g_variant_unref (cached_var_post);
|
||
|
+ g_variant_unref (var_post);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+ibus_input_context_post_process_key_event (IBusInputContext *context)
|
||
|
+{
|
||
|
+ GVariant *cached_var_post;
|
||
|
+ gboolean enable = FALSE;
|
||
|
+ GVariant *result;
|
||
|
+ GError *error = NULL;
|
||
|
+ GVariant *variant = NULL;
|
||
|
+ GVariantIter iter;
|
||
|
+ gsize size;
|
||
|
+ char type = 0;
|
||
|
+ GVariant *vtext = NULL;
|
||
|
+
|
||
|
+ g_assert (IBUS_IS_INPUT_CONTEXT (context));
|
||
|
+
|
||
|
+ cached_var_post =
|
||
|
+ g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
|
||
|
+ "EffectivePostProcessKeyEvent");
|
||
|
+ if (cached_var_post)
|
||
|
+ g_variant_get (cached_var_post, "(b)", &enable);
|
||
|
+ if (!enable) {
|
||
|
+ g_warning ("%s: ibus_input_context_set_post_process_key_event() "
|
||
|
+ "needs to be called before.",
|
||
|
+ G_STRFUNC);
|
||
|
+ if (cached_var_post)
|
||
|
+ g_variant_unref (cached_var_post);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ g_variant_unref (cached_var_post);
|
||
|
+ result = g_dbus_proxy_call_sync (
|
||
|
+ (GDBusProxy *)context,
|
||
|
+ "org.freedesktop.DBus.Properties.Get",
|
||
|
+ g_variant_new ("(ss)",
|
||
|
+ IBUS_INTERFACE_INPUT_CONTEXT,
|
||
|
+ "PostProcessKeyEvent"),
|
||
|
+ G_DBUS_CALL_FLAGS_NONE,
|
||
|
+ -1,
|
||
|
+ NULL,
|
||
|
+ &error);
|
||
|
+ if (error) {
|
||
|
+ g_warning ("%s: %s", G_STRFUNC, error->message);
|
||
|
+ g_error_free (error);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ g_variant_get (result, "(v)", &variant);
|
||
|
+ g_assert (variant);
|
||
|
+ g_variant_iter_init (&iter, variant);
|
||
|
+ size = g_variant_iter_n_children (&iter);
|
||
|
+ while (size >0 && g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) {
|
||
|
+ IBusText *text =
|
||
|
+ (IBusText *)ibus_serializable_deserialize_object (vtext);
|
||
|
+ if (!IBUS_IS_TEXT (text)) {
|
||
|
+ g_warning ("%s: %s", G_STRFUNC, "text is not IBusText");
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ switch (type) {
|
||
|
+ case 'c':
|
||
|
+ g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text);
|
||
|
+ break;
|
||
|
+ case 'f': {
|
||
|
+ gchar **array = NULL;
|
||
|
+ guint keyval, keycode, state;
|
||
|
+ array = g_strsplit (text->text, ",", -1);
|
||
|
+ keyval = g_ascii_strtoull (array[0], NULL, 10);
|
||
|
+ keycode = g_ascii_strtoull (array[1], NULL, 10);
|
||
|
+ state = g_ascii_strtoull (array[2], NULL, 10);
|
||
|
+ g_strfreev (array);
|
||
|
+ g_signal_emit (context,
|
||
|
+ context_signals[FORWARD_KEY_EVENT],
|
||
|
+ 0,
|
||
|
+ keyval,
|
||
|
+ keycode,
|
||
|
+ state | IBUS_FORWARD_MASK);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ default:
|
||
|
+ g_warning ("%s: Type '%c' is not supported.", G_STRFUNC, type);
|
||
|
+ }
|
||
|
+ if (g_object_is_floating (text)) {
|
||
|
+ g_object_ref_sink (text);
|
||
|
+ g_object_unref (text);
|
||
|
+ }
|
||
|
+ g_clear_pointer (&vtext, g_variant_unref);
|
||
|
+ }
|
||
|
+
|
||
|
+ g_variant_unref (variant);
|
||
|
+ g_variant_unref (result);
|
||
|
+}
|
||
|
+
|
||
|
#define DEFINE_FUNC(name, Name) \
|
||
|
void \
|
||
|
ibus_input_context_##name (IBusInputContext *context) \
|
||
|
diff --git a/src/ibusinputcontext.h b/src/ibusinputcontext.h
|
||
|
index 09992148..ca604670 100644
|
||
|
--- a/src/ibusinputcontext.h
|
||
|
+++ b/src/ibusinputcontext.h
|
||
|
@@ -2,7 +2,7 @@
|
||
|
/* vim:set et sts=4: */
|
||
|
/* ibus - The Input Bus
|
||
|
* Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
|
||
|
- * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
||
|
+ * Copyright (C) 2018-2023 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
||
|
* Copyright (C) 2008-2018 Red Hat, Inc.
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
@@ -298,7 +298,6 @@ gboolean ibus_input_context_process_key_event
|
||
|
guint32 keycode,
|
||
|
guint32 state);
|
||
|
|
||
|
-
|
||
|
/**
|
||
|
* ibus_input_context_set_cursor_location:
|
||
|
* @context: An IBusInputContext.
|
||
|
@@ -519,9 +518,38 @@ void ibus_input_context_set_content_type
|
||
|
*
|
||
|
* See also ibus_engine_update_preedit_text_with_mode().
|
||
|
*/
|
||
|
-void ibus_input_context_set_client_commit_preedit (
|
||
|
- IBusInputContext *context,
|
||
|
+void ibus_input_context_set_client_commit_preedit
|
||
|
+ (IBusInputContext *context,
|
||
|
gboolean client_commit);
|
||
|
|
||
|
+/**
|
||
|
+ * ibus_input_context_set_post_process_key_event:
|
||
|
+ * @context: An #IBusInputContext.
|
||
|
+ * @enable: Can use ibus_input_context_post_process_key_event() to retrieve
|
||
|
+ * commit-text and forwar-key-event signals during
|
||
|
+ * calling ibus_input_context_process_key_event() if it's %TRUE.
|
||
|
+ *
|
||
|
+ * Since: 1.5.00
|
||
|
+ * Stability: Unstable
|
||
|
+ */
|
||
|
+void ibus_input_context_set_post_process_key_event
|
||
|
+ (IBusInputContext *context,
|
||
|
+ gboolean enable);
|
||
|
+/**
|
||
|
+ * ibus_input_context_post_process_key_event:
|
||
|
+ * @context: An #IBusInputContext.
|
||
|
+ *
|
||
|
+ * Call this API after ibus_input_context_process_key_event() returns
|
||
|
+ * to retrieve commit-text and forwar-key-event signals during
|
||
|
+ * calling ibus_input_context_process_key_event().
|
||
|
+ *
|
||
|
+ * See also ibus_input_context_set_post_process_key_event().
|
||
|
+ *
|
||
|
+ * Since: 1.5.00
|
||
|
+ * Stability: Unstable
|
||
|
+ */
|
||
|
+void ibus_input_context_post_process_key_event
|
||
|
+ (IBusInputContext *context);
|
||
|
+
|
||
|
G_END_DECLS
|
||
|
#endif
|
||
|
--
|
||
|
2.41.0
|
||
|
|
||
|
From 86d9bb9a1cbd4ffbd6bc2a4de85cb76a43bc2ced Mon Sep 17 00:00:00 2001
|
||
|
From: Peng Wu <pwu@redhat.com>
|
||
|
Date: Mon, 24 Jul 2023 14:04:12 +0800
|
||
|
Subject: [PATCH] client/gtk2: Update set_cursor_location function to use Gdk
|
||
|
functions
|
||
|
|
||
|
For ibus-gtk4, use the Gdk functions to get the inner cursor location.
|
||
|
The inner cursor location is translated by XTranslateCoordinates
|
||
|
for X Window.
|
||
|
For ibus-gtk3, use gdk_window_get_root_coords function to translate the
|
||
|
inner cursor location for X Window.
|
||
|
In Wayland, the set_cursor_location_relative function is called.
|
||
|
In X Window, the set_cursor_location function is called.
|
||
|
|
||
|
Fixes: https://github.com/ibus/ibus/commit/d0a47c3
|
||
|
Fixes: https://github.com/ibus/ibus/commit/a823161
|
||
|
|
||
|
BUG=https://github.com/ibus/ibus/pull/2549
|
||
|
BUG=https://gitlab.gnome.org/GNOME/gtk/-/issues/3024#note_987835
|
||
|
---
|
||
|
client/gtk2/ibusimcontext.c | 141 +++++++++++++++---------------------
|
||
|
1 file changed, 58 insertions(+), 83 deletions(-)
|
||
|
|
||
|
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
|
||
|
index 7ccc129d..b5a44da0 100644
|
||
|
--- a/client/gtk2/ibusimcontext.c
|
||
|
+++ b/client/gtk2/ibusimcontext.c
|
||
|
@@ -27,6 +27,7 @@
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <gtk/gtk.h>
|
||
|
+#include <gdk/gdk.h>
|
||
|
#include <gdk/gdkkeysyms.h>
|
||
|
#include <ibus.h>
|
||
|
#include "ibusimcontext.h"
|
||
|
@@ -1612,8 +1613,13 @@ static gboolean
|
||
|
_set_cursor_location_internal (IBusIMContext *ibusimcontext)
|
||
|
{
|
||
|
GdkRectangle area;
|
||
|
+ GdkDisplay *display = NULL;
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
GtkWidget *root;
|
||
|
+ GtkNative *native;
|
||
|
+ graphene_point_t p;
|
||
|
+ int tx = 0, ty = 0;
|
||
|
+ double nx = 0., ny = 0.;
|
||
|
#endif
|
||
|
|
||
|
if(ibusimcontext->client_window == NULL ||
|
||
|
@@ -1623,103 +1629,72 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext)
|
||
|
|
||
|
area = ibusimcontext->cursor_area;
|
||
|
|
||
|
-#ifdef GDK_WINDOWING_WAYLAND
|
||
|
#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
root = GTK_WIDGET (gtk_widget_get_root (ibusimcontext->client_window));
|
||
|
- /* FIXME: GTK_STYLE_CLASS_TITLEBAR is available in GTK3 but not GTK4.
|
||
|
- * gtk_css_boxes_get_content_rect() is available in GTK4 but it's an
|
||
|
- * internal API and calculate the window edge 32 in GTK3.
|
||
|
- */
|
||
|
- area.y += 32;
|
||
|
- area.width = 50; /* FIXME: Why 50 meets the cursor position? */
|
||
|
- area.height = gtk_widget_get_height (root);
|
||
|
- area.height += 32;
|
||
|
- if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
|
||
|
- ibus_input_context_set_cursor_location_relative (
|
||
|
- ibusimcontext->ibuscontext,
|
||
|
- area.x,
|
||
|
- area.y,
|
||
|
- area.width,
|
||
|
- area.height);
|
||
|
- return FALSE;
|
||
|
- }
|
||
|
-#else
|
||
|
- if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) {
|
||
|
- gdouble px, py;
|
||
|
- GdkWindow *parent;
|
||
|
- GdkWindow *window = ibusimcontext->client_window;
|
||
|
-
|
||
|
- while ((parent = gdk_window_get_effective_parent (window)) != NULL) {
|
||
|
- gdk_window_coords_to_parent (window, area.x, area.y, &px, &py);
|
||
|
- area.x = px;
|
||
|
- area.y = py;
|
||
|
- window = parent;
|
||
|
- }
|
||
|
-
|
||
|
- _set_rect_scale_factor_with_window (&area,
|
||
|
- ibusimcontext->client_window);
|
||
|
- ibus_input_context_set_cursor_location_relative (
|
||
|
- ibusimcontext->ibuscontext,
|
||
|
- area.x,
|
||
|
- area.y,
|
||
|
- area.width,
|
||
|
- area.height);
|
||
|
- return FALSE;
|
||
|
+ /* Translates the given point in client_window coordinates to coordinates
|
||
|
+ relative to root coordinate system. */
|
||
|
+ if (!gtk_widget_compute_point (ibusimcontext->client_window,
|
||
|
+ root,
|
||
|
+ &GRAPHENE_POINT_INIT (area.x, area.y),
|
||
|
+ &p)) {
|
||
|
+ graphene_point_init (&p, area.x, area.y);
|
||
|
}
|
||
|
-#endif
|
||
|
-#endif
|
||
|
|
||
|
-#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
-#elif GTK_CHECK_VERSION (2, 91, 0)
|
||
|
- if (area.x == -1 && area.y == -1 && area.width == 0 && area.height == 0) {
|
||
|
- area.x = 0;
|
||
|
- area.y += gdk_window_get_height (ibusimcontext->client_window);
|
||
|
- }
|
||
|
-#else
|
||
|
- if (area.x == -1 && area.y == -1 && area.width == 0 && area.height == 0) {
|
||
|
- gint w, h;
|
||
|
- gdk_drawable_get_size (ibusimcontext->client_window, &w, &h);
|
||
|
- area.y += h;
|
||
|
- area.x = 0;
|
||
|
- }
|
||
|
-#endif
|
||
|
+ native = gtk_widget_get_native (ibusimcontext->client_window);
|
||
|
+ /* Translates from the surface coordinates into the widget coordinates. */
|
||
|
+ gtk_native_get_surface_transform (native, &nx, &ny);
|
||
|
|
||
|
-#if GTK_CHECK_VERSION (3, 98, 4)
|
||
|
-#if defined(GDK_WINDOWING_X11)
|
||
|
- GdkDisplay *display = gtk_widget_get_display (ibusimcontext->client_window);
|
||
|
+ display = gtk_widget_get_display (ibusimcontext->client_window);
|
||
|
if (GDK_IS_X11_DISPLAY (display)) {
|
||
|
- Display *xdisplay = gdk_x11_display_get_xdisplay (display);
|
||
|
- Window root_window = gdk_x11_display_get_xrootwindow (display);
|
||
|
- GtkNative *native = gtk_widget_get_native (
|
||
|
- ibusimcontext->client_window);
|
||
|
- GdkSurface *surface = gtk_native_get_surface (native);
|
||
|
- /* The window is the toplevel window but not the inner text widget.
|
||
|
- * Unfortunatelly GTK4 cannot get the coordinate of the text widget.
|
||
|
- */
|
||
|
- Window window = gdk_x11_surface_get_xid (surface);
|
||
|
+ GdkSurface *surface = gtk_native_get_surface
|
||
|
+ (gtk_widget_get_native (ibusimcontext->client_window));
|
||
|
Window child;
|
||
|
- int x, y;
|
||
|
- XTranslateCoordinates (xdisplay, window, root_window,
|
||
|
- 0, 0, &x, &y, &child);
|
||
|
- XWindowAttributes xwa;
|
||
|
- XGetWindowAttributes (xdisplay, window, &xwa);
|
||
|
- area.x = x - xwa.x + area.x;
|
||
|
- area.y = y - xwa.y + area.y;
|
||
|
- area.width = 50; /* FIXME: Why 50 meets the cursor position? */
|
||
|
- area.height = xwa.height;
|
||
|
+ int scale_factor = gtk_widget_get_scale_factor
|
||
|
+ (ibusimcontext->client_window);
|
||
|
+
|
||
|
+ XTranslateCoordinates (GDK_DISPLAY_XDISPLAY (display),
|
||
|
+ GDK_SURFACE_XID (surface),
|
||
|
+ gdk_x11_display_get_xrootwindow (display),
|
||
|
+ 0, 0, &tx, &ty,
|
||
|
+ &child);
|
||
|
+
|
||
|
+ tx = tx / scale_factor;
|
||
|
+ ty = ty / scale_factor;
|
||
|
}
|
||
|
-#endif
|
||
|
+
|
||
|
+ area.x = p.x + nx + tx;
|
||
|
+ area.y = p.y + ny + ty;
|
||
|
#else
|
||
|
gdk_window_get_root_coords (ibusimcontext->client_window,
|
||
|
area.x, area.y,
|
||
|
&area.x, &area.y);
|
||
|
#endif
|
||
|
+
|
||
|
_set_rect_scale_factor_with_window (&area, ibusimcontext->client_window);
|
||
|
- ibus_input_context_set_cursor_location (ibusimcontext->ibuscontext,
|
||
|
- area.x,
|
||
|
- area.y,
|
||
|
- area.width,
|
||
|
- area.height);
|
||
|
+
|
||
|
+#ifdef GDK_WINDOWING_WAYLAND
|
||
|
+#if !GTK_CHECK_VERSION (3, 98, 4)
|
||
|
+ display = gdk_window_get_display (ibusimcontext->client_window);
|
||
|
+#endif
|
||
|
+
|
||
|
+ if (GDK_IS_WAYLAND_DISPLAY (display)) {
|
||
|
+ ibus_input_context_set_cursor_location_relative (ibusimcontext->ibuscontext,
|
||
|
+ area.x,
|
||
|
+ area.y,
|
||
|
+ area.width,
|
||
|
+ area.height);
|
||
|
+
|
||
|
+ } else {
|
||
|
+#endif
|
||
|
+ ibus_input_context_set_cursor_location (ibusimcontext->ibuscontext,
|
||
|
+ area.x,
|
||
|
+ area.y,
|
||
|
+ area.width,
|
||
|
+ area.height);
|
||
|
+#ifdef GDK_WINDOWING_WAYLAND
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
--
|
||
|
2.41.0
|
||
|
|
||
|
From f176569cf774f87b23270257da68249dcda837c9 Mon Sep 17 00:00:00 2001
|
||
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
||
|
Date: Wed, 18 Oct 2023 16:57:28 +0900
|
||
|
Subject: [PATCH] src: Add DeleteSurroundingText to PostProcessKeyEvent
|
||
|
|
||
|
DeleteSurroundingText also can be delayed sending to IBus clients.
|
||
|
Now surrounding D-Bus methods are added to PostProcessKeyEvent.
|
||
|
|
||
|
Fixes: https://github.com/ibus/ibus/commit/38f09c6
|
||
|
|
||
|
BUG=https://github.com/ibus/ibus/issues/2570
|
||
|
---
|
||
|
bus/inputcontext.c | 33 +++++++++++++++++++++++++++++++--
|
||
|
src/ibusinputcontext.c | 23 +++++++++++++++++++++++
|
||
|
2 files changed, 54 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/bus/inputcontext.c b/bus/inputcontext.c
|
||
|
index aecc64f8..64430fe4 100644
|
||
|
--- a/bus/inputcontext.c
|
||
|
+++ b/bus/inputcontext.c
|
||
|
@@ -2382,7 +2382,7 @@ _engine_forward_key_event_cb (BusEngineProxy *engine,
|
||
|
g_assert (context->queue_during_process_key_event);
|
||
|
|
||
|
if (context->processing_key_event && g_queue_get_length (
|
||
|
- context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
+ context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
SyncForwardingData *data;
|
||
|
IBusText *text = ibus_text_new_from_printf ("%u,%u,%u",
|
||
|
keyval, keycode, state);
|
||
|
@@ -2397,6 +2397,21 @@ _engine_delete_surrounding_text_cb (BusEngineProxy *engine,
|
||
|
|
||
|
g_assert (context->engine == engine);
|
||
|
|
||
|
+ if (context->processing_key_event && g_queue_get_length (
|
||
|
+ context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
+ SyncForwardingData *data;
|
||
|
+ IBusText *text = ibus_text_new_from_printf ("%d,%u",
|
||
|
+ offset_from_cursor, nchars);
|
||
|
+ if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
+ == MAX_SYNC_DATA) {
|
||
|
+ g_warning ("Exceed max number of sync process_key_event data");
|
||
|
+ }
|
||
|
+ data = g_slice_new (SyncForwardingData);
|
||
|
+ data->key = 'd';
|
||
|
+ data->text = g_object_ref (text);
|
||
|
+ g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
+ return;
|
||
|
+ }
|
||
|
bus_input_context_emit_signal (context,
|
||
|
"DeleteSurroundingText",
|
||
|
g_variant_new ("(iu)", offset_from_cursor, nchars),
|
||
|
@@ -2442,6 +2457,20 @@ _engine_require_surrounding_text_cb (BusEngineProxy *engine,
|
||
|
|
||
|
g_assert (context->engine == engine);
|
||
|
|
||
|
+ if (context->processing_key_event && g_queue_get_length (
|
||
|
+ context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
+ SyncForwardingData *data;
|
||
|
+ IBusText *text = ibus_text_new_from_static_string ("");
|
||
|
+ if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
+ == MAX_SYNC_DATA) {
|
||
|
+ g_warning ("Exceed max number of post process_key_event data");
|
||
|
+ }
|
||
|
+ data = g_slice_new (SyncForwardingData);
|
||
|
+ data->key = 'r';
|
||
|
+ data->text = text;
|
||
|
+ g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
+ return;
|
||
|
+ }
|
||
|
bus_input_context_emit_signal (context,
|
||
|
"RequireSurroundingText",
|
||
|
NULL,
|
||
|
@@ -3158,7 +3187,7 @@ bus_input_context_commit_text_use_extension (BusInputContext *context,
|
||
|
if (use_extension && context->emoji_extension) {
|
||
|
bus_panel_proxy_commit_text_received (context->emoji_extension, text);
|
||
|
} else if (context->processing_key_event && g_queue_get_length (
|
||
|
- context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
+ context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
SyncForwardingData *data;
|
||
|
if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
== MAX_SYNC_DATA) {
|
||
|
diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c
|
||
|
index def23b25..c6a030fe 100644
|
||
|
--- a/src/ibusinputcontext.c
|
||
|
+++ b/src/ibusinputcontext.c
|
||
|
@@ -1406,6 +1406,7 @@ ibus_input_context_set_post_process_key_event (IBusInputContext *context,
|
||
|
void
|
||
|
ibus_input_context_post_process_key_event (IBusInputContext *context)
|
||
|
{
|
||
|
+ IBusInputContextPrivate *priv;
|
||
|
GVariant *cached_var_post;
|
||
|
gboolean enable = FALSE;
|
||
|
GVariant *result;
|
||
|
@@ -1418,6 +1419,7 @@ ibus_input_context_post_process_key_event (IBusInputContext *context)
|
||
|
|
||
|
g_assert (IBUS_IS_INPUT_CONTEXT (context));
|
||
|
|
||
|
+ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context));
|
||
|
cached_var_post =
|
||
|
g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
|
||
|
"EffectivePostProcessKeyEvent");
|
||
|
@@ -1479,6 +1481,25 @@ ibus_input_context_post_process_key_event (IBusInputContext *context)
|
||
|
state | IBUS_FORWARD_MASK);
|
||
|
break;
|
||
|
}
|
||
|
+ case 'r': {
|
||
|
+ priv->needs_surrounding_text = TRUE;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case 'd': {
|
||
|
+ gchar **array = NULL;
|
||
|
+ gint offset_from_cursor;
|
||
|
+ guint nchars;
|
||
|
+ array = g_strsplit (text->text, ",", -1);
|
||
|
+ offset_from_cursor = g_ascii_strtoll (array[0], NULL, 10);
|
||
|
+ nchars = g_ascii_strtoull (array[1], NULL, 10);
|
||
|
+ g_strfreev (array);
|
||
|
+ g_signal_emit (context,
|
||
|
+ context_signals[DELETE_SURROUNDING_TEXT],
|
||
|
+ 0,
|
||
|
+ offset_from_cursor,
|
||
|
+ nchars);
|
||
|
+ break;
|
||
|
+ }
|
||
|
default:
|
||
|
g_warning ("%s: Type '%c' is not supported.", G_STRFUNC, type);
|
||
|
}
|
||
|
--
|
||
|
2.41.0
|
||
|
|
||
|
From ef0d29d8bf4e533c428b2cd9d3ee9fa42e9e20e7 Mon Sep 17 00:00:00 2001
|
||
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
||
|
Date: Wed, 25 Oct 2023 16:46:07 +0900
|
||
|
Subject: [PATCH] src: Add preedit D-Bus signals to PostProcessKeyEvent
|
||
|
|
||
|
ibus-hangul calls UpdatePreeditText signal during pressing Enter key
|
||
|
to hide the current preedit text and this also causes the reorder issue
|
||
|
in sync process-key-event and need to move the preedit signals
|
||
|
to PostProcessKeyEvent.
|
||
|
|
||
|
Also refactor PostProcessKeyEvent codes.
|
||
|
|
||
|
Fixes: https://github.com/ibus/ibus/commit/38f09c6
|
||
|
|
||
|
BUG=https://github.com/ibus/ibus/pull/2575
|
||
|
---
|
||
|
bus/inputcontext.c | 176 +++++++++++++++++++++++++++--------------
|
||
|
src/ibusinputcontext.c | 162 +++++++++++++++++++++++++++++--------
|
||
|
2 files changed, 248 insertions(+), 90 deletions(-)
|
||
|
|
||
|
diff --git a/bus/inputcontext.c b/bus/inputcontext.c
|
||
|
index 64430fe4..c914fbd2 100644
|
||
|
--- a/bus/inputcontext.c
|
||
|
+++ b/bus/inputcontext.c
|
||
|
@@ -48,11 +48,25 @@ struct _SetEngineByDescData {
|
||
|
};
|
||
|
typedef struct _SetEngineByDescData SetEngineByDescData;
|
||
|
|
||
|
+typedef struct _DeleteSurroundingData {
|
||
|
+ gint offset;
|
||
|
+ guint nchars;
|
||
|
+} DeleteSurroundingData;
|
||
|
+
|
||
|
typedef struct _SyncForwardingData {
|
||
|
- gchar key;
|
||
|
- IBusText *text;
|
||
|
+ char key;
|
||
|
+ IBusText *text;
|
||
|
} SyncForwardingData;
|
||
|
|
||
|
+typedef struct _SyncForwardingPreData {
|
||
|
+ char key;
|
||
|
+ IBusText *text;
|
||
|
+ union {
|
||
|
+ guint uints[3];
|
||
|
+ DeleteSurroundingData deleting;
|
||
|
+ } u;
|
||
|
+} SyncForwardingPreData;
|
||
|
+
|
||
|
struct _BusInputContext {
|
||
|
IBusService parent;
|
||
|
|
||
|
@@ -970,6 +984,7 @@ _ic_process_key_event (BusInputContext *context,
|
||
|
}
|
||
|
else {
|
||
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", FALSE));
|
||
|
+ context->processing_key_event = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -1654,6 +1670,71 @@ bus_input_context_service_set_property (IBusService *service,
|
||
|
}
|
||
|
|
||
|
|
||
|
+static gboolean
|
||
|
+bus_input_context_make_post_process_key_event (BusInputContext *context,
|
||
|
+ SyncForwardingPreData *pre_data)
|
||
|
+{
|
||
|
+ SyncForwardingData *data;
|
||
|
+ if (context->processing_key_event && g_queue_get_length (
|
||
|
+ context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
+ if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
+ == MAX_SYNC_DATA) {
|
||
|
+ g_warning ("Exceed max number of post process_key_event data");
|
||
|
+ }
|
||
|
+ data = g_slice_new (SyncForwardingData);
|
||
|
+ data->key = pre_data->key;
|
||
|
+ switch (pre_data->key) {
|
||
|
+ case 'c':
|
||
|
+ data->text = g_object_ref (pre_data->text);
|
||
|
+ break;
|
||
|
+ case 'd':
|
||
|
+ data->text = ibus_text_new_from_printf (
|
||
|
+ "%d,%u",
|
||
|
+ pre_data->u.deleting.offset,
|
||
|
+ pre_data->u.deleting.nchars);
|
||
|
+ break;
|
||
|
+ case 'f':
|
||
|
+ data->text = ibus_text_new_from_printf ("%u,%u,%u",
|
||
|
+ pre_data->u.uints[0],
|
||
|
+ pre_data->u.uints[1],
|
||
|
+ pre_data->u.uints[2]);
|
||
|
+ break;
|
||
|
+ case 'h':
|
||
|
+ case 'r':
|
||
|
+ case 's':
|
||
|
+ data->text = ibus_text_new_from_static_string ("");
|
||
|
+ break;
|
||
|
+ case 'u':
|
||
|
+ case 'm':
|
||
|
+ data->text = g_object_ref (pre_data->text);
|
||
|
+ g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
+ data = g_slice_new (SyncForwardingData);
|
||
|
+ data->key = pre_data->key;
|
||
|
+ if (pre_data->key == 'u') {
|
||
|
+ data->text = ibus_text_new_from_printf (
|
||
|
+ "%u,%u",
|
||
|
+ pre_data->u.uints[0],
|
||
|
+ pre_data->u.uints[1]);
|
||
|
+ } else {
|
||
|
+ data->text = ibus_text_new_from_printf (
|
||
|
+ "%u,%u,%u",
|
||
|
+ pre_data->u.uints[0],
|
||
|
+ pre_data->u.uints[1],
|
||
|
+ pre_data->u.uints[2]);
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ g_warning ("Type %c of SyncForwardingData is not supported",
|
||
|
+ pre_data->key);
|
||
|
+ g_slice_free (SyncForwardingData, data);
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+ g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
+ return TRUE;
|
||
|
+ }
|
||
|
+ return FALSE;
|
||
|
+}
|
||
|
+
|
||
|
gboolean
|
||
|
bus_input_context_has_focus (BusInputContext *context)
|
||
|
{
|
||
|
@@ -1893,6 +1974,9 @@ bus_input_context_show_preedit_text (BusInputContext *context,
|
||
|
}
|
||
|
|
||
|
if (PREEDIT_CONDITION) {
|
||
|
+ SyncForwardingPreData pre_data = { 's', };
|
||
|
+ if (bus_input_context_make_post_process_key_event (context, &pre_data))
|
||
|
+ return;
|
||
|
bus_input_context_emit_signal (context,
|
||
|
"ShowPreeditText",
|
||
|
NULL,
|
||
|
@@ -1933,6 +2017,9 @@ bus_input_context_hide_preedit_text (BusInputContext *context,
|
||
|
}
|
||
|
|
||
|
if (PREEDIT_CONDITION) {
|
||
|
+ SyncForwardingPreData pre_data = { 'h', };
|
||
|
+ if (bus_input_context_make_post_process_key_event (context, &pre_data))
|
||
|
+ return;
|
||
|
bus_input_context_emit_signal (context,
|
||
|
"HidePreeditText",
|
||
|
NULL,
|
||
|
@@ -2254,27 +2340,18 @@ _engine_forward_key_event_cb (BusEngineProxy *engine,
|
||
|
guint state,
|
||
|
BusInputContext *context)
|
||
|
{
|
||
|
+ SyncForwardingPreData pre_data = { 'f', };
|
||
|
+
|
||
|
g_assert (BUS_IS_ENGINE_PROXY (engine));
|
||
|
g_assert (BUS_IS_INPUT_CONTEXT (context));
|
||
|
-
|
||
|
g_assert (context->engine == engine);
|
||
|
g_assert (context->queue_during_process_key_event);
|
||
|
|
||
|
- if (context->processing_key_event && g_queue_get_length (
|
||
|
- context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
- SyncForwardingData *data;
|
||
|
- IBusText *text = ibus_text_new_from_printf ("%u,%u,%u",
|
||
|
- keyval, keycode, state);
|
||
|
- if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
- == MAX_SYNC_DATA) {
|
||
|
- g_warning ("Exceed max number of post process_key_event data");
|
||
|
- }
|
||
|
- data = g_slice_new (SyncForwardingData);
|
||
|
- data->key = 'f';
|
||
|
- data->text = text;
|
||
|
- g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
+ pre_data.u.uints[0] = keyval;
|
||
|
+ pre_data.u.uints[1] = keycode;
|
||
|
+ pre_data.u.uints[2] = state;
|
||
|
+ if (bus_input_context_make_post_process_key_event (context, &pre_data))
|
||
|
return;
|
||
|
- }
|
||
|
bus_input_context_emit_signal (context,
|
||
|
"ForwardKeyEvent",
|
||
|
g_variant_new ("(uuu)", keyval, keycode, state),
|
||
|
@@ -2292,26 +2369,16 @@ _engine_delete_surrounding_text_cb (BusEngineProxy *engine,
|
||
|
guint nchars,
|
||
|
BusInputContext *context)
|
||
|
{
|
||
|
+ SyncForwardingPreData pre_data = { 'd', };
|
||
|
+
|
||
|
g_assert (BUS_IS_ENGINE_PROXY (engine));
|
||
|
g_assert (BUS_IS_INPUT_CONTEXT (context));
|
||
|
-
|
||
|
g_assert (context->engine == engine);
|
||
|
|
||
|
- if (context->processing_key_event && g_queue_get_length (
|
||
|
- context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
- SyncForwardingData *data;
|
||
|
- IBusText *text = ibus_text_new_from_printf ("%d,%u",
|
||
|
- offset_from_cursor, nchars);
|
||
|
- if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
- == MAX_SYNC_DATA) {
|
||
|
- g_warning ("Exceed max number of sync process_key_event data");
|
||
|
- }
|
||
|
- data = g_slice_new (SyncForwardingData);
|
||
|
- data->key = 'd';
|
||
|
- data->text = g_object_ref (text);
|
||
|
- g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
+ pre_data.u.deleting.offset = offset_from_cursor;
|
||
|
+ pre_data.u.deleting.nchars = nchars;
|
||
|
+ if (bus_input_context_make_post_process_key_event (context, &pre_data))
|
||
|
return;
|
||
|
- }
|
||
|
bus_input_context_emit_signal (context,
|
||
|
"DeleteSurroundingText",
|
||
|
g_variant_new ("(iu)", offset_from_cursor, nchars),
|
||
|
@@ -2452,25 +2520,14 @@ static void
|
||
|
_engine_require_surrounding_text_cb (BusEngineProxy *engine,
|
||
|
BusInputContext *context)
|
||
|
{
|
||
|
+ SyncForwardingPreData pre_data = { 'r', };
|
||
|
+
|
||
|
g_assert (BUS_IS_ENGINE_PROXY (engine));
|
||
|
g_assert (BUS_IS_INPUT_CONTEXT (context));
|
||
|
-
|
||
|
g_assert (context->engine == engine);
|
||
|
|
||
|
- if (context->processing_key_event && g_queue_get_length (
|
||
|
- context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
- SyncForwardingData *data;
|
||
|
- IBusText *text = ibus_text_new_from_static_string ("");
|
||
|
- if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
- == MAX_SYNC_DATA) {
|
||
|
- g_warning ("Exceed max number of post process_key_event data");
|
||
|
- }
|
||
|
- data = g_slice_new (SyncForwardingData);
|
||
|
- data->key = 'r';
|
||
|
- data->text = text;
|
||
|
- g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
+ if (bus_input_context_make_post_process_key_event (context, &pre_data))
|
||
|
return;
|
||
|
- }
|
||
|
bus_input_context_emit_signal (context,
|
||
|
"RequireSurroundingText",
|
||
|
NULL,
|
||
|
@@ -3178,6 +3235,8 @@ bus_input_context_commit_text_use_extension (BusInputContext *context,
|
||
|
IBusText *text,
|
||
|
gboolean use_extension)
|
||
|
{
|
||
|
+ SyncForwardingPreData pre_data = { 'c', text, };
|
||
|
+
|
||
|
g_assert (BUS_IS_INPUT_CONTEXT (context));
|
||
|
g_assert (context->queue_during_process_key_event);
|
||
|
|
||
|
@@ -3186,17 +3245,9 @@ bus_input_context_commit_text_use_extension (BusInputContext *context,
|
||
|
|
||
|
if (use_extension && context->emoji_extension) {
|
||
|
bus_panel_proxy_commit_text_received (context->emoji_extension, text);
|
||
|
- } else if (context->processing_key_event && g_queue_get_length (
|
||
|
- context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
|
||
|
- SyncForwardingData *data;
|
||
|
- if (g_queue_get_length (context->queue_during_process_key_event)
|
||
|
- == MAX_SYNC_DATA) {
|
||
|
- g_warning ("Exceed max number of sync process_key_event data");
|
||
|
- }
|
||
|
- data = g_slice_new (SyncForwardingData);
|
||
|
- data->key = 'c';
|
||
|
- data->text = g_object_ref (text);
|
||
|
- g_queue_push_tail (context->queue_during_process_key_event, data);
|
||
|
+ } else if (bus_input_context_make_post_process_key_event (context,
|
||
|
+ &pre_data)) {
|
||
|
+ return;
|
||
|
} else {
|
||
|
GVariant *variant = ibus_serializable_serialize (
|
||
|
(IBusSerializable *)text);
|
||
|
@@ -3245,9 +3296,18 @@ bus_input_context_update_preedit_text (BusInputContext *context,
|
||
|
context->preedit_cursor_pos,
|
||
|
context->preedit_visible);
|
||
|
} else if (PREEDIT_CONDITION) {
|
||
|
+ SyncForwardingPreData pre_data = { 'u', context->preedit_text, };
|
||
|
GVariant *variant = ibus_serializable_serialize (
|
||
|
(IBusSerializable *)context->preedit_text);
|
||
|
- if (context->client_commit_preedit) {
|
||
|
+ pre_data.u.uints[0] = context->preedit_cursor_pos;
|
||
|
+ pre_data.u.uints[1] = extension_visible ? 1 : 0;
|
||
|
+ pre_data.u.uints[2] = context->preedit_mode;
|
||
|
+ if (context->client_commit_preedit)
|
||
|
+ pre_data.key = 'm';
|
||
|
+ if (bus_input_context_make_post_process_key_event (context,
|
||
|
+ &pre_data)) {
|
||
|
+ return;
|
||
|
+ } else if (context->client_commit_preedit) {
|
||
|
bus_input_context_emit_signal (
|
||
|
context,
|
||
|
"UpdatePreeditTextWithMode",
|
||
|
diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c
|
||
|
index c6a030fe..1b62f656 100644
|
||
|
--- a/src/ibusinputcontext.c
|
||
|
+++ b/src/ibusinputcontext.c
|
||
|
@@ -1403,10 +1403,103 @@ ibus_input_context_set_post_process_key_event (IBusInputContext *context,
|
||
|
g_variant_unref (var_post);
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+static void
|
||
|
+ibus_input_context_fwd_text_to_commit (IBusInputContext *context,
|
||
|
+ IBusText *text)
|
||
|
+{
|
||
|
+ g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static void
|
||
|
+ibus_input_context_fwd_text_to_forward_key_event (IBusInputContext *context,
|
||
|
+ IBusText *text)
|
||
|
+{
|
||
|
+ gchar **array = NULL;
|
||
|
+ guint keyval, keycode, state;
|
||
|
+ array = g_strsplit (text->text, ",", -1);
|
||
|
+ keyval = g_ascii_strtoull (array[0], NULL, 10);
|
||
|
+ keycode = g_ascii_strtoull (array[1], NULL, 10);
|
||
|
+ state = g_ascii_strtoull (array[2], NULL, 10);
|
||
|
+ g_strfreev (array);
|
||
|
+ g_signal_emit (context,
|
||
|
+ context_signals[FORWARD_KEY_EVENT],
|
||
|
+ 0,
|
||
|
+ keyval,
|
||
|
+ keycode,
|
||
|
+ state | IBUS_FORWARD_MASK);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static void
|
||
|
+ibus_input_context_fwd_text_to_require_surrounding (IBusInputContext *context,
|
||
|
+ IBusText *text)
|
||
|
+{
|
||
|
+ IBusInputContextPrivate *priv;
|
||
|
+ g_assert (IBUS_IS_INPUT_CONTEXT (context));
|
||
|
+ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context));
|
||
|
+ priv->needs_surrounding_text = TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static void
|
||
|
+ibus_input_context_fwd_text_to_delete_surrounding (IBusInputContext *context,
|
||
|
+ IBusText *text)
|
||
|
+{
|
||
|
+ gchar **array = NULL;
|
||
|
+ gint offset_from_cursor;
|
||
|
+ guint nchars;
|
||
|
+ array = g_strsplit (text->text, ",", -1);
|
||
|
+ offset_from_cursor = g_ascii_strtoll (array[0], NULL, 10);
|
||
|
+ nchars = g_ascii_strtoull (array[1], NULL, 10);
|
||
|
+ g_strfreev (array);
|
||
|
+ g_signal_emit (context,
|
||
|
+ context_signals[DELETE_SURROUNDING_TEXT],
|
||
|
+ 0,
|
||
|
+ offset_from_cursor,
|
||
|
+ nchars);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static void
|
||
|
+ibus_input_context_fwd_text_to_update_preedit (IBusInputContext *context,
|
||
|
+ IBusText *text,
|
||
|
+ IBusText *position,
|
||
|
+ char type)
|
||
|
+{
|
||
|
+ gchar **array = NULL;
|
||
|
+ guint32 cursor_pos;
|
||
|
+ gboolean visible;
|
||
|
+ guint mode = 0;
|
||
|
+
|
||
|
+ array = g_strsplit (position->text, ",", -1);
|
||
|
+ cursor_pos = g_ascii_strtoull (array[0], NULL, 10);
|
||
|
+ visible = g_ascii_strtoull (array[1], NULL, 10) ? TRUE : FALSE;
|
||
|
+ if (type == 'u') {
|
||
|
+ g_signal_emit (context,
|
||
|
+ context_signals[UPDATE_PREEDIT_TEXT],
|
||
|
+ 0,
|
||
|
+ text,
|
||
|
+ cursor_pos,
|
||
|
+ visible);
|
||
|
+ } else {
|
||
|
+ mode = g_ascii_strtoull (array[2], NULL, 10);
|
||
|
+ g_signal_emit (context,
|
||
|
+ context_signals[UPDATE_PREEDIT_TEXT_WITH_MODE],
|
||
|
+ 0,
|
||
|
+ text,
|
||
|
+ cursor_pos,
|
||
|
+ visible,
|
||
|
+ mode);
|
||
|
+ }
|
||
|
+ g_strfreev (array);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
void
|
||
|
ibus_input_context_post_process_key_event (IBusInputContext *context)
|
||
|
{
|
||
|
- IBusInputContextPrivate *priv;
|
||
|
GVariant *cached_var_post;
|
||
|
gboolean enable = FALSE;
|
||
|
GVariant *result;
|
||
|
@@ -1419,7 +1513,6 @@ ibus_input_context_post_process_key_event (IBusInputContext *context)
|
||
|
|
||
|
g_assert (IBUS_IS_INPUT_CONTEXT (context));
|
||
|
|
||
|
- priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context));
|
||
|
cached_var_post =
|
||
|
g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
|
||
|
"EffectivePostProcessKeyEvent");
|
||
|
@@ -1454,7 +1547,7 @@ ibus_input_context_post_process_key_event (IBusInputContext *context)
|
||
|
g_assert (variant);
|
||
|
g_variant_iter_init (&iter, variant);
|
||
|
size = g_variant_iter_n_children (&iter);
|
||
|
- while (size >0 && g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) {
|
||
|
+ while (size > 0 && g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) {
|
||
|
IBusText *text =
|
||
|
(IBusText *)ibus_serializable_deserialize_object (vtext);
|
||
|
if (!IBUS_IS_TEXT (text)) {
|
||
|
@@ -1463,41 +1556,48 @@ ibus_input_context_post_process_key_event (IBusInputContext *context)
|
||
|
}
|
||
|
switch (type) {
|
||
|
case 'c':
|
||
|
- g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text);
|
||
|
+ ibus_input_context_fwd_text_to_commit (context, text);
|
||
|
break;
|
||
|
case 'f': {
|
||
|
- gchar **array = NULL;
|
||
|
- guint keyval, keycode, state;
|
||
|
- array = g_strsplit (text->text, ",", -1);
|
||
|
- keyval = g_ascii_strtoull (array[0], NULL, 10);
|
||
|
- keycode = g_ascii_strtoull (array[1], NULL, 10);
|
||
|
- state = g_ascii_strtoull (array[2], NULL, 10);
|
||
|
- g_strfreev (array);
|
||
|
- g_signal_emit (context,
|
||
|
- context_signals[FORWARD_KEY_EVENT],
|
||
|
- 0,
|
||
|
- keyval,
|
||
|
- keycode,
|
||
|
- state | IBUS_FORWARD_MASK);
|
||
|
+ ibus_input_context_fwd_text_to_forward_key_event (context, text);
|
||
|
break;
|
||
|
}
|
||
|
case 'r': {
|
||
|
- priv->needs_surrounding_text = TRUE;
|
||
|
+ ibus_input_context_fwd_text_to_require_surrounding (context, text);
|
||
|
break;
|
||
|
}
|
||
|
case 'd': {
|
||
|
- gchar **array = NULL;
|
||
|
- gint offset_from_cursor;
|
||
|
- guint nchars;
|
||
|
- array = g_strsplit (text->text, ",", -1);
|
||
|
- offset_from_cursor = g_ascii_strtoll (array[0], NULL, 10);
|
||
|
- nchars = g_ascii_strtoull (array[1], NULL, 10);
|
||
|
- g_strfreev (array);
|
||
|
- g_signal_emit (context,
|
||
|
- context_signals[DELETE_SURROUNDING_TEXT],
|
||
|
- 0,
|
||
|
- offset_from_cursor,
|
||
|
- nchars);
|
||
|
+ ibus_input_context_fwd_text_to_delete_surrounding (context, text);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case 'u':
|
||
|
+ case 'm': {
|
||
|
+ IBusText *position;
|
||
|
+ g_clear_pointer (&vtext, g_variant_unref);
|
||
|
+ if (!g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) {
|
||
|
+ g_warning ("%s: %s", G_STRFUNC,
|
||
|
+ "Type 'u' requires next type 'u'");
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (type != 'u' && type != 'm') {
|
||
|
+ g_warning ("%s: %s", G_STRFUNC,
|
||
|
+ "The next of type 'u' should be type 'u'");
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ position =
|
||
|
+ (IBusText *)ibus_serializable_deserialize_object (vtext);
|
||
|
+ if (!IBUS_IS_TEXT (position)) {
|
||
|
+ g_warning ("%s: %s", G_STRFUNC, "text is not IBusText");
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ ibus_input_context_fwd_text_to_update_preedit (context,
|
||
|
+ text,
|
||
|
+ position,
|
||
|
+ type);
|
||
|
+ if (g_object_is_floating (position)) {
|
||
|
+ g_object_ref_sink (position);
|
||
|
+ g_object_unref (position);
|
||
|
+ }
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
--
|
||
|
2.41.0
|
||
|
|