diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
index 80f3acf..bbbb577 100644
--- a/bus/ibusimpl.c
+++ b/bus/ibusimpl.c
@@ -815,6 +815,17 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus,
engine = bus_input_context_get_engine (ibus->focused_context);
if (engine) {
g_object_ref (engine);
+ /* _ic_focus_in() can be called before _ic_focus_out() is
+ * called under the async processes of two ibus clients.
+ * E.g. gedit is a little slower v.s. a simple GtkTextView
+ * application is the fastest when you click a Hangul
+ * preedit text between the applications.
+ * preedit will be committed with focus-out in the ibus client
+ * likes ibus-im.so
+ * so do not commit preedit here in focus-in event.
+ */
+ bus_input_context_clear_preedit_text (ibus->focused_context,
+ FALSE);
bus_input_context_set_engine (ibus->focused_context, NULL);
bus_input_context_set_emoji_extension (ibus->focused_context,
NULL);
diff --git a/bus/inputcontext.c b/bus/inputcontext.c
index 4f98b84..1b8e7ad 100644
--- a/bus/inputcontext.c
+++ b/bus/inputcontext.c
@@ -73,6 +73,7 @@ struct _BusInputContext {
guint preedit_cursor_pos;
gboolean preedit_visible;
guint preedit_mode;
+ gboolean client_commit_preedit;
/* auxiliary text */
IBusText *auxiliary_text;
@@ -212,6 +213,9 @@ static IBusPropList *props_empty = NULL;
static const gchar introspection_xml[] =
""
" "
+ /* properties */
+ " "
+ " \n"
/* methods */
" "
" "
@@ -273,6 +277,12 @@ static const gchar introspection_xml[] =
" "
" "
" "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
" "
" "
" "
@@ -297,9 +307,6 @@ static const gchar introspection_xml[] =
" "
" "
" "
-
- /* properties */
- " "
" "
"";
@@ -1069,6 +1076,12 @@ _ic_reset (BusInputContext *context,
GDBusMethodInvocation *invocation)
{
if (context->engine) {
+ if (context->preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) {
+ if (context->client_commit_preedit)
+ bus_input_context_clear_preedit_text (context, FALSE);
+ else
+ bus_input_context_clear_preedit_text (context, TRUE);
+ }
bus_engine_proxy_reset (context->engine);
}
g_dbus_method_invocation_return_value (invocation, NULL);
@@ -1354,6 +1367,13 @@ _ic_set_content_type (BusInputContext *context,
}
}
+static void
+_ic_set_client_commit_preedit (BusInputContext *context,
+ GVariant *value)
+{
+ g_variant_get (value, "(b)", &context->client_commit_preedit);
+}
+
static gboolean
bus_input_context_service_set_property (IBusService *service,
GDBusConnection *connection,
@@ -1379,9 +1399,14 @@ bus_input_context_service_set_property (IBusService *service,
if (!bus_input_context_service_authorized_method (service, connection))
return FALSE;
+ g_return_val_if_fail (BUS_IS_INPUT_CONTEXT (service), FALSE);
+
if (g_strcmp0 (property_name, "ContentType") == 0) {
- BusInputContext *context = (BusInputContext *) service;
- _ic_set_content_type (context, value);
+ _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;
}
@@ -1453,22 +1478,44 @@ bus_input_context_focus_in (BusInputContext *context)
/**
* bus_input_context_clear_preedit_text:
+ * @context: A #BusInputContext
+ * @with_signal: %FALSE if the preedit is already updated in ibus clients
+ * likes ibus-im.so. Otherwise %TRUE.
*
- * Clear context->preedit_text. If the preedit mode is IBUS_ENGINE_PREEDIT_COMMIT, commit it before clearing.
+ * Clear context->preedit_text. If the preedit mode is
+ * IBUS_ENGINE_PREEDIT_COMMIT, commit it before clearing.
*/
-static void
-bus_input_context_clear_preedit_text (BusInputContext *context)
+void
+bus_input_context_clear_preedit_text (BusInputContext *context,
+ gboolean with_signal)
{
+ IBusText *preedit_text;
+ guint preedit_mode;
+ gboolean preedit_visible;
+
g_assert (BUS_IS_INPUT_CONTEXT (context));
- if (context->preedit_visible &&
- context->preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) {
- bus_input_context_commit_text (context, context->preedit_text);
+ if (!with_signal) {
+ g_object_unref (context->preedit_text);
+ context->preedit_mode = IBUS_ENGINE_PREEDIT_CLEAR;
+ context->preedit_text = (IBusText *) g_object_ref_sink (text_empty);
+ context->preedit_cursor_pos = 0;
+ context->preedit_visible = FALSE;
+ return;
}
- /* always clear preedit text */
+ /* always clear preedit text to reset the cursor position in the
+ * client application before commit the preeit text. */
+ preedit_text = g_object_ref (context->preedit_text);
+ preedit_mode = context->preedit_mode;
+ preedit_visible = context->preedit_visible;
bus_input_context_update_preedit_text (context,
text_empty, 0, FALSE, IBUS_ENGINE_PREEDIT_CLEAR, TRUE);
+
+ if (preedit_visible && preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) {
+ bus_input_context_commit_text (context, preedit_text);
+ }
+ g_object_unref (preedit_text);
}
void
@@ -1479,7 +1526,10 @@ bus_input_context_focus_out (BusInputContext *context)
if (!context->has_focus)
return;
- bus_input_context_clear_preedit_text (context);
+ if (context->client_commit_preedit)
+ bus_input_context_clear_preedit_text (context, FALSE);
+ else
+ bus_input_context_clear_preedit_text (context, TRUE);
bus_input_context_update_auxiliary_text (context, text_empty, FALSE);
bus_input_context_update_lookup_table (context,
lookup_table_empty,
@@ -2338,7 +2388,7 @@ bus_input_context_disable (BusInputContext *context)
{
g_assert (BUS_IS_INPUT_CONTEXT (context));
- bus_input_context_clear_preedit_text (context);
+ bus_input_context_clear_preedit_text (context, TRUE);
bus_input_context_update_auxiliary_text (context, text_empty, FALSE);
bus_input_context_update_lookup_table (context,
lookup_table_empty,
@@ -2385,7 +2435,7 @@ bus_input_context_unset_engine (BusInputContext *context)
{
g_assert (BUS_IS_INPUT_CONTEXT (context));
- bus_input_context_clear_preedit_text (context);
+ bus_input_context_clear_preedit_text (context, TRUE);
bus_input_context_update_auxiliary_text (context, text_empty, FALSE);
bus_input_context_update_lookup_table (context,
lookup_table_empty,
@@ -2807,14 +2857,26 @@ bus_input_context_update_preedit_text (BusInputContext *context,
} else if (PREEDIT_CONDITION) {
GVariant *variant = ibus_serializable_serialize (
(IBusSerializable *)context->preedit_text);
- bus_input_context_emit_signal (context,
- "UpdatePreeditText",
- g_variant_new (
- "(vub)",
- variant,
- context->preedit_cursor_pos,
- extension_visible),
- NULL);
+ if (context->client_commit_preedit) {
+ bus_input_context_emit_signal (
+ context,
+ "UpdatePreeditTextWithMode",
+ g_variant_new ("(vubu)",
+ variant,
+ context->preedit_cursor_pos,
+ extension_visible,
+ context->preedit_mode),
+ NULL);
+ } else {
+ bus_input_context_emit_signal (
+ context,
+ "UpdatePreeditText",
+ g_variant_new ("(vub)",
+ variant,
+ context->preedit_cursor_pos,
+ extension_visible),
+ NULL);
+ }
} else {
g_signal_emit (context,
context_signals[UPDATE_PREEDIT_TEXT],
diff --git a/bus/inputcontext.h b/bus/inputcontext.h
index a46d5c0..7105fff 100644
--- a/bus/inputcontext.h
+++ b/bus/inputcontext.h
@@ -2,8 +2,8 @@
/* vim:set et sts=4: */
/* ibus - The Input Bus
* Copyright (C) 2008-2014 Peng Huang
- * Copyright (C) 2017 Takao Fujiwara
- * Copyright (C) 2008-2014 Red Hat, Inc.
+ * Copyright (C) 2017-2018 Takao Fujiwara
+ * Copyright (C) 2008-2018 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
@@ -377,5 +377,20 @@ void bus_input_context_update_lookup_table
void bus_input_context_panel_extension_received
(BusInputContext *context,
IBusExtensionEvent *event);
+
+/**
+ * bus_input_context_clear_preedit_text:
+ *
+ * Clear context->preedit_text. If the preedit mode is
+ * IBUS_ENGINE_PREEDIT_COMMIT and with_signal is %TRUE, commit it before
+ * clearing.
+ * If with_signal is %FALSE, this just clears the preedit coditions
+ * and the actual preedit is handled in ibus clients.
+ */
+void bus_input_context_clear_preedit_text
+ (BusInputContext *context,
+ gboolean
+ with_signal);
+
G_END_DECLS
#endif
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
index e4de52d..50290c5 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
- * Copyright (C) 2015-2017 Takao Fujiwara
- * Copyright (C) 2008-2017 Red Hat, Inc.
+ * Copyright (C) 2015-2019 Takao Fujiwara
+ * Copyright (C) 2008-2019 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
@@ -61,6 +61,7 @@ struct _IBusIMContext {
PangoAttrList *preedit_attrs;
gint preedit_cursor_pos;
gboolean preedit_visible;
+ guint preedit_mode;
GdkRectangle cursor_area;
gboolean has_focus;
@@ -71,6 +72,10 @@ struct _IBusIMContext {
/* cancellable */
GCancellable *cancellable;
GQueue *events_queue;
+
+#if !GTK_CHECK_VERSION (3, 93, 0)
+ gboolean use_button_press_event;
+#endif
};
struct _IBusIMContextClass {
@@ -132,8 +137,14 @@ static void ibus_im_context_set_surrounding
gint len,
gint cursor_index);
-
/* static methods*/
+static void _ibus_context_update_preedit_text_cb
+ (IBusInputContext *ibuscontext,
+ IBusText *text,
+ gint cursor_pos,
+ gboolean visible,
+ guint mode,
+ IBusIMContext *ibusimcontext);
static void _create_input_context (IBusIMContext *context);
static gboolean _set_cursor_location_internal
(IBusIMContext *context);
@@ -163,7 +174,6 @@ static void _create_fake_input_context (void);
static gboolean _set_content_type (IBusIMContext *context);
-
static GType _ibus_type_im_context = 0;
static GtkIMContextClass *parent_class = NULL;
@@ -291,6 +301,7 @@ ibus_im_context_commit_event (IBusIMContext *ibusimcontext,
IBusText *text = ibus_text_new_from_unichar (ch);
g_signal_emit (ibusimcontext, _signal_commit_id, 0, text->text);
g_object_unref (text);
+ _request_surrounding_text (ibusimcontext);
return TRUE;
}
return FALSE;
@@ -303,7 +314,6 @@ _process_key_event_done (GObject *object,
{
IBusInputContext *context = (IBusInputContext *)object;
GdkEventKey *event = (GdkEventKey *) user_data;
-
GError *error = NULL;
gboolean retval = ibus_input_context_process_key_event_async_finish (
context,
@@ -352,12 +362,10 @@ _process_key_event (IBusInputContext *context,
retval = TRUE;
}
- if (retval) {
+ if (retval)
event->state |= IBUS_HANDLED_MASK;
- }
- else {
+ else
event->state |= IBUS_IGNORED_MASK;
- }
return retval;
}
@@ -379,9 +387,12 @@ _request_surrounding_text (IBusIMContext *context)
g_signal_emit (context, _signal_retrieve_surrounding_id, 0,
&return_value);
if (!return_value) {
- context->caps &= ~IBUS_CAP_SURROUNDING_TEXT;
- ibus_input_context_set_capabilities (context->ibuscontext,
- context->caps);
+ /* #2054 firefox::IMContextWrapper::GetCurrentParagraph() could
+ * fail with the first typing on firefox but it succeeds with
+ * the second typing.
+ */
+ g_warning ("%s has no capability of surrounding-text feature",
+ g_get_prgname ());
}
}
}
@@ -552,6 +563,10 @@ daemon_name_appeared (GDBusConnection *connection,
const gchar *owner,
gpointer data)
{
+ if (!g_strcmp0 (ibus_bus_get_service_name (_bus), IBUS_SERVICE_PORTAL)) {
+ _daemon_is_running = TRUE;
+ return;
+ }
/* If ibus-daemon is running and run ssh -X localhost,
* daemon_name_appeared() is called but ibus_get_address() == NULL
* because the hostname and display number are different between
@@ -744,6 +759,7 @@ ibus_im_context_init (GObject *obj)
ibusimcontext->preedit_attrs = NULL;
ibusimcontext->preedit_cursor_pos = 0;
ibusimcontext->preedit_visible = FALSE;
+ ibusimcontext->preedit_mode = IBUS_ENGINE_PREEDIT_CLEAR;
// Init cursor area
ibusimcontext->cursor_area.x = -1;
@@ -854,6 +870,36 @@ ibus_im_context_finalize (GObject *obj)
G_OBJECT_CLASS(parent_class)->finalize (obj);
}
+static void
+ibus_im_context_clear_preedit_text (IBusIMContext *ibusimcontext)
+{
+ gchar *preedit_string = NULL;
+ g_assert (ibusimcontext->ibuscontext);
+ if (ibusimcontext->preedit_visible &&
+ ibusimcontext->preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) {
+ preedit_string = g_strdup (ibusimcontext->preedit_string);
+ }
+
+ /* Clear the preedit_string but keep the preedit_cursor_pos and
+ * preedit_visible because a time lag could happen, firefox commit
+ * the preedit text before the preedit text is cleared and it cause
+ * a double commits of the Hangul preedit in firefox if the preedit
+ * would be located on the URL bar and click on anywhere of firefox
+ * out of the URL bar.
+ */
+ _ibus_context_update_preedit_text_cb (ibusimcontext->ibuscontext,
+ ibus_text_new_from_string (""),
+ ibusimcontext->preedit_cursor_pos,
+ ibusimcontext->preedit_visible,
+ IBUS_ENGINE_PREEDIT_CLEAR,
+ ibusimcontext);
+ if (preedit_string) {
+ g_signal_emit (ibusimcontext, _signal_commit_id, 0, preedit_string);
+ g_free (preedit_string);
+ _request_surrounding_text (ibusimcontext);
+ }
+}
+
static gboolean
ibus_im_context_filter_keypress (GtkIMContext *context,
GdkEventKey *event)
@@ -1003,6 +1049,7 @@ ibus_im_context_focus_out (GtkIMContext *context)
ibusimcontext->has_focus = FALSE;
if (ibusimcontext->ibuscontext) {
+ ibus_im_context_clear_preedit_text (ibusimcontext);
ibus_input_context_focus_out (ibusimcontext->ibuscontext);
}
@@ -1022,6 +1069,13 @@ ibus_im_context_reset (GtkIMContext *context)
IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
if (ibusimcontext->ibuscontext) {
+ /* Commented out ibus_im_context_clear_preedit_text().
+ * Hangul needs to receive the reset callback with button press
+ * but other IMEs should avoid to receive the reset callback
+ * by themselves.
+ * IBus uses button-press-event instead until GTK is fixed.
+ * https://gitlab.gnome.org/GNOME/gtk/issues/1534
+ */
ibus_input_context_reset (ibusimcontext->ibuscontext);
}
gtk_im_context_reset (ibusimcontext->slave);
@@ -1068,21 +1122,80 @@ ibus_im_context_get_preedit_string (GtkIMContext *context,
}
+#if !GTK_CHECK_VERSION (3, 93, 0)
+/* Use the button-press-event signal until GtkIMContext always emits the reset
+ * signal.
+ * https://gitlab.gnome.org/GNOME/gtk/merge_requests/460
+ */
+static gboolean
+ibus_im_context_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ IBusIMContext *ibusimcontext)
+{
+ if (event->button != 1)
+ return FALSE;
+
+ if (ibusimcontext->ibuscontext) {
+ ibus_im_context_clear_preedit_text (ibusimcontext);
+ ibus_input_context_reset (ibusimcontext->ibuscontext);
+ }
+ return FALSE;
+}
+
+static void
+_connect_button_press_event (IBusIMContext *ibusimcontext,
+ gboolean do_connect)
+{
+ GtkWidget *widget = NULL;
+
+ g_assert (ibusimcontext->client_window);
+ gdk_window_get_user_data (ibusimcontext->client_window,
+ (gpointer *)&widget);
+ /* firefox needs GtkWidget instead of GtkWindow */
+ if (GTK_IS_WIDGET (widget)) {
+ if (do_connect) {
+ g_signal_connect (
+ widget,
+ "button-press-event",
+ G_CALLBACK (ibus_im_context_button_press_event_cb),
+ ibusimcontext);
+ ibusimcontext->use_button_press_event = TRUE;
+ } else {
+ g_signal_handlers_disconnect_by_func (
+ widget,
+ G_CALLBACK (ibus_im_context_button_press_event_cb),
+ ibusimcontext);
+ ibusimcontext->use_button_press_event = FALSE;
+ }
+ }
+}
+#endif
+
static void
ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client)
{
+ IBusIMContext *ibusimcontext;
+
IDEBUG ("%s", __FUNCTION__);
- IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
+ ibusimcontext = IBUS_IM_CONTEXT (context);
if (ibusimcontext->client_window) {
+#if !GTK_CHECK_VERSION (3, 93, 0)
+ if (ibusimcontext->use_button_press_event)
+ _connect_button_press_event (ibusimcontext, FALSE);
+#endif
g_object_unref (ibusimcontext->client_window);
ibusimcontext->client_window = NULL;
}
- if (client != NULL)
+ if (client != NULL) {
ibusimcontext->client_window = g_object_ref (client);
-
+#if !GTK_CHECK_VERSION (3, 93, 0)
+ if (!ibusimcontext->use_button_press_event)
+ _connect_button_press_event (ibusimcontext, TRUE);
+#endif
+ }
if (ibusimcontext->slave)
gtk_im_context_set_client_window (ibusimcontext->slave, client);
}
@@ -1393,6 +1506,7 @@ _key_is_modifier (guint keyval)
return FALSE;
}
}
+
/* Copy from gdk */
static GdkEventKey *
_create_gdk_event (IBusIMContext *ibusimcontext,
@@ -1530,6 +1644,7 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext,
IBusText *text,
gint cursor_pos,
gboolean visible,
+ guint mode,
IBusIMContext *ibusimcontext)
{
IDEBUG ("%s", __FUNCTION__);
@@ -1545,6 +1660,15 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext,
ibusimcontext->preedit_attrs = NULL;
}
+#if !GTK_CHECK_VERSION (3, 93, 0)
+ if (!ibusimcontext->use_button_press_event &&
+ mode == IBUS_ENGINE_PREEDIT_COMMIT) {
+ if (ibusimcontext->client_window) {
+ _connect_button_press_event (ibusimcontext, TRUE);
+ }
+ }
+#endif
+
str = text->text;
ibusimcontext->preedit_string = g_strdup (str);
if (text->attrs) {
@@ -1586,6 +1710,7 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext,
flag = ibusimcontext->preedit_visible != visible;
ibusimcontext->preedit_visible = visible;
+ ibusimcontext->preedit_mode = mode;
if (ibusimcontext->preedit_visible) {
if (flag) {
@@ -1676,7 +1801,7 @@ _create_input_context_done (IBusBus *bus,
g_error_free (error);
}
else {
-
+ ibus_input_context_set_client_commit_preedit (context, TRUE);
ibusimcontext->ibuscontext = context;
g_signal_connect (ibusimcontext->ibuscontext,
@@ -1692,7 +1817,7 @@ _create_input_context_done (IBusBus *bus,
G_CALLBACK (_ibus_context_delete_surrounding_text_cb),
ibusimcontext);
g_signal_connect (ibusimcontext->ibuscontext,
- "update-preedit-text",
+ "update-preedit-text-with-mode",
G_CALLBACK (_ibus_context_update_preedit_text_cb),
ibusimcontext);
g_signal_connect (ibusimcontext->ibuscontext,
diff --git a/portal/org.freedesktop.IBus.Portal.xml b/portal/org.freedesktop.IBus.Portal.xml
index afce4da..376ad42 100644
--- a/portal/org.freedesktop.IBus.Portal.xml
+++ b/portal/org.freedesktop.IBus.Portal.xml
@@ -1,6 +1,6 @@