From 17648f0522910480b6c5dd4f5356ca1f6c160bf5 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Tue, 29 Mar 2022 22:48:19 +0200 Subject: [PATCH] src: Fix refcounting issues Commit 5a455b1ead attempted to fix both GLib warnings around floating references and other presumed refcounting issues. However it missed 2 kinds of bugs: - The places that take an IBusText created from a static string were made to avoid freeing it afterwards, but the staticness refers to the string content, not the object itself. - The places that are documented to emit signals on floating object references used to do the following after signal emission: if (g_object_is_floating (object)) g_object_unref (object) And did possibly trigger GLib warnings were changed to: if (g_object_is_floating (object)) g_object_sink_ref (object); g_object_unref (object); Which fixes the GLib warning for floating references, but do unintendedly steal one reference away for non floating references. This commit is essentially a revert of commit 5a455b1ead, but addressing both things differently: - All label/tooltip/symbol IBusText properties in IBusProperty do now always sink the reference of the stored object. - All places documented as maybe using objects with a floating reference on signals changed to doing: if (g_object_is_floating (object)) { g_object_ref_sink (object); g_object_unref (object); } So the floating reference is owned and unreferenced without warnings, but already owned references are left unchanged. This addresses the possible GLib warnings, fixes the possible double unrefs happening on IBusText used in signals, and fixes the missing unrefs on IBusText objects created from static strings. BUG=https://github.com/ibus/ibus/issues/2393 BUG=https://github.com/ibus/ibus/issues/2387 --- src/ibusinputcontext.c | 35 +++++++++++++++++++++-------------- src/ibusproperty.c | 32 +++++++++++++++++--------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c index 4b27551b..7981de38 100644 --- a/src/ibusinputcontext.c +++ b/src/ibusinputcontext.c @@ -549,9 +549,10 @@ ibus_input_context_g_signal (GDBusProxy *proxy, g_variant_unref (variant); g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text); - if (g_object_is_floating (text)) + if (g_object_is_floating (text)) { g_object_ref_sink (text); - g_object_unref (text); + g_object_unref (text); + } return; } if (g_strcmp0 (signal_name, "UpdatePreeditText") == 0) { @@ -569,9 +570,10 @@ ibus_input_context_g_signal (GDBusProxy *proxy, cursor_pos, visible); - if (g_object_is_floating (text)) + if (g_object_is_floating (text)) { g_object_ref_sink (text); - g_object_unref (text); + g_object_unref (text); + } return; } if (g_strcmp0 (signal_name, "UpdatePreeditTextWithMode") == 0) { @@ -592,9 +594,10 @@ ibus_input_context_g_signal (GDBusProxy *proxy, visible, mode); - if (g_object_is_floating (text)) + if (g_object_is_floating (text)) { g_object_ref_sink (text); - g_object_unref (text); + g_object_unref (text); + } return; } @@ -621,9 +624,10 @@ ibus_input_context_g_signal (GDBusProxy *proxy, 0, text, visible); - if (g_object_is_floating (text)) + if (g_object_is_floating (text)) { g_object_ref_sink (text); - g_object_unref (text); + g_object_unref (text); + } return; } @@ -640,9 +644,10 @@ ibus_input_context_g_signal (GDBusProxy *proxy, 0, table, visible); - if (g_object_is_floating (table)) + if (g_object_is_floating (table)) { g_object_ref_sink (table); - g_object_unref (table); + g_object_unref (table); + } return; } @@ -659,9 +664,10 @@ ibus_input_context_g_signal (GDBusProxy *proxy, 0, prop_list); - if (g_object_is_floating (prop_list)) + if (g_object_is_floating (prop_list)) { g_object_ref_sink (prop_list); - g_object_unref (prop_list); + g_object_unref (prop_list); + } return; } @@ -673,9 +679,10 @@ ibus_input_context_g_signal (GDBusProxy *proxy, g_signal_emit (context, context_signals[UPDATE_PROPERTY], 0, prop); - if (g_object_is_floating (prop)) + if (g_object_is_floating (prop)) { g_object_ref_sink (prop); - g_object_unref (prop); + g_object_unref (prop); + } return; } diff --git a/src/ibusproperty.c b/src/ibusproperty.c index 6d4ed088..cd8a0e2a 100644 --- a/src/ibusproperty.c +++ b/src/ibusproperty.c @@ -336,20 +336,17 @@ ibus_property_destroy (IBusProperty *prop) prop->priv->icon = NULL; if (prop->priv->label) { - if (!ibus_text_get_is_static (prop->priv->label)) - g_object_unref (prop->priv->label); + g_object_unref (prop->priv->label); prop->priv->label = NULL; } if (prop->priv->symbol) { - if (!ibus_text_get_is_static (prop->priv->symbol)) - g_object_unref (prop->priv->symbol); + g_object_unref (prop->priv->symbol); prop->priv->symbol = NULL; } if (prop->priv->tooltip) { - if (!ibus_text_get_is_static (prop->priv->tooltip)) - g_object_unref (prop->priv->tooltip); + g_object_unref (prop->priv->tooltip); prop->priv->tooltip = NULL; } @@ -404,7 +401,7 @@ ibus_property_deserialize (IBusProperty *prop, g_variant_get_child (variant, retval++, "u", &prop->priv->type); GVariant *subvar = g_variant_get_child_value (variant, retval++); - if (prop->priv->label && !ibus_text_get_is_static (prop->priv->label)) { + if (prop->priv->label) { g_object_unref (prop->priv->label); } prop->priv->label = IBUS_TEXT (ibus_serializable_deserialize (subvar)); @@ -414,7 +411,7 @@ ibus_property_deserialize (IBusProperty *prop, ibus_g_variant_get_child_string (variant, retval++, &prop->priv->icon); subvar = g_variant_get_child_value (variant, retval++); - if (prop->priv->tooltip && !ibus_text_get_is_static (prop->priv->tooltip)) { + if (prop->priv->tooltip) { g_object_unref (prop->priv->tooltip); } prop->priv->tooltip = IBUS_TEXT (ibus_serializable_deserialize (subvar)); @@ -435,7 +432,7 @@ ibus_property_deserialize (IBusProperty *prop, /* Keep the serialized order for the compatibility when add new members. */ subvar = g_variant_get_child_value (variant, retval++); - if (prop->priv->symbol && !ibus_text_get_is_static (prop->priv->symbol)) { + if (prop->priv->symbol) { g_object_unref (prop->priv->symbol); } prop->priv->symbol = IBUS_TEXT (ibus_serializable_deserialize (subvar)); @@ -567,7 +564,7 @@ ibus_property_set_label (IBusProperty *prop, g_assert (IBUS_IS_PROPERTY (prop)); g_return_if_fail (label == NULL || IBUS_IS_TEXT (label)); - if (prop->priv->label && !ibus_text_get_is_static (prop->priv->label)) { + if (prop->priv->label) { g_object_unref (prop->priv->label); } @@ -575,8 +572,10 @@ ibus_property_set_label (IBusProperty *prop, prop->priv->label = ibus_text_new_from_static_string (""); } else { - prop->priv->label = g_object_ref_sink (label); + prop->priv->label = label; } + + g_object_ref_sink (prop->priv->label); } void @@ -586,7 +585,7 @@ ibus_property_set_symbol (IBusProperty *prop, g_assert (IBUS_IS_PROPERTY (prop)); g_return_if_fail (symbol == NULL || IBUS_IS_TEXT (symbol)); - if (prop->priv->symbol && !ibus_text_get_is_static (prop->priv->symbol)) { + if (prop->priv->symbol) { g_object_unref (prop->priv->symbol); } @@ -594,8 +593,10 @@ ibus_property_set_symbol (IBusProperty *prop, prop->priv->symbol = ibus_text_new_from_static_string (""); } else { - prop->priv->symbol = g_object_ref_sink (symbol); + prop->priv->symbol = symbol; } + + g_object_ref_sink (prop->priv->symbol); } void @@ -615,7 +616,7 @@ ibus_property_set_tooltip (IBusProperty *prop, g_assert (IBUS_IS_PROPERTY (prop)); g_assert (tooltip == NULL || IBUS_IS_TEXT (tooltip)); - if (prop->priv->tooltip && !ibus_text_get_is_static (prop->priv->tooltip)) { + if (prop->priv->tooltip) { g_object_unref (prop->priv->tooltip); } @@ -624,8 +625,9 @@ ibus_property_set_tooltip (IBusProperty *prop, } else { prop->priv->tooltip = tooltip; - g_object_ref_sink (prop->priv->tooltip); } + + g_object_ref_sink (prop->priv->tooltip); } void -- 2.34.1 From 1b5b9548ad418765717ce1fbdc70b3f3eaae67fc Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Mon, 14 Mar 2022 14:25:10 +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 BUG=chromium-os:11421 BUG=http://codereview.appspot.com/3989060 --- client/gtk2/ibusimcontext.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c index a5e5e792..e314ae98 100644 --- a/client/gtk2/ibusimcontext.c +++ b/client/gtk2/ibusimcontext.c @@ -2,7 +2,7 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2015-2021 Takao Fujiwara + * Copyright (C) 2015-2022 Takao Fujiwara * Copyright (C) 2008-2021 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -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.34.1 From 37900574934bb01cc31860ae3ae2f668e4360838 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Mon, 28 Mar 2022 23:18:58 +0900 Subject: [PATCH] src/tests: Run ibus-daemon from CI even if GNOME desktop gnome-shell no longer launch ibus-daemon with IBus systemd file. This is a workaround to call ibus-daemon after GNOME fails to launch ibus-daemon BUG=https://gitlab.gnome.org/GNOME/gdm/-/issues/777 --- src/tests/ibus-desktop-testing-runner.in | 38 +++++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in index 48528326..6b208345 100755 --- a/src/tests/ibus-desktop-testing-runner.in +++ b/src/tests/ibus-desktop-testing-runner.in @@ -55,6 +55,7 @@ GREEN='\033[0;32m' RED='\033[0;31m' NC='\033[0m' + print_log() { if [ x"$RESULT_LOG" != x ] ; then @@ -69,6 +70,7 @@ print_log() fi } + usage() { $ECHO -e \ @@ -95,6 +97,7 @@ usage() "" } + parse_args() { # This is GNU getopt. "sudo port getopt" in BSD? @@ -129,6 +132,7 @@ parse_args() fi } + init_desktop() { if [ "$RESULT_LOG" != "" ] ; then @@ -207,6 +211,7 @@ _EOF #export XDG_SEAT=seat0 } + run_dbus_daemon() { # Use dbus-launch --exit-with-session later instead of --sh-syntax @@ -216,6 +221,7 @@ run_dbus_daemon() export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$UID/bus" } + init_gnome() { # gsettings set command needs dconf-service with the same $DISPLAY @@ -258,6 +264,7 @@ init_gnome() fi } + run_desktop() { echo "$DESKTOP_COMMAND" | grep gnome-session > /dev/null @@ -278,12 +285,28 @@ run_desktop() $DESKTOP_COMMAND & PID_GNOME_SESSION=$! sleep 30 - if [ $HAS_GNOME -ne 0 ] ; then - ibus-daemon --daemonize --verbose - sleep 3 - fi + + # gnome-shell 42 checks if org.freedesktop.IBus.session.GNOME.service + # systemd file is available with org.freedesktop.systemd1.Manager.GetUnit + # D-Bus method, which is provided by IBus 1.5.26, and if the file + # is available, gnome-shell no longer launch ibus-daemon + # because gnome-shell assumes gnome-session would launch ibus-daemon + # with org.freedesktop.systemd1.Manager.StartUnit D-Bus method. + # But actually gnome-session failed to launch ibus-daemon + # because the IBus systemd file depends on gnome-session.target + # but this CI launches gnome-session directly. + # + # So ibus-dameon is now always called here after gnome-shell fails to + # launch ibus-daemon. + # It may be better this CI launches GDM autologin to run gnome-session + # with gnome-session.target systemd file. + # But `systemctl start gdm` terminates the parent script forcibly + # and the script cannot get the CI result. + ibus-daemon --daemonize --verbose + sleep 3 } + count_case_result() { retval=$1 @@ -298,6 +321,7 @@ count_case_result() echo $pass $fail } + echo_case_result() { retval=$1 @@ -311,6 +335,7 @@ echo_case_result() fi } + run_direct_test_cases() { pass=0 @@ -363,6 +388,7 @@ EOF_ENVS echo $pass $fail } + run_gnome_desktop_testing_runner() { pass=0 @@ -397,6 +423,7 @@ EOF echo $pass $fail } + run_test_suite() { pass=0 @@ -435,6 +462,7 @@ EOF_RUNNER fi } + finit() { echo "# Killing left gnome-session and Xorg" @@ -451,6 +479,7 @@ finit() echo "# Finished $PROGNAME testing" } + main() { parse_args "$@" @@ -470,5 +499,6 @@ main() finit } + # Need to enclose $@ with double quotes not to split the array. main "$@" -- 2.34.1 From b024ea8fcee6fe1a20570a6f80cc4f9f8f420706 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Wed, 20 Apr 2022 19:36:10 +0900 Subject: [PATCH] ui/gtk3: Disable XKB engines in Plasma Wayland Currently ibus-ui-gtk3 runs the setxkbmap command internally to set the XKB keymaps from XKB engines but setxkbmap does not work in Wayland session. The IBus XKB engines are disabled at the moment in Plamsa Wayland and ibus-ui-gtk3 asks users to use systemsettings5. Will use libinput and libxkbcommon later but it would be better to implement IBus in Plamsa Wayland compositor. BUG=rhbz#2076596 --- configure.ac | 16 ++++++++++ ui/gtk3/Makefile.am | 17 ++++++++++- ui/gtk3/panel.vala | 74 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 100 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index a3cdb2da..79b9c11a 100644 --- a/configure.ac +++ b/configure.ac @@ -636,6 +636,21 @@ if test x"$enable_engine" = x"yes"; then enable_engine="yes (enabled, use --disable-engine to disable)" fi +# --disable-libnotify +AC_ARG_ENABLE(libnotify, + AS_HELP_STRING([--disable-libnotify], + [Disable to link libnotify]), + [enable_libnotify=$enableval], + [enable_libnotify=yes] +) +AM_CONDITIONAL([ENABLE_LIBNOTIFY], [test x"$enable_libnotify" = x"yes"]) +if test x"$enable_libnotify" = x"yes"; then + PKG_CHECK_MODULES(LIBNOTIFY, [ + libnotify >= 0.7 + ]) + enable_libnotify="yes (enabled, use --disable-libnotify to disable)" +fi + PKG_CHECK_MODULES(XTEST, [x11 xtst], [enable_xtest=yes], @@ -871,6 +886,7 @@ Build options: No snooper regexes "$NO_SNOOPER_APPS" Panel icon "$IBUS_ICON_KEYBOARD" Enable surrounding-text $enable_surrounding_text + Enable libnotify $enable_libnotify Enable Emoji dict $enable_emoji_dict Unicode Emoji directory $UNICODE_EMOJI_DIR CLDR annotation directory $EMOJI_ANNOTATION_DIR diff --git a/ui/gtk3/Makefile.am b/ui/gtk3/Makefile.am index ab379328..2a9cabde 100644 --- a/ui/gtk3/Makefile.am +++ b/ui/gtk3/Makefile.am @@ -3,7 +3,7 @@ # ibus - The Input Bus # # Copyright (c) 2007-2015 Peng Huang -# Copyright (c) 2015-2020 Takao Fujwiara +# Copyright (c) 2015-2022 Takao Fujwiara # Copyright (c) 2007-2020 Red Hat, Inc. # # This library is free software; you can redistribute it and/or @@ -81,6 +81,21 @@ AM_VALAFLAGS = \ --target-glib="$(VALA_TARGET_GLIB_VERSION)" \ $(NULL) +if ENABLE_LIBNOTIFY +AM_CFLAGS += \ + @LIBNOTIFY_CFLAGS@ \ + $(NULL) + +AM_LDADD += \ + @LIBNOTIFY_LIBS@ \ + $(NULL) + +AM_VALAFLAGS += \ + --pkg=libnotify \ + -D ENABLE_LIBNOTIFY \ + $(NULL) +endif + if ENABLE_APPINDICATOR AM_VALAFLAGS += --define=INDICATOR endif diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala index 07ce6524..bd70d7d2 100644 --- a/ui/gtk3/panel.vala +++ b/ui/gtk3/panel.vala @@ -73,6 +73,7 @@ class Panel : IBus.PanelService { private string m_icon_prop_key = ""; private int m_property_icon_delay_time = 500; private uint m_property_icon_delay_time_id; + private bool m_is_wayland; #if INDICATOR private bool m_is_kde = is_kde(); #else @@ -93,6 +94,18 @@ class Panel : IBus.PanelService { m_bus = bus; +#if USE_GDK_WAYLAND + Gdk.set_allowed_backends("*"); + var display = Gdk.DisplayManager.get().open_display(null); + Type instance_type = display.get_type(); + Type wayland_type = typeof(GdkWayland.Display); + m_is_wayland = instance_type.is_a(wayland_type); + Gdk.set_allowed_backends("x11"); +#else + m_is_wayland = false; + warning("Checking Wayland is disabled"); +#endif + init_settings(); // init ui @@ -553,6 +566,11 @@ class Panel : IBus.PanelService { GLib.List im_engines = get_engines_from_locale(engines); + if (m_is_wayland) { + if (xkb_engines.length() > 0) + xkb_engines = new GLib.List(); + } + string[] names = {}; foreach (unowned IBus.EngineDesc engine in xkb_engines) names += engine.get_name(); @@ -728,6 +746,32 @@ class Panel : IBus.PanelService { inited_engines_order = false; } + private void update_version_1_5_26() { +#if ENABLE_LIBNOTIFY + if (!Notify.is_initted()) { + Notify.init ("ibus"); + } + + var notification = new Notify.Notification( + _("IBus Attention"), + _("Layout changes do not work in Plasma Wayland. " + + "Please use systemsettings5."), + "ibus"); + notification.set_timeout(30 * 1000); + notification.set_category("hotkey"); + + try { + notification.show(); + } catch (GLib.Error e){ + warning (_("Layout changes do not work in Plasma Wayland. " + + "Please use systemsettings5.")); + } +#else + warning (_("Layout changes do not work in Plasma Wayland. " + + "Please use systemsettings5.")); +#endif + } + private void set_version() { string prev_version = m_settings_general.get_string("version"); string current_version = null; @@ -735,6 +779,9 @@ class Panel : IBus.PanelService { if (compare_versions(prev_version, "1.5.8") < 0) update_version_1_5_8(); + if (compare_versions(prev_version, "1.5.26") < 0) + update_version_1_5_26(); + current_version = "%d.%d.%d".printf(IBus.MAJOR_VERSION, IBus.MINOR_VERSION, IBus.MICRO_VERSION); @@ -856,7 +903,7 @@ class Panel : IBus.PanelService { m_icon_prop_key = ""; // set xkb layout - if (!m_use_system_keyboard_layout) + if (!m_use_system_keyboard_layout && !m_is_wayland) m_xkblayout.set_layout(engine); set_language_from_engine(engine); @@ -960,17 +1007,25 @@ class Panel : IBus.PanelService { string[]? order_names) { string[]? engine_names = unowned_engine_names; - if (engine_names == null || engine_names.length == 0) - engine_names = {"xkb:us::eng"}; + if (engine_names == null || engine_names.length == 0) { + if (m_is_wayland) + engine_names = {}; + else + engine_names = {"xkb:us::eng"}; + } string[] names = {}; foreach (var name in order_names) { + if (m_is_wayland && name.has_prefix("xkb:")) + continue; if (name in engine_names) names += name; } foreach (var name in engine_names) { + if (m_is_wayland && name.has_prefix("xkb:")) + continue; if (name in names) continue; names += name; @@ -1011,9 +1066,14 @@ class Panel : IBus.PanelService { } if (m_engines.length == 0) { - m_engines = engines; - switch_engine(0, true); - run_preload_engines(engines, 1); + if (engines.length > 0) { + m_engines = engines; + switch_engine(0, true); + run_preload_engines(engines, 1); + } else { + m_candidate_panel.set_language(new Pango.AttrLanguage( + Pango.Language.from_string(null))); + } } else { var current_engine = m_engines[0]; m_engines = engines; @@ -1478,6 +1538,8 @@ class Panel : IBus.PanelService { /* Do not change the order of m_engines during running switcher. */ if (m_switcher.is_running()) return; + if (m_engines.length == 0) + return; if (m_icon_type == IconType.INDICATOR) { // Wait for the callback of the session bus. -- 2.34.1 From bca7bf0f97230806a26f53c798050408108cfb3d Mon Sep 17 00:00:00 2001 From: Mike FABIAN Date: Wed, 25 May 2022 23:07:24 +0900 Subject: [PATCH] data/dconf: Update xkb-latin-layouts in gschema Add more keyboard layouts which cannot produce ASCII to data/dconf/org.freedesktop.ibus.gschema.xml Remove "mal" and "mkd", there are no such layouts. BUG=https://github.com/ibus/ibus/issues/2404 --- data/dconf/org.freedesktop.ibus.gschema.xml | 47 ++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/data/dconf/org.freedesktop.ibus.gschema.xml b/data/dconf/org.freedesktop.ibus.gschema.xml index 516f7520..8b181d76 100644 --- a/data/dconf/org.freedesktop.ibus.gschema.xml +++ b/data/dconf/org.freedesktop.ibus.gschema.xml @@ -28,7 +28,52 @@ The saved version number will be used to check the difference between the version of the previous installed ibus and one of the current ibus. - [ 'ara', 'bg', 'cz', 'dev', 'gr', 'gur', 'in', 'jp(kana)', 'mal', 'mkd', 'ru', 'ua' ] + + [ 'af', 'af(fa-olpc)', 'af(ps-olpc)', 'af(ps)', 'af(uz)', + 'af(uz-olpc)', 'am', 'am(eastern)', 'am(eastern-alt)', + 'am(phonetic)', 'am(phonetic-alt)', 'am(western)', 'ara', + 'ara(azerty)', 'ara(azerty_digits)', 'ara(buckwalter)', + 'ara(digits)', 'ara(qwerty)', 'ara(qwerty_digits)', + 'az(cyrillic)', 'bd', 'bd(probhat)', 'bg', 'bg(bas_phonetic)', + 'bg(phonetic)', 'brai', 'brai(left_hand)', 'brai(right_hand)', + 'bt', 'by', 'by(legacy)', 'ca(ike)', 'ca(multi-2gr)', + 'cn(tib)', 'cn(tib_asciinum)', 'cn(ug)', 'cz', 'cz(ucw)', + 'de(ru)', 'dev', 'et', 'fr(geo)', 'ge', 'ge(os)', 'gr', + 'gr(extended)', 'gr(nodeadkeys)', 'gr(polytonic)', + 'gr(simple)', 'gur', 'il', 'il(biblical)', 'il(lyx)', + 'il(phonetic)', 'in', 'in(ben)', 'in(ben_baishakhi)', + 'in(ben_bornona)', 'in(ben_gitanjali)', 'in(ben_inscript)', + 'in(ben_probhat)', 'in(bolnagri)', 'in(deva)', 'in(guj)', + 'in(guru)', 'in(hin-kagapa)', 'in(hin-wx)', 'in(jhelum)', + 'in(kan)', 'in(kan-kagapa)', 'in(mal)', 'in(mal_enhanced)', + 'in(mal_lalitha)', 'in(mar-kagapa)', 'in(ori)', + 'in(san-kagapa)', 'in(tam)', 'in(tam_tamilnet)', + 'in(tam_tamilnet_TAB)', 'in(tam_tamilnet_TSCII)', + 'in(tam_tamilnet_with_tam_nums)', 'in(tel)', 'in(tel-kagapa)', + 'in(urd-phonetic)', 'in(urd-phonetic3)', 'in(urd-winkeys)', + 'iq', 'ir', 'ir(pes_keypad)', 'jp(kana)', 'jp(mac)', 'kg', + 'kg(phonetic)', 'kh', 'kz', 'kz(kazrus)', 'kz(ruskaz)', 'la', + 'la(stea)', 'lk', 'lk(tam_TAB)', 'lk(tam_unicode)', 'ma', + 'ma(tifinagh)', 'ma(tifinagh-alt)', + 'ma(tifinagh-alt-phonetic)', 'ma(tifinagh-extended)', + 'ma(tifinagh-extended-phonetic)', 'ma(tifinagh-phonetic)', + 'me(cyrillic)', 'me(cyrillicalternatequotes)', + 'me(cyrillicyz)', 'mk', 'mk(nodeadkeys)', 'mm', 'mn', 'mv', + 'np', 'ph(capewell-dvorak-bay)', 'ph(capewell-qwerf2k6-bay)', + 'ph(colemak-bay)', 'ph(dvorak-bay)', 'ph(qwerty-bay)', 'pk', + 'pk(ara)', 'pk(snd)', 'pk(urd-crulp)', 'pk(urd-nla)', + 'pl(ru_phonetic_dvorak)', 'rs', 'rs(alternatequotes)', + 'rs(rue)', 'rs(yz)', 'ru', 'ru(bak)', 'ru(chm)', 'ru(cv)', + 'ru(dos)', 'ru(kom)', 'ru(legacy)', 'ru(mac)', + 'ru(os_legacy)', 'ru(os_winkeys)', 'ru(phonetic)', + 'ru(phonetic_winkeys)', 'ru(sah)', 'ru(srp)', 'ru(tt)', + 'ru(typewriter)', 'ru(typewriter-legacy)', 'ru(udm)', + 'ru(xal)', 'se(rus)', 'se(rus_nodeadkeys)', 'se(swl)', 'sy', + 'sy(syc)', 'sy(syc_phonetic)', 'th', 'th(pat)', 'th(tis)', + 'tj', 'tj(legacy)', 'tz', 'ua', 'ua(homophonic)', + 'ua(legacy)', 'ua(phonetic)', 'ua(rstu)', 'ua(rstu_ru)', + 'ua(typewriter)', 'ua(winkeys)', 'us(chr)', 'us(rus)', 'uz' ] + Latin layouts which have no ASCII US layout is appended to the Latin layouts. variant can be omitted. -- 2.35.3 From 16df64edadc21f50906e5442b73425b9256fbf65 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Wed, 25 May 2022 23:07:33 +0900 Subject: [PATCH] src/tests: Add xkb-latin-layouts case BUG=https://github.com/ibus/ibus/issues/2404 --- src/tests/Makefile.am | 26 ++++++-- src/tests/runtest | 1 + src/tests/xkb-latin-layouts | 130 ++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 8 deletions(-) create mode 100755 src/tests/xkb-latin-layouts diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index f932f18f..ca5285bd 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -41,8 +41,9 @@ prog_ldadd =\ $(top_builddir)/src/libibus-@IBUS_API_VERSION@.la \ $(NULL) -noinst_PROGRAMS = $(TESTS) -TESTS = \ +noinst_PROGRAMS = $(TESTS_C) +noinst_SCRIPTS = $(TESTS_SCRIPT) +TESTS_C = \ ibus-bus \ ibus-config \ ibus-configservice \ @@ -56,16 +57,25 @@ TESTS = \ ibus-util \ $(NULL) +TESTS_SCRIPT = \ + xkb-latin-layouts \ + $(NULL) + +TESTS = \ + $(TESTS_C) \ + $(TESTS_SCRIPT) \ + $(NULL) + CLEANFILES = if ENABLE_ENGINE -TESTS += ibus-engine-switch +TESTS_C += ibus-engine-switch endif if ENABLE_GTK3 -TESTS += ibus-compose +TESTS_C += ibus-compose if ENABLE_XTEST -TESTS += ibus-keypress +TESTS_C += ibus-keypress endif endif @@ -99,9 +109,10 @@ CLEANFILES += \ org.freedesktop.IBus.Desktop.Testing.desktop \ $(NULL) -test_execs_PROGRAMS = $(TESTS) +test_execs_PROGRAMS = $(TESTS_C) +test_execs_SCRIPTS = $(TESTS_SCRIPT) if ENABLE_GTK3 -test_execs_SCRIPTS = ibus-compose-locales +test_execs_SCRIPTS += ibus-compose-locales CLEANFILES += \ ibus-compose-locales \ $(NULL) @@ -138,6 +149,7 @@ ibus-desktop-testing-runner: ibus-desktop-testing-runner.in EXTRA_DIST = \ $(test_metas_in) \ + $(TESTS_SCRIPT) \ runtest \ ibus-compose.emoji \ ibus-compose.env \ diff --git a/src/tests/runtest b/src/tests/runtest index a6e4194b..a229140a 100755 --- a/src/tests/runtest +++ b/src/tests/runtest @@ -35,6 +35,7 @@ ibus-engine-switch ibus-compose ibus-keypress test-stress +xkb-latin-layouts " IBUS_SCHEMA_FILE='org.freedesktop.ibus.gschema.xml' GTK_QUERY_MODULE=gtk-query-immodules-3.0-32 diff --git a/src/tests/xkb-latin-layouts b/src/tests/xkb-latin-layouts new file mode 100755 index 00000000..f8dced6b --- /dev/null +++ b/src/tests/xkb-latin-layouts @@ -0,0 +1,130 @@ +#!/bin/bash + +PROGNAME=`basename $0` +VERSION=0.1 +# POSIX sh has no 'echo -e' +: ${ECHO:='/usr/bin/echo'} +TMPDIR= +INSTALLED_SCHEMAS_DIR= + + +usage() +{ + $ECHO -e \ +"This test runs setxkbmap command for gsettings xkb-latin-layouts value\n" \ +"$PROGNAME [OPTIONS…]\n" \ +"\n" \ +"OPTIONS:\n" \ +"-h, --help This help\n" \ +"-v, --version Show version\n" \ +"-D, --schemasdir=DIR Load the latest schema file in DIR\n" \ +"" +} + + +parse_args() +{ + # This is GNU getopt. "sudo port getopt" in BSD? + ARGS=`getopt -o hD:Tv --long \ + help,schemasdir:,tap,version\ + -- "$@"`; + eval set -- "$ARGS" + while [ 1 ] ; do + case "$1" in + -h | --help ) usage; exit 0;; + -D | --schemasdir ) INSTALLED_SCHEMAS_DIR="$2"; shift 2;; + -T | --tap ) shift;; # ignore the option + -v | --version ) $ECHO -e "$VERSION"; exit 0;; + -- ) shift; break;; + * ) shift;; + esac + done +} + + +init() +{ + set -e + + # gnome-continuous doesn't have a machine-id set, which + # breaks dbus-launch. There's dbus-run-session which is + # better, but not everyone has it yet. + export DBUS_FATAL_WARNINGS=0 + export TMPDIR=$(mktemp -d --tmpdir="$PWD") + export XDG_CONFIG_HOME="$TMPDIR/config" + export XDG_CACHE_HOME="$TMPDIR/cache" + export GSETTINGS_SCHEMA_DIR="$TMPDIR/schemas" + mkdir -p $XDG_CONFIG_HOME $XDG_CACHE_HOME $GSETTINGS_SCHEMA_DIR + + eval `dbus-launch --sh-syntax` + + trap 'rm -rf $TMPDIR; kill $DBUS_SESSION_BUS_PID; setxkbmap -layout us' ERR + + # in case that schema is not installed on the system + glib-compile-schemas --targetdir "$GSETTINGS_SCHEMA_DIR" "$INSTALLED_SCHEMAS_DIR" +} + + +finit() +{ + # dbus-launch and gsettings run /usr/lib*/gvfsd-fuse $TMPDIR/cache/gvfs -f + # via systemd since gvfs 1.45.90 in Fedora 33 + # and rm $TMPDIR could be failed until umount would be called. + if [ -d $TMPDIR/cache/gvfs ] ; then + umount $TMPDIR/cache/gvfs + fi + rm -rf $TMPDIR + + kill $DBUS_SESSION_BUS_PID + exit 0 +} + + +test_xkb_keymaps() +{ + # Loop over top level schemas since "gsettings list-recursively" only + # looks for direct children. + xkb_latin_layouts=`gsettings get org.freedesktop.ibus.general xkb-latin-layouts` + while read keymap ; do + eval keymap="$keymap" + HAS_VARIANT=$($ECHO "$keymap" | grep '(' 2> /dev/null) ||: + if [ "x$HAS_VARIANT" != "x" ] ; then + layout=$($ECHO "$keymap" | sed -e 's/\([^(]*\)([^)]*)/\1/') + variant=$($ECHO "$keymap" | sed -e 's/[^(]*(\([^)]*\))/\1/') + $ECHO setxkbmap -layout $layout -variant $variant + setxkbmap -layout $layout -variant $variant + else + layout="$keymap" + $ECHO setxkbmap -layout $layout + setxkbmap -layout $layout + fi + if [ $? -ne 0 ] ; then + $ECHO "Error in layout $layout variant $variant" + setxkbmap -layout us + exit 1 + fi + done << EOF_READ_XKB + `$ECHO $xkb_latin_layouts | sed -e 's/^\[//' -e 's/\]$//' | tr "," "\n"` +EOF_READ_XKB + + setxkbmap -layout us +} + + +main() +{ + parse_args "$@" + + if [ x"$INSTALLED_SCHEMAS_DIR" != x ] ; then + init + fi + + test_xkb_keymaps + + if [ x"$INSTALLED_SCHEMAS_DIR" != x ] ; then + finit + fi +} + + +main "$@" -- 2.35.3 From 233a3f4d4d3dc6782e74db5bf4e7c28fae729bc9 Mon Sep 17 00:00:00 2001 From: Hollow Man Date: Wed, 26 Jan 2022 09:35:11 +0800 Subject: [PATCH 1/3] Add functionality to change IBus panel themes with available GTK themes To allow IBus to have their own control of themes. https://gitlab.gnome.org/GNOME/gnome-tweaks/-/blob/b9badc47b92dd73f8cedbd2efc66cbaf3ea25773/gtweak/tweaks/tweak_group_appearance.py#L69 BUG=https://github.com/ibus/ibus/pull/2327 Signed-off-by: Hollow Man --- data/dconf/org.freedesktop.ibus.gschema.xml | 20 +++ setup/main.py | 137 ++++++++++++++++++++ setup/setup.ui | 97 +++++++++++++- ui/gtk3/bindingcommon.vala | 46 +++++++ ui/gtk3/panel.vala | 18 +++ ui/gtk3/panelbinding.vala | 18 +++ 6 files changed, 335 insertions(+), 1 deletion(-) diff --git a/data/dconf/org.freedesktop.ibus.gschema.xml b/data/dconf/org.freedesktop.ibus.gschema.xml index 8b181d76..051f21a5 100644 --- a/data/dconf/org.freedesktop.ibus.gschema.xml +++ b/data/dconf/org.freedesktop.ibus.gschema.xml @@ -210,6 +210,26 @@ Custom font Custom font name for language panel + + false + Use custom theme + Use custom theme name for language panel + + + 'Adwaita' + Custom theme + Custom theme name for language panel + + + false + Use custom icon + Use custom icon name for language panel + + + 'Adwaita' + Custom icon + Custom icon name for language panel + true Choose glyphs with input method's language on candidate window diff --git a/setup/main.py b/setup/main.py index 1b9056a6..71896693 100644 --- a/setup/main.py +++ b/setup/main.py @@ -29,6 +29,7 @@ import os import signal import sys import time +import glob from gi import require_version as gi_require_version gi_require_version('GLib', '2.0') @@ -196,6 +197,79 @@ class Setup(object): 'sensitive', Gio.SettingsBindFlags.GET) + # custom theme + self.__model_custom_theme = self.__builder.get_object( + "model_custom_theme") + self.__combobox_custom_theme = self.__builder.get_object( + "combobox_custom_theme") + self.__checkbutton_custom_theme = self.__builder.get_object( + "checkbutton_custom_theme") + + def update_combobox_custom_theme(settings, key): + theme_name_list = self.__init_available_gtk_themes() + self.__model_custom_theme.clear() + for name in theme_name_list: + self.__model_custom_theme.append([name]) + current_theme = self.__settings_panel.get_string(key) + try: + current_theme_number = theme_name_list.index(current_theme) + except ValueError: + self.__settings_panel.reset(key) + current_theme = self.__settings_panel.get_string(key) + current_theme_number = theme_name_list.index(current_theme) + self.__combobox_custom_theme.set_active(current_theme_number) + + update_combobox_custom_theme(None, 'custom-theme') + self.__settings_panel.bind('use-custom-theme', + self.__checkbutton_custom_theme, + 'active', + Gio.SettingsBindFlags.DEFAULT) + self.__settings_panel.connect('changed::custom-theme', + update_combobox_custom_theme) + self.__settings_panel.bind('use-custom-theme', + self.__combobox_custom_theme, + 'sensitive', + Gio.SettingsBindFlags.DEFAULT) + self.__combobox_custom_theme.connect("changed", + self.__on_combobox_custom_theme_changed) + + + # custom icon + self.__model_custom_icon = self.__builder.get_object( + "model_custom_icon") + self.__combobox_custom_icon = self.__builder.get_object( + "combobox_custom_icon") + self.__checkbutton_custom_icon = self.__builder.get_object( + "checkbutton_custom_icon") + + def update_combobox_custom_icon(settings, key): + icon_name_list = self.__init_available_gtk_icons() + self.__model_custom_icon.clear() + for name in icon_name_list: + self.__model_custom_icon.append([name]) + current_icon = self.__settings_panel.get_string(key) + try: + current_icon_number = icon_name_list.index(current_icon) + except ValueError: + self.__settings_panel.reset(key) + current_icon = self.__settings_panel.get_string(key) + current_icon_number = icon_name_list.index(current_icon) + self.__combobox_custom_icon.set_active(current_icon_number) + + update_combobox_custom_icon(None, 'custom-icon') + self.__settings_panel.bind('use-custom-icon', + self.__checkbutton_custom_icon, + 'active', + Gio.SettingsBindFlags.DEFAULT) + self.__settings_panel.connect('changed::custom-icon', + update_combobox_custom_icon) + self.__settings_panel.bind('use-custom-icon', + self.__combobox_custom_icon, + 'sensitive', + Gio.SettingsBindFlags.DEFAULT) + self.__combobox_custom_icon.connect("changed", + self.__on_combobox_custom_icon_changed) + # show icon on system tray self.__checkbutton_show_icon_on_systray = self.__builder.get_object( "checkbutton_show_icon_on_systray") @@ -588,6 +662,69 @@ class Setup(object): _("Use shortcut with shift to switch to the previous input method") entry.set_tooltip_text(tooltip) + def __init_available_gtk_themes(self): + path_list = [] + path_list.append(os.path.join(GLib.get_home_dir(), ".themes")) + path_list.append(os.path.join(GLib.get_user_data_dir(), "themes")) + path_list.extend(list(map(lambda x: os.path.join( + x, "themes"), GLib.get_system_data_dirs()))) + theme_name_list = [] + gtk_theme_path = [] + for path in path_list: + gtk_theme_path.extend(glob.glob(path + "/*/gtk-*/gtk.css")) + gtk_theme_path.extend(glob.glob(path + "/*/gtk-*/gtk-dark.css")) + for path in gtk_theme_path: + filename = os.path.basename(path) + appendix = "" + if filename == "gtk-dark.css": + appendix = ":dark" + theme_name_list.append(os.path.basename( + os.path.dirname(os.path.dirname(path))) + appendix) + + theme_name_list.extend([ + 'Adwaita', 'Adwaita:dark', + 'HighContrast', 'HighContrastInverse' + ]) + theme_name_list = list(set(theme_name_list)) + theme_name_list.sort() + + return theme_name_list + + def __on_combobox_custom_theme_changed(self, combobox): + tree_iter = self.__combobox_custom_theme.get_active_iter() + if tree_iter is not None: + model = self.__combobox_custom_theme.get_model() + theme_name = model[tree_iter][0] + self.__settings_panel.set_string('custom-theme', theme_name) + + def __init_available_gtk_icons(self): + path_list = [] + path_list.append(os.path.join(GLib.get_home_dir(), ".icons")) + path_list.append(os.path.join(GLib.get_user_data_dir(), "icons")) + path_list.extend(list(map(lambda x: os.path.join( + x, "icons"), GLib.get_system_data_dirs()))) + icon_name_list = [] + gtk_icon_path = [] + for path in path_list: + gtk_icon_path.extend(glob.glob(path + "/*/index.theme")) + for path in gtk_icon_path: + dir = os.path.dirname(path) + if not os.path.exists(os.path.join(dir, "cursors")): + icon_name_list.append(os.path.basename(dir)) + + icon_name_list.extend(["Adwaita"]) + icon_name_list = list(set(icon_name_list)) + icon_name_list.sort() + + return icon_name_list + + def __on_combobox_custom_icon_changed(self, combobox): + tree_iter = self.__combobox_custom_icon.get_active_iter() + if tree_iter is not None: + model = self.__combobox_custom_icon.get_model() + icon_name = model[tree_iter][0] + self.__settings_panel.set_string('custom-icon', icon_name) + def __item_started_column_toggled_cb(self, cell, path_str, model): # get toggled iter diff --git a/setup/setup.ui b/setup/setup.ui index a15b9083..5a9804f9 100644 --- a/setup/setup.ui +++ b/setup/setup.ui @@ -55,6 +55,18 @@ + + + + + + + + + + + + 3.0 1.0 @@ -1318,13 +1330,96 @@ 0 + + + True + False + 12 + 6 + + + Use custom theme: + False + True + True + False + False + True + start + True + True + + + 0 + 0 + + + + + True + False + model_custom_theme + True + + + + 0 + + + + + 1 + 0 + + + + + Use custom icon: + False + True + True + False + False + True + start + True + + + 0 + 1 + + + + + True + False + model_custom_icon + + + + 0 + + + + + 1 + 1 + + + + + False + False + 1 + + True False - <b>Fonts</b> + <b>Font and Theme</b> True diff --git a/ui/gtk3/bindingcommon.vala b/ui/gtk3/bindingcommon.vala index 150d4c39..e825167b 100644 --- a/ui/gtk3/bindingcommon.vala +++ b/ui/gtk3/bindingcommon.vala @@ -212,4 +212,50 @@ class BindingCommon { css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); } + + public static void + set_custom_theme(GLib.Settings? settings_panel) { + if (settings_panel == null) + return; + + bool use_custom_theme = settings_panel.get_boolean("use-custom-theme"); + string custom_theme = settings_panel.get_string("custom-theme"); + + Gtk.Settings gtk_settings = Gtk.Settings.get_default(); + + if (use_custom_theme == false) + custom_theme = ""; + + if (custom_theme == null || custom_theme == "") { + gtk_settings.reset_property("gtk-theme-name"); + gtk_settings.reset_property("gtk-application-prefer-dark-theme"); + } else { + string[] custom_theme_splitted = custom_theme.split(":"); + gtk_settings.gtk_theme_name = custom_theme_splitted[0]; + if (custom_theme_splitted.length == 2 && + custom_theme_splitted[1] == "dark") + gtk_settings.gtk_application_prefer_dark_theme = true; + else + gtk_settings.gtk_application_prefer_dark_theme = false; + } + } + + public static void + set_custom_icon(GLib.Settings? settings_panel) { + if (settings_panel == null) + return; + + bool use_custom_icon = settings_panel.get_boolean("use-custom-icon"); + string custom_icon = settings_panel.get_string("custom-icon"); + + Gtk.Settings gtk_settings = Gtk.Settings.get_default(); + + if (use_custom_icon == false) + custom_icon = ""; + + if (custom_icon == null || custom_icon == "") + gtk_settings.reset_property("gtk-icon-theme-name"); + else + gtk_settings.gtk_icon_theme_name = custom_icon; + } } diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala index 61bfa1b6..101c2b3d 100644 --- a/ui/gtk3/panel.vala +++ b/ui/gtk3/panel.vala @@ -211,6 +211,22 @@ class Panel : IBus.PanelService { ref m_css_provider); }); + m_settings_panel.changed["custom-theme"].connect((key) => { + BindingCommon.set_custom_theme(m_settings_panel); + }); + + m_settings_panel.changed["use-custom-theme"].connect((key) => { + BindingCommon.set_custom_theme(m_settings_panel); + }); + + m_settings_panel.changed["custom-icon"].connect((key) => { + BindingCommon.set_custom_icon(m_settings_panel); + }); + + m_settings_panel.changed["use-custom-icon"].connect((key) => { + BindingCommon.set_custom_icon(m_settings_panel); + }); + m_settings_panel.changed["use-glyph-from-engine-lang"].connect((key) => { m_use_engine_lang = m_settings_panel.get_boolean( @@ -816,6 +832,8 @@ class Panel : IBus.PanelService { BindingCommon.set_custom_font(m_settings_panel, null, ref m_css_provider); + BindingCommon.set_custom_theme(m_settings_panel); + BindingCommon.set_custom_icon(m_settings_panel); set_show_icon_on_systray(); set_lookup_table_orientation(); set_show_property_panel(); diff --git a/ui/gtk3/panelbinding.vala b/ui/gtk3/panelbinding.vala index e63d93f2..3c516afd 100644 --- a/ui/gtk3/panelbinding.vala +++ b/ui/gtk3/panelbinding.vala @@ -270,6 +270,22 @@ class PanelBinding : IBus.PanelService { ref m_css_provider); }); + m_settings_panel.changed["custom-theme"].connect((key) => { + BindingCommon.set_custom_theme(m_settings_panel); + }); + + m_settings_panel.changed["use-custom-theme"].connect((key) => { + BindingCommon.set_custom_theme(m_settings_panel); + }); + + m_settings_panel.changed["custom-icon"].connect((key) => { + BindingCommon.set_custom_icon(m_settings_panel); + }); + + m_settings_panel.changed["use-custom-icon"].connect((key) => { + BindingCommon.set_custom_icon(m_settings_panel); + }); + m_settings_emoji.changed["unicode-hotkey"].connect((key) => { set_emoji_hotkey(); }); @@ -422,6 +438,8 @@ class PanelBinding : IBus.PanelService { BindingCommon.set_custom_font(m_settings_panel, m_settings_emoji, ref m_css_provider); + BindingCommon.set_custom_theme(m_settings_panel); + BindingCommon.set_custom_icon(m_settings_panel); set_emoji_favorites(); if (m_load_emoji_at_startup && !m_loaded_emoji) set_emoji_lang(); -- 2.35.3 From addab9fdc7f98c172b6fcb1e24faa133368bdaf3 Mon Sep 17 00:00:00 2001 From: Hollow Man Date: Wed, 26 Jan 2022 10:03:04 +0800 Subject: [PATCH 2/3] Revert support for choosing GTK themes dark variant So that the theme list won't get too messy BUG=https://github.com/ibus/ibus/pull/2327 Signed-off-by: Hollow Man --- setup/main.py | 10 ++-------- ui/gtk3/bindingcommon.vala | 14 +++----------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/setup/main.py b/setup/main.py index 71896693..d0e05666 100644 --- a/setup/main.py +++ b/setup/main.py @@ -672,18 +672,12 @@ class Setup(object): gtk_theme_path = [] for path in path_list: gtk_theme_path.extend(glob.glob(path + "/*/gtk-*/gtk.css")) - gtk_theme_path.extend(glob.glob(path + "/*/gtk-*/gtk-dark.css")) for path in gtk_theme_path: - filename = os.path.basename(path) - appendix = "" - if filename == "gtk-dark.css": - appendix = ":dark" theme_name_list.append(os.path.basename( - os.path.dirname(os.path.dirname(path))) + appendix) + os.path.dirname(os.path.dirname(path)))) theme_name_list.extend([ - 'Adwaita', 'Adwaita:dark', - 'HighContrast', 'HighContrastInverse' + 'Adwaita', 'HighContrast', 'HighContrastInverse' ]) theme_name_list = list(set(theme_name_list)) theme_name_list.sort() diff --git a/ui/gtk3/bindingcommon.vala b/ui/gtk3/bindingcommon.vala index e825167b..4ecb7159 100644 --- a/ui/gtk3/bindingcommon.vala +++ b/ui/gtk3/bindingcommon.vala @@ -226,18 +226,10 @@ class BindingCommon { if (use_custom_theme == false) custom_theme = ""; - if (custom_theme == null || custom_theme == "") { + if (custom_theme == null || custom_theme == "") gtk_settings.reset_property("gtk-theme-name"); - gtk_settings.reset_property("gtk-application-prefer-dark-theme"); - } else { - string[] custom_theme_splitted = custom_theme.split(":"); - gtk_settings.gtk_theme_name = custom_theme_splitted[0]; - if (custom_theme_splitted.length == 2 && - custom_theme_splitted[1] == "dark") - gtk_settings.gtk_application_prefer_dark_theme = true; - else - gtk_settings.gtk_application_prefer_dark_theme = false; - } + else + gtk_settings.gtk_theme_name = custom_theme; } public static void -- 2.35.3 From ff99828cb60915318ed0f40998a1a23d5dea42c7 Mon Sep 17 00:00:00 2001 From: Hollow Man Date: Wed, 26 Jan 2022 11:19:40 +0800 Subject: [PATCH 3/3] Add tooltip text for use custom icon and theme BUG=https://github.com/ibus/ibus/pull/2327 Signed-off-by: Hollow Man --- setup/setup.ui | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup/setup.ui b/setup/setup.ui index 5a9804f9..6ded2061 100644 --- a/setup/setup.ui +++ b/setup/setup.ui @@ -1339,6 +1339,7 @@ Use custom theme: + Choose a theme of the candidate window False True True @@ -1375,6 +1376,7 @@ Use custom icon: + Choose a theme of the arrow buttons on the candidate window False True True -- 2.35.3 From 9ad063746ec3d919217ae18acce2d4768bcfca05 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Mon, 20 Jun 2022 21:01:31 +0900 Subject: [PATCH] ui/gtk3: Hide XKB engine but enable it in Plasma Wayland IBus just cannot defer key events to the secondary input methods to switch XKB keymaps in Plasma Wayland because IBus has to handle the compose keys before defer the key events. Also update the POT file. BUG=rhbz#2088656 --- data/dconf/org.freedesktop.ibus.gschema.xml | 4 +- ui/gtk3/panel.vala | 50 ++- 3 files changed, 248 insertions(+), 180 deletions(-) diff --git a/data/dconf/org.freedesktop.ibus.gschema.xml b/data/dconf/org.freedesktop.ibus.gschema.xml index 051f21a5..0ece2b4f 100644 --- a/data/dconf/org.freedesktop.ibus.gschema.xml +++ b/data/dconf/org.freedesktop.ibus.gschema.xml @@ -223,12 +223,12 @@ false Use custom icon - Use custom icon name for language panel + Use custom icon name for arrow buttons on candidate window 'Adwaita' Custom icon - Custom icon name for language panel + Custom icon name for arrow buttons on candidate window true diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala index 101c2b3d..452b14c8 100644 --- a/ui/gtk3/panel.vala +++ b/ui/gtk3/panel.vala @@ -41,6 +41,7 @@ class Panel : IBus.PanelService { private Gtk.Menu m_ime_menu; private Gtk.Menu m_sys_menu; private IBus.EngineDesc[] m_engines = {}; + private IBus.EngineDesc m_en_engine; private GLib.HashTable m_engine_contexts = new GLib.HashTable(GLib.str_hash, GLib.str_equal); @@ -928,13 +929,20 @@ class Panel : IBus.PanelService { } private void switch_engine(int i, bool force = false) { - GLib.assert(i >= 0 && i < m_engines.length); + if (m_is_wayland) + GLib.assert(i >= 0 && i <= m_engines.length); + else + GLib.assert(i >= 0 && i < m_engines.length); // Do not need switch if (i == 0 && !force) return; - IBus.EngineDesc engine = m_engines[i]; + IBus.EngineDesc engine; + if (m_is_wayland && m_engines.length == 0) + engine = m_en_engine; + else + engine = m_engines[i]; set_engine(engine); } @@ -1024,17 +1032,15 @@ class Panel : IBus.PanelService { string[]? order_names) { string[]? engine_names = unowned_engine_names; - if (engine_names == null || engine_names.length == 0) { - if (m_is_wayland) - engine_names = {}; - else - engine_names = {"xkb:us::eng"}; - } + if (engine_names == null || engine_names.length == 0) + engine_names = {"xkb:us::eng"}; string[] names = {}; foreach (var name in order_names) { if (m_is_wayland && name.has_prefix("xkb:")) + name = "xkb:us::eng"; + if (name in names) continue; if (name in engine_names) names += name; @@ -1042,7 +1048,7 @@ class Panel : IBus.PanelService { foreach (var name in engine_names) { if (m_is_wayland && name.has_prefix("xkb:")) - continue; + name = "xkb:us::eng"; if (name in names) continue; names += name; @@ -1083,14 +1089,20 @@ class Panel : IBus.PanelService { } if (m_engines.length == 0) { - if (engines.length > 0) { - m_engines = engines; - switch_engine(0, true); - run_preload_engines(engines, 1); - } else { - m_candidate_panel.set_language(new Pango.AttrLanguage( - Pango.Language.from_string(null))); + m_engines = engines; + // Do not show engines in panel icon and suggest systemsettings5 + // in Plasma Wayland in case all engines are XKB. + if (m_is_wayland && m_engines.length == 1 && + m_engines[0].get_name() == "xkb:us::eng") { + m_engines = {}; + if (m_en_engine == null) { + m_en_engine = + m_bus.get_engines_by_names({"xkb:us::eng"})[0]; + } } + switch_engine(0, true); + if (m_engines.length > 0) + run_preload_engines(m_engines, 1); } else { var current_engine = m_engines[0]; m_engines = engines; @@ -1307,6 +1319,10 @@ class Panel : IBus.PanelService { var longname = engine.get_longname(); var textdomain = engine.get_textdomain(); var transname = GLib.dgettext(textdomain, longname); + if (m_is_wayland && engine.get_name().has_prefix("xkb:")) { + language = _("Other"); + transname = _("No input method"); + } var item = new Gtk.MenuItem.with_label( "%s - %s".printf (IBus.get_language_name(language), transname)); // Make a copy of engine to workaround a bug in vala. @@ -1584,7 +1600,7 @@ class Panel : IBus.PanelService { if (engine != null) { var name = engine.get_name(); - if (name.length >= 4 && name[0:4] == "xkb:") + if (!m_is_wayland && name.length >= 4 && name[0:4] == "xkb:") language = m_switcher.get_xkb_language(engine); } -- 2.35.3 From b94f0c1cea5d0e423fef3bcc13b23f212f04c930 Mon Sep 17 00:00:00 2001 From: fujiwarat 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. --- src/ibusaccelgroup.c | 14 +++++++------- src/ibustypes.h | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) 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 - * “a” or “F1” or “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 “” and “”. 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 “minus” instead of - * “-”. + * 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 “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.35.3 From 4e48e7237d73d20f0426265dbb6b692b14891932 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Thu, 7 Jul 2022 08:21:24 +0900 Subject: [PATCH] tools: Enable ibus restart in GNOME desktop If ibus-daemon is called via systemd, IBus restart API cannot restart ibus-daemon but just terminates it. Now ibus restart command checks the systemd avaiability and restart ibus-daemon via systemd. ibus start command is also added to launch ibus-daemon with systemd. BUG=https://github.com/ibus/ibus/issues/2407 --- tools/Makefile.am | 3 +- tools/ibus.1.in | 30 +++++- tools/main.vala | 261 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 330 insertions(+), 44 deletions(-) diff --git a/tools/Makefile.am b/tools/Makefile.am index 5c18d3d6..e380a9aa 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -3,7 +3,7 @@ # ibus - The Input Bus # # Copyright (c) 2007-2013 Peng Huang -# Copyright (c) 2015-2017 Takao Fujiwara +# Copyright (c) 2015-2022 Takao Fujiwara # Copyright (c) 2007-2017 Red Hat, Inc. # # This library is free software; you can redistribute it and/or @@ -57,6 +57,7 @@ AM_LDADD = \ AM_VALAFLAGS = \ --vapidir=$(top_builddir)/bindings/vala \ --vapidir=$(top_srcdir)/bindings/vala \ + --pkg=gio-2.0 \ --pkg=ibus-1.0 \ --pkg=posix \ --pkg=config \ diff --git a/tools/ibus.1.in b/tools/ibus.1.in index 525d972e..fe1b7157 100644 --- a/tools/ibus.1.in +++ b/tools/ibus.1.in @@ -3,7 +3,7 @@ .\" Copyright (C) Takao Fujiwara , 2013-2017. .\" Copyright (c) Peng Huang , 2013. .\" -.TH "IBUS" 1 "May 2017" "@VERSION@" "User Commands" +.TH "IBUS" 1 "Jul 2022" "@VERSION@" "User Commands" .SH NAME .B ibus \- command line utility for ibus @@ -45,13 +45,33 @@ Exit ibus-daemon. \fBlist-engine\fR Show ibus engines list. .TP -\fBrestart\fR -Restart ibus-daemon. +\fBrestart\fR [\fB\-\-type=TYPE|\-\-verbose|\-\-help\fR] +Restart ibus-daemon. This command tries to restart ibus-daemon via systemd +firstly and directly secondary by default. If +.B \-\-type=systemd +is given, It tries to restart via systemd only. If +.B \-\-type=direct +is given, It tries to restart with an IBus API only. GNOME desktop runs +ibus-daemon via systemd and other desktops run ibus-daemon directly. +.TP +\fBstart\fR [\fB\-\-type=TYPE|\-\-verbose|\-\-help\fR] +Start ibus-daemon. This command tries to start ibus-daemon via systemd +firstly and directly secondary by default. If +.B \-\-type=systemd +is given, It tries to start as a background process via systemd only. If +.B \-\-type=direct +is given, It tries to start directly only as a foreground process and other +option arguments of ibus command are sent to ibus-daemon. E.g. +ibus start +.B \-\-type=direct +.B \-\-xim +& +GNOME desktop runs ibus-daemon via systemd and other desktops run ibus-daemon directly. .TP \fBversion\fR Show the ibus version. .TP -\fBread\-cache\fR [\fB\-\-system|\-\-file=FILE\fR] +\fBread\-cache\fR [\fB\-\-system|\-\-file=FILE|\-\-help\fR] Show the content of the user registry cache if .B \-\-system is not given. @@ -64,7 +84,7 @@ if .B \-\-file=FILE is given. .TP -\fBwrite\-cache\fR [\fB\-\-system|\-\-file=FILE\fR] +\fBwrite\-cache\fR [\fB\-\-system|\-\-file=FILE|\-\-help\fR] Save the user registry cache if .B \-\-system is not given. diff --git a/tools/main.vala b/tools/main.vala index 26e7fd88..407eaf74 100644 --- a/tools/main.vala +++ b/tools/main.vala @@ -3,7 +3,7 @@ * ibus - The Input Bus * * Copyright(c) 2013 Peng Huang - * Copyright(c) 2015-2020 Takao Fujiwara + * Copyright(c) 2015-2022 Takao Fujiwara * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,17 +27,23 @@ private const string IBUS_SCHEMAS_GENERAL_HOTKEY = private const string IBUS_SCHEMAS_PANEL = "org.freedesktop.ibus.panel"; private const string IBUS_SCHEMAS_PANEL_EMOJI = "org.freedesktop.ibus.panel.emoji"; +private const string SYSTEMD_SESSION_GNOME_FILE = + "org.freedesktop.IBus.session.GNOME.service"; bool name_only = false; /* system() exists as a public API. */ bool is_system = false; string cache_file = null; string engine_id = null; +bool verbose = false; +string daemon_type = null; +string systemd_service_file = null; class EngineList { public IBus.EngineDesc[] data = {}; } + IBus.Bus? get_bus() { var bus = new IBus.Bus(); if (!bus.is_connected ()) @@ -45,6 +51,131 @@ IBus.Bus? get_bus() { return bus; } + +GLib.DBusConnection? get_session_bus(bool verbose) { + try { + return GLib.Bus.get_sync (GLib.BusType.SESSION, null); + } catch (GLib.IOError e) { + if (verbose) + stderr.printf("%s\n", e.message); + } + return null; +} + +string? +get_ibus_systemd_object_path(GLib.DBusConnection connection, + bool verbose) { + string object_path = null; + assert(systemd_service_file != null); + try { + var variant = connection.call_sync ( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnit", + new GLib.Variant("(s)", systemd_service_file), + new GLib.VariantType("(o)"), + GLib.DBusCallFlags.NONE, + -1, + null); + variant.get("(o)", ref object_path); + if (verbose) { + stderr.printf("Succeed to get an object path \"%s\" for IBus " + + "systemd service file \"%s\".\n", + object_path, systemd_service_file); + } + return object_path; + } catch (GLib.Error e) { + if (verbose) { + stderr.printf("IBus systemd service file \"%s\" is not installed " + + "in your system: %s\n", + systemd_service_file, e.message); + } + } + return null; +} + + +bool +is_running_daemon_via_systemd(GLib.DBusConnection connection, + string object_path, + bool verbose) { + string? state = null; + try { + while (true) { + var variant = connection.call_sync ( + "org.freedesktop.systemd1", + object_path, + "org.freedesktop.DBus.Properties", + "Get", + new GLib.Variant("(ss)", + "org.freedesktop.systemd1.Unit", + "ActiveState"), + new GLib.VariantType("(v)"), + GLib.DBusCallFlags.NONE, + -1, + null); + GLib.Variant child = null; + variant.get("(v)", ref child); + state = child.dup_string(); + if (verbose) { + stderr.printf("systemd state is \"%s\" for an object " + + "path \"%s\".\n", state, object_path); + } + if (state != "activating") + break; + Posix.sleep(1); + } + } catch (GLib.Error e) { + if (verbose) + stderr.printf("%s\n", e.message); + return false; + } + if (state == "active") + return true; + return false; +} + + +bool +start_daemon_via_systemd(GLib.DBusConnection connection, + bool restart, + bool verbose) { + string object_path = null; + string method = "StartUnit"; + assert(systemd_service_file != null); + if (restart) + method = "RestartUnit"; + try { + var variant = connection.call_sync ( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method, + new GLib.Variant("(ss)", systemd_service_file, "fail"), + new GLib.VariantType("(o)"), + GLib.DBusCallFlags.NONE, + -1, + null); + variant.get("(o)", ref object_path); + if (verbose) { + stderr.printf("Succeed to restart IBus daemon via IBus systemd " + + "service file \"%s\": \"%s\"\n", + systemd_service_file, object_path); + } + return true; + } catch (GLib.Error e) { + if (verbose) { + stderr.printf("Failed to %s IBus daemon via IBus systemd " + + "service file \"%s\": %s\n", + restart ? "restart" : "start", + systemd_service_file, e.message); + } + } + return false; +} + + int list_engine(string[] argv) { const OptionEntry[] options = { { "name-only", 0, 0, OptionArg.NONE, out name_only, @@ -99,6 +230,7 @@ int list_engine(string[] argv) { return Posix.EXIT_SUCCESS; } + private int exec_setxkbmap(IBus.EngineDesc engine) { string layout = engine.get_layout(); string variant = engine.get_layout_variant(); @@ -149,6 +281,7 @@ private int exec_setxkbmap(IBus.EngineDesc engine) { return Posix.EXIT_SUCCESS; } + int get_set_engine(string[] argv) { var bus = get_bus(); string engine = null; @@ -182,20 +315,121 @@ int get_set_engine(string[] argv) { return Posix.EXIT_SUCCESS; } + int message_watch(string[] argv) { return Posix.EXIT_SUCCESS; } -int restart_daemon(string[] argv) { - var bus = get_bus(); - if (bus == null) { - stderr.printf(_("Can't connect to IBus.\n")); + +int start_daemon_real(string[] argv, + bool restart) { + const OptionEntry[] options = { + { "type", 0, 0, OptionArg.STRING, out daemon_type, + N_("Start or restart daemon with \"direct\" or \"systemd\" TYPE."), + "TYPE" }, + { "service-file", 0, 0, OptionArg.STRING, out systemd_service_file, + N_("Start or restart daemon with SYSTEMD_SERVICE file."), + "SYSTEMD_SERVICE" }, + { "verbose", 0, 0, OptionArg.NONE, out verbose, + N_("Show debug messages."), null }, + { null } + }; + + var option = new OptionContext(); + option.add_main_entries(options, Config.GETTEXT_PACKAGE); + option.set_ignore_unknown_options(true); + + try { + option.parse(ref argv); + } catch (OptionError e) { + stderr.printf("%s\n", e.message); + return Posix.EXIT_FAILURE; + } + if (daemon_type != null && daemon_type != "direct" && + daemon_type != "systemd") { + stderr.printf("type argument must be \"direct\" or \"systemd\"\n"); + return Posix.EXIT_FAILURE; + } + if (systemd_service_file == null) + systemd_service_file = SYSTEMD_SESSION_GNOME_FILE; + + do { + if (daemon_type == "direct") + break; + GLib.DBusConnection? connection = get_session_bus(verbose); + if (connection == null) + break; + string? object_path = null; + if (restart) { + object_path = get_ibus_systemd_object_path(connection, verbose); + if (object_path == null) + break; + if (!is_running_daemon_via_systemd(connection, + object_path, + verbose)) { + break; + } + } + if (!start_daemon_via_systemd(connection, restart, verbose)) + break; + // Do not check the systemd state in case of restart because + // the systemd file validation is already done and also stopping + // daemon and starting daemon take time and the state could be + // "inactive" with the time lag. + if (restart) + return Posix.EXIT_SUCCESS; + object_path = get_ibus_systemd_object_path(connection, verbose); + if (object_path == null) + break; + if (!is_running_daemon_via_systemd(connection, object_path, verbose)) + break; + return Posix.EXIT_SUCCESS; + } while (false); + + if (daemon_type == "systemd") return Posix.EXIT_FAILURE; + if (restart) { + var bus = get_bus(); + if (bus == null) { + stderr.printf(_("Can't connect to IBus.\n")); + return Posix.EXIT_FAILURE; + } + bus.exit(true); + if (verbose) { + stderr.printf("Succeed to restart ibus-daemon with an IBus API " + + "directly.\n"); + } + } else { + string startarg = "ibus-daemon"; + argv[0] = startarg; + var paths = GLib.Environment.get_variable("PATH").split(":"); + foreach (unowned string path in paths) { + var full_path = "%s/%s".printf(path, startarg); + if (GLib.FileUtils.test(full_path, GLib.FileTest.IS_EXECUTABLE)) { + startarg = full_path; + break; + } + } + // When ibus-daemon is launched by GLib.Process.spawn_async(), + // the parent process will be systemd + if (verbose) { + stderr.printf("Running \"%s\" directly as a foreground " + + "process.\n", startarg); + } + Posix.execv(startarg, argv); } - bus.exit(true); return Posix.EXIT_SUCCESS; } + +int restart_daemon(string[] argv) { + return start_daemon_real(argv, true); +} + +int start_daemon(string[] argv) { + return start_daemon_real(argv, false); +} + int exit_daemon(string[] argv) { var bus = get_bus(); if (bus == null) { @@ -206,11 +440,13 @@ int exit_daemon(string[] argv) { return Posix.EXIT_SUCCESS; } + int print_version(string[] argv) { print("IBus %s\n", Config.PACKAGE_VERSION); return Posix.EXIT_SUCCESS; } + int read_cache (string[] argv) { const OptionEntry[] options = { { "system", 0, 0, OptionArg.NONE, out is_system, @@ -251,6 +487,7 @@ int read_cache (string[] argv) { return Posix.EXIT_SUCCESS; } + int write_cache (string[] argv) { const OptionEntry[] options = { { "system", 0, 0, OptionArg.NONE, out is_system, @@ -283,12 +520,14 @@ int write_cache (string[] argv) { Posix.EXIT_SUCCESS : Posix.EXIT_FAILURE; } + int print_address(string[] argv) { string address = IBus.get_address(); print("%s\n", address != null ? address : "(null)"); return Posix.EXIT_SUCCESS; } + private int read_config_options(string[] argv) { const OptionEntry[] options = { { "engine-id", 0, 0, OptionArg.STRING, out engine_id, @@ -309,6 +548,7 @@ private int read_config_options(string[] argv) { return Posix.EXIT_SUCCESS; } + private GLib.SList get_ibus_schemas() { string[] ids = {}; if (engine_id != null) { @@ -342,6 +582,7 @@ private GLib.SList get_ibus_schemas() { return ibus_schemas; } + int read_config(string[] argv) { if (read_config_options(argv) == Posix.EXIT_FAILURE) return Posix.EXIT_FAILURE; @@ -370,6 +611,7 @@ int read_config(string[] argv) { return Posix.EXIT_SUCCESS; } + int reset_config(string[] argv) { if (read_config_options(argv) == Posix.EXIT_FAILURE) return Posix.EXIT_FAILURE; @@ -401,6 +643,7 @@ int reset_config(string[] argv) { return Posix.EXIT_SUCCESS; } + #if EMOJI_DICT int emoji_dialog(string[] argv) { string cmd = Config.LIBEXECDIR + "/ibus-ui-emojier"; @@ -427,11 +670,13 @@ int emoji_dialog(string[] argv) { } #endif + int print_help(string[] argv) { print_usage(stdout); return Posix.EXIT_SUCCESS; } + delegate int EntryFunc(string[] argv); struct CommandEntry { @@ -440,12 +685,14 @@ struct CommandEntry { unowned EntryFunc entry; } + const CommandEntry commands[] = { { "engine", N_("Set or get engine"), get_set_engine }, { "exit", N_("Exit ibus-daemon"), exit_daemon }, { "list-engine", N_("Show available engines"), list_engine }, { "watch", N_("(Not implemented)"), message_watch }, { "restart", N_("Restart ibus-daemon"), restart_daemon }, + { "start", N_("Start ibus-daemon"), start_daemon }, { "version", N_("Show version"), print_version }, { "read-cache", N_("Show the content of registry cache"), read_cache }, { "write-cache", N_("Create registry cache"), write_cache }, @@ -460,6 +707,7 @@ const CommandEntry commands[] = { static string program_name; + void print_usage(FileStream stream) { stream.printf(_("Usage: %s COMMAND [OPTION...]\n\n"), program_name); stream.printf(_("Commands:\n")); @@ -470,6 +718,7 @@ void print_usage(FileStream stream) { } } + public int main(string[] argv) { GLib.Intl.setlocale(GLib.LocaleCategory.ALL, ""); GLib.Intl.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR); -- 2.35.3 From 5b441fabc9d766e694b992e0e2f28924d00a7402 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Thu, 7 Jul 2022 08:22:26 +0900 Subject: [PATCH] tools: Add ibus im-module command ibus im-module command can retrive gtk-im-module value from an instance of GtkIMMultiContext. The GTK version can be specified by --type option and the default is --type=gtk3 and GTK3 im-ibus.so is dlopened. --- client/gtk2/ibusim.c | 20 ++++++ client/gtk4/ibusim.c | 20 ++++++ tools/IBusIMModule-1.0.metadata | 1 + tools/Makefile.am | 116 ++++++++++++++++++++++++++------ tools/ibus.1.in | 10 +++ tools/ibusimmodule.c | 87 ++++++++++++++++++++++++ tools/ibusimmodule.h | 36 ++++++++++ tools/main.vala | 11 +++ 8 files changed, 308 insertions(+), 40 deletions(-) create mode 100644 tools/IBusIMModule-1.0.metadata create mode 100644 tools/ibusimmodule.c create mode 100644 tools/ibusimmodule.h diff --git a/client/gtk2/ibusim.c b/client/gtk2/ibusim.c index 55609ce7..e196d536 100644 --- a/client/gtk2/ibusim.c +++ b/client/gtk2/ibusim.c @@ -77,3 +77,23 @@ im_module_list (const GtkIMContextInfo ***contexts, *n_contexts = G_N_ELEMENTS (info_list); } +G_MODULE_EXPORT const char * +im_get_context_id (int *argc, + char ***argv) +{ + GtkIMContext *context; + char *preedit_string = NULL; + PangoAttrList *preedit_attrs = NULL; + const char *context_id; + + gtk_init (argc, argv); + context = gtk_im_multicontext_new (); + gtk_im_context_get_preedit_string (context, + &preedit_string, + &preedit_attrs, + 0); + context_id = gtk_im_multicontext_get_context_id ( + GTK_IM_MULTICONTEXT (context)); + return context_id; +} + diff --git a/client/gtk4/ibusim.c b/client/gtk4/ibusim.c index 5ecf9778..562bdf2d 100644 --- a/client/gtk4/ibusim.c +++ b/client/gtk4/ibusim.c @@ -50,3 +50,23 @@ g_io_im_ibus_unload (GTypeModule *type_module) g_type_module_unuse (type_module); } +G_MODULE_EXPORT const char * +im_get_context_id (int *argc, + char ***argv) +{ + GtkIMContext *context; + char *preedit_string = NULL; + PangoAttrList *preedit_attrs = NULL; + const char *context_id; + + gtk_init (); + context = gtk_im_multicontext_new (); + gtk_im_context_get_preedit_string (context, + &preedit_string, + &preedit_attrs, + 0); + context_id = gtk_im_multicontext_get_context_id ( + GTK_IM_MULTICONTEXT (context)); + return context_id; +} + diff --git a/tools/IBusIMModule-1.0.metadata b/tools/IBusIMModule-1.0.metadata new file mode 100644 index 00000000..14adc9ee --- /dev/null +++ b/tools/IBusIMModule-1.0.metadata @@ -0,0 +1 @@ +IBusIMModule cheader_filename="ibusimmodule.h" name="IBusIMModule" diff --git a/tools/Makefile.am b/tools/Makefile.am index e380a9aa..a9262ee0 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -24,9 +24,19 @@ NULL = libibus = $(top_builddir)/src/libibus-@IBUS_API_VERSION@.la +libibusimmodule = libibusimmodule.la +ibusimmodule_gir = IBusIMModule-1.0.gir +ibus_immodule_vapi = ibus-immodule-1.0.vapi libibus_emoji_dialog = \ $(top_builddir)/ui/gtk3/libibus-emoji-dialog-@IBUS_API_VERSION@.la +noinst_LTLIBRARIES = $(libibusimmodule) +noinst_DATA = +INTROSPECTION_GIRS = +MAINTAINERCLEANFILES = +DISTCLEANFILES = +VAPIGEN_VAPIS = + # force include config.h before gi18n.h. AM_CPPFLAGS = \ -I$(top_srcdir)/src \ @@ -47,22 +57,26 @@ AM_CFLAGS = \ $(NULL) AM_LDADD = \ - @GOBJECT2_LIBS@ \ - @GLIB2_LIBS@ \ - @GIO2_LIBS@ \ - @GTHREAD2_LIBS@ \ - $(libibus) \ - $(NULL) + @GOBJECT2_LIBS@ \ + @GLIB2_LIBS@ \ + @GIO2_LIBS@ \ + @GTHREAD2_LIBS@ \ + $(libibus) \ + $(libibusimmodule) \ + $(NULL) AM_VALAFLAGS = \ - --vapidir=$(top_builddir)/bindings/vala \ - --vapidir=$(top_srcdir)/bindings/vala \ - --pkg=gio-2.0 \ - --pkg=ibus-1.0 \ - --pkg=posix \ - --pkg=config \ - --target-glib="$(VALA_TARGET_GLIB_VERSION)" \ - $(NULL) + --vapidir=$(top_builddir)/bindings/vala \ + --vapidir=$(top_srcdir)/bindings/vala \ + --vapidir=$(builddir) \ + --vapidir=$(srcdir) \ + --pkg=gio-2.0 \ + --pkg=ibus-1.0 \ + --pkg=ibus-immodule-1.0 \ + --pkg=posix \ + --pkg=config \ + --target-glib="$(VALA_TARGET_GLIB_VERSION)" \ + $(NULL) bin_PROGRAMS = ibus @@ -79,9 +93,27 @@ bash_completion_DATA= \ $(NULL) bash_completiondir=@datadir@/bash-completion/completions +libibusimmodule_la_SOURCES = \ + ibusimmodule.c \ + ibusimmodule.h \ + $(NULL) +libibusimmodule_la_CFLAGS = \ + @GLIB2_CFLAGS@ \ + -DGTK2_IM_MODULEDIR=\"$(GTK2_IM_MODULEDIR)\" \ + -DGTK3_IM_MODULEDIR=\"$(GTK3_IM_MODULEDIR)\" \ + -DGTK4_IM_MODULEDIR=\"$(GTK4_IM_MODULEDIR)\" \ + $(NULL) +libibusimmodule_la_LIBADD = \ + @GLIB2_LIBS@ \ + $(NULL) +libibusimmodule_la_LDFLAGS = \ + -no-undefined \ + -export-symbols-regex "ibus_.*" \ + $(NULL) + man_one_in_files = ibus.1.in man_one_files = $(man_one_in_files:.1.in=.1) -man_one_DATA =$(man_one_files:.1=.1.gz) +man_one_DATA =$(man_one_files:.1=.1.gz) man_onedir = $(mandir)/man1 %.1: %.1.in $(AM_V_GEN) sed \ @@ -91,14 +123,17 @@ man_onedir = $(mandir)/man1 $(AM_V_GEN) gzip -c $< > $@.tmp && mv $@.tmp $@ EXTRA_DIST = \ - $(man_one_in_files) \ - ibus.bash \ - $(NULL) + $(ibus_immodule_vapi) \ + $(ibusimmodule_gir) \ + $(man_one_in_files) \ + ibus.bash \ + IBusIMModule-1.0.metadata \ + $(NULL) CLEANFILES = \ - $(man_one_DATA) \ - $(man_one_files) \ - $(NULL) + $(man_one_DATA) \ + $(man_one_files) \ + $(NULL) if ENABLE_EMOJI_DICT if ENABLE_UI @@ -108,4 +143,43 @@ AM_VALAFLAGS += \ endif endif +if HAVE_INTROSPECTION +BUILT_SOURCES = $(INTROSPECTION_GIRS) $(VAPIGEN_VAPIS) + +-include $(INTROSPECTION_MAKEFILE) +INTROSPECTION_SCANNER_ARGS = +INTROSPECTION_COMPILER_ARGS = \ + --includedir=$(srcdir) \ + --includedir=. \ + $(NULL) + +IBusIMModule-1.0.gir: $(libibusimmodule) Makefile +IBusIMModule_1_0_gir_SCANNERFLAGS = \ + --pkg=glib-2.0 \ + $(IBUS_GIR_SCANNERFLAGS) \ + $(NULL) +IBusIMModule_1_0_gir_INCLUDES = GLib-2.0 +IBusIMModule_1_0_gir_LIBS = $(libibusimmodule) +IBusIMModule_1_0_gir_FILES = ibusimmodule.h +IBusIMModule_1_0_gir_CFLAGS = \ + -I$(srcdir) \ + -I$(builddir) \ + $(NULL) + +INTROSPECTION_GIRS += $(ibusimmodule_gir) +noinst_DATA += $(ibusimmodule_gir) +MAINTAINERCLEANFILES += $(ibusimmodule_gir) +DISTCLEANFILES += $(ibusimmodule_gir) + +-include $(VAPIGEN_MAKEFILE) +ibus-immodule-1.0.vapi: $(ibusimmodule_gir) IBusIMModule-1.0.metadata +ibus_immodule_1_0_vapi_DEPS = glib-2.0 +ibus_immodule_1_0_vapi_METADATADIRS = $(srcdir) +ibus_immodule_1_0_vapi_FILES = IBusIMModule-1.0.gir +VAPIGEN_VAPIS += $(ibus_immodule_vapi) +noinst_DATA += $(ibus_immodule_vapi) +MAINTAINERCLEANFILES += $(ibus_immodule_vapi) +DISTCLEANFILES += $(ibus_immodule_vapi) +endif + -include $(top_srcdir)/git.mk diff --git a/tools/ibus.1.in b/tools/ibus.1.in index fe1b7157..84ef5fff 100644 --- a/tools/ibus.1.in +++ b/tools/ibus.1.in @@ -128,6 +128,16 @@ option enables to match annotations with a partial string. These settings are available with .B ibus\-setup (1) utility. +.TP +\fBim-module\fR [\fB\-\-type=TYPE|\-\-help\fR] +Show an internal im-module value in a virtual GTK application. If IBus is +installed and configured properly, the output is "ibus". This sub-command +is useful for some users who build IBus from the source codes and check +the configurations. Currently the sub-command supports GTK applications only +and the default is GTK3. If you wish to check a GTK4 application, you can +specify +.B \-\-type=gtk4 +option and you can choose one of "gtk2", "gtk3" and "gtk4". .SH BUGS If you find a bug, please report it at https://github.com/ibus/ibus/issues diff --git a/tools/ibusimmodule.c b/tools/ibusimmodule.c new file mode 100644 index 00000000..20ccc748 --- /dev/null +++ b/tools/ibusimmodule.c @@ -0,0 +1,87 @@ +#include +#include +#include + +#ifndef DEFAULT_IM_MODULE_TYPE +#define DEFAULT_IM_MODULE_TYPE "gtk3" +#endif + +#define OPTION_TYPE_MESSAGE \ + N_("Type im-module TYPE = \"gtk2\", \"gtk3\", \"gtk4\". Default is " \ + "\"gtk3\".") + +typedef const char * (* IBusIMGetContextIdFunc) (int *argc, char ***argv); + +static char *im_module_type; + + +char * +ibus_im_module_get_id (int argc, char *argv[]) +{ + static const GOptionEntry options[3] = { + { "type", (char)0, (int)0, G_OPTION_ARG_STRING, &im_module_type, + OPTION_TYPE_MESSAGE, + "TYPE"}, + { NULL } + }; + GOptionContext *option; + GError *error = NULL; + void *module; + char *im_context_id; + IBusIMGetContextIdFunc im_get_context_id; + + if (!(option = g_option_context_new (NULL))) { + g_critical ("malloc GOptionContext is failed."); + return NULL; + } + g_option_context_add_main_entries (option, options, GETTEXT_PACKAGE); + g_option_context_parse (option, &argc, &argv, &error); + if (error) { + g_critical ("%s", error->message); + g_clear_error (&error); + return NULL; + } + g_option_context_free (option); + if (!im_module_type) + im_module_type = g_strdup (DEFAULT_IM_MODULE_TYPE); + + if (G_LIKELY (!g_strcmp0 (im_module_type, "gtk3"))) { + module = dlopen (GTK3_IM_MODULEDIR "/im-ibus.so", + RTLD_LAZY); + } else if (!g_strcmp0 (im_module_type, "gtk4")) { + const char *module_path_env = g_getenv ("GTK_PATH"); + char *module_path; + if (module_path_env) { + module_path = g_build_filename (module_path_env, + GTK4_IM_MODULEDIR "/libim-ibus.so", + NULL); + } else { + module_path = g_strdup (GTK4_IM_MODULEDIR "/libim-ibus.so"); + } + module = dlopen (module_path, RTLD_LAZY); + g_free (module_path); + } else if (!g_strcmp0 (im_module_type, "gtk2")) { + module = dlopen (GTK2_IM_MODULEDIR "/im-ibus.so", + RTLD_LAZY); + } else { + module = dlopen (im_module_type, RTLD_LAZY); + } + if (!module) { + g_warning ("Not found module: %s", dlerror ()); + return NULL; + } + + im_get_context_id = dlsym (module, "im_get_context_id"); + if (!im_get_context_id) { + g_warning ("Not found im_get_context_id: %s", dlerror ()); + dlclose (module); + return NULL; + } + + im_context_id = strdup (im_get_context_id (&argc, &argv)); + dlclose (module); + return im_context_id; +} + +#undef DEFAULT_IM_MODULE_TYPE + diff --git a/tools/ibusimmodule.h b/tools/ibusimmodule.h new file mode 100644 index 00000000..e762a747 --- /dev/null +++ b/tools/ibusimmodule.h @@ -0,0 +1,36 @@ +/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ +/* vim:set et sts=4: */ +/* ibus - The Input Bus + * Copyright (C) 2022 Takao Fujiwara + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __IBUS_IM_MODULE_CONTEXT_H_ +#define __IBUS_IM_MODULE_CONTEXT_H_ + +/** + * ibus_im_module_get_id: + * @argc: The length of argv + * @argv: (array length=argc) (element-type utf8): argv from main() + * + * Retrieve im-module value from GTK instance. + * + * Returns: (nullable): im-module value. + */ +char * ibus_im_module_get_id (int argc, char *argv[]); + +#endif diff --git a/tools/main.vala b/tools/main.vala index 407eaf74..1fed2440 100644 --- a/tools/main.vala +++ b/tools/main.vala @@ -671,6 +671,15 @@ int emoji_dialog(string[] argv) { #endif +int read_im_module(string[] argv) { + string? im_module = IBusIMModule.im_module_get_id(argv); + if (im_module == null) + return Posix.EXIT_FAILURE; + print("%s\n".printf(im_module)); + return Posix.EXIT_SUCCESS; +} + + int print_help(string[] argv) { print_usage(stdout); return Posix.EXIT_SUCCESS; @@ -702,6 +711,8 @@ const CommandEntry commands[] = { #if EMOJI_DICT { "emoji", N_("Save emoji on dialog to clipboard"), emoji_dialog }, #endif + { "im-module", N_("Retrieve im-module value from GTK instance"), + read_im_module }, { "help", N_("Show this information"), print_help } }; -- 2.35.3 From 7e42b437c901bb56ca2f776aad5fe65d0d8c246a Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Thu, 7 Jul 2022 08:22:42 +0900 Subject: [PATCH] client/gtk2: Implement new process_key_event for GTK4 --- client/gtk2/ibusimcontext.c | 147 ++++++++++++++++++++++++++++++------ src/ibustypes.h | 4 + 2 files changed, 127 insertions(+), 24 deletions(-) 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.35.3 From b14cab3753c6510a0a48eec673aa6eac89c793a1 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Thu, 7 Jul 2022 08:22:45 +0900 Subject: [PATCH] src/ibusengine: Add focus_in_id()/focus_out_id() class methods IBusEngine constructor now has a 'has-focus-id' property and if it's %TRUE, IBusEngine::focus_in_id()/focus_out_id() are called instaed of IBusEngine::focus_in()/focus_out() and the class method has an object_path argument for the unique input context ID and a client argument for the client application type likes ibus-gtk, ibus-gtk4, xim. --- bus/engineproxy.c | 304 +++++++++++++++++++++++++++++----------- bus/engineproxy.h | 12 +- bus/ibusimpl.c | 13 ++ bus/ibusimpl.h | 13 +- bus/inputcontext.c | 50 +++++-- src/ibusengine.c | 217 ++++++++++++++++++++++++++-- src/ibusengine.h | 10 +- src/ibusmarshalers.list | 1 + 8 files changed, 505 insertions(+), 115 deletions(-) diff --git a/bus/engineproxy.c b/bus/engineproxy.c index 2d98995c..fd1f34fb 100644 --- a/bus/engineproxy.c +++ b/bus/engineproxy.c @@ -2,7 +2,7 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2015-2018 Takao Fujiwara + * Copyright (C) 2015-2022 Takao Fujiwara * Copyright (C) 2008-2016 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -59,6 +59,7 @@ struct _BusEngineProxy { /* cached properties */ IBusPropList *prop_list; + gboolean has_focus_id; }; struct _BusEngineProxyClass { @@ -105,30 +106,35 @@ static IBusText *text_empty = NULL; static IBusPropList *prop_list_empty = NULL; /* functions prototype */ -static void bus_engine_proxy_set_property (BusEngineProxy *engine, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void bus_engine_proxy_get_property (BusEngineProxy *engine, - guint prop_id, - GValue *value, - GParamSpec *pspec); +static void bus_engine_proxy_set_property (BusEngineProxy *engine, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void bus_engine_proxy_get_property (BusEngineProxy *engine, + guint prop_id, + GValue *value, + GParamSpec *pspec); static void bus_engine_proxy_real_register_properties - (BusEngineProxy *engine, - IBusPropList *prop_list); + (BusEngineProxy *engine, + IBusPropList *prop_list); static void bus_engine_proxy_real_update_property - (BusEngineProxy *engine, - IBusProperty *prop); -static void bus_engine_proxy_real_destroy (IBusProxy *proxy); -static void bus_engine_proxy_g_signal (GDBusProxy *proxy, - const gchar *sender_name, - const gchar *signal_name, - GVariant *parameters); + (BusEngineProxy *engine, + IBusProperty *prop); +static void bus_engine_proxy_real_destroy (IBusProxy *proxy); +static void bus_engine_proxy_g_signal (GDBusProxy *proxy, + const gchar *sender_name, + const gchar *signal_name, + GVariant *parameters); static void bus_engine_proxy_initable_iface_init - (GInitableIface *initable_iface); + (GInitableIface + *initable_iface); +static void bus_engine_proxy_get_has_focus_id + (BusEngineProxy *engine); G_DEFINE_TYPE_WITH_CODE (BusEngineProxy, bus_engine_proxy, IBUS_TYPE_PROXY, - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, bus_engine_proxy_initable_iface_init) + G_IMPLEMENT_INTERFACE ( + G_TYPE_INITABLE, + bus_engine_proxy_initable_iface_init) ); static GInitableIface *parent_initable_iface = NULL; @@ -138,8 +144,10 @@ bus_engine_proxy_class_init (BusEngineProxyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); - gobject_class->set_property = (GObjectSetPropertyFunc)bus_engine_proxy_set_property; - gobject_class->get_property = (GObjectGetPropertyFunc)bus_engine_proxy_get_property; + gobject_class->set_property = + (GObjectSetPropertyFunc)bus_engine_proxy_set_property; + gobject_class->get_property = + (GObjectGetPropertyFunc)bus_engine_proxy_get_property; class->register_properties = bus_engine_proxy_real_register_properties; class->update_property = bus_engine_proxy_real_update_property; @@ -147,8 +155,9 @@ bus_engine_proxy_class_init (BusEngineProxyClass *class) IBUS_PROXY_CLASS (class)->destroy = bus_engine_proxy_real_destroy; G_DBUS_PROXY_CLASS (class)->g_signal = bus_engine_proxy_g_signal; - parent_initable_iface = - (GInitableIface *)g_type_interface_peek (bus_engine_proxy_parent_class, G_TYPE_INITABLE); + parent_initable_iface = (GInitableIface *)g_type_interface_peek ( + bus_engine_proxy_parent_class, + G_TYPE_INITABLE); /* install properties */ g_object_class_install_property (gobject_class, @@ -164,7 +173,9 @@ bus_engine_proxy_class_init (BusEngineProxyClass *class) G_PARAM_STATIC_NICK )); - /* install glib signals that will be sent when corresponding D-Bus signals are sent from an engine process. */ + /* install glib signals that will be sent when corresponding D-Bus signals + * are sent from an engine process. + */ engine_signals[COMMIT_TEXT] = g_signal_new (I_("commit-text"), G_TYPE_FROM_CLASS (class), @@ -473,7 +484,8 @@ bus_engine_proxy_real_destroy (IBusProxy *proxy) engine->prop_list = NULL; } - IBUS_PROXY_CLASS (bus_engine_proxy_parent_class)->destroy ((IBusProxy *)engine); + IBUS_PROXY_CLASS (bus_engine_proxy_parent_class)->destroy ( + (IBusProxy *)engine); } static void @@ -486,7 +498,8 @@ _g_object_unref_if_floating (gpointer instance) /** * bus_engine_proxy_g_signal: * - * Handle all D-Bus signals from the engine process. This function emits corresponding glib signal for the D-Bus signal. + * Handle all D-Bus signals from the engine process. This function emits + * corresponding glib signal for the D-Bus signal. */ static void bus_engine_proxy_g_signal (GDBusProxy *proxy, @@ -522,7 +535,9 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy, } } - /* Handle D-Bus signals with parameters. Deserialize them and emit a glib signal. */ + /* Handle D-Bus signals with parameters. Deserialize them and emit a glib + * signal. + */ if (g_strcmp0 (signal_name, "CommitText") == 0) { GVariant *arg0 = NULL; g_variant_get (parameters, "(v)", &arg0); @@ -568,7 +583,8 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy, gboolean visible = FALSE; guint mode = 0; - g_variant_get (parameters, "(vubu)", &arg0, &cursor_pos, &visible, &mode); + g_variant_get (parameters, "(vubu)", + &arg0, &cursor_pos, &visible, &mode); g_return_if_fail (arg0 != NULL); IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (arg0)); @@ -594,7 +610,11 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy, g_variant_unref (arg0); g_return_if_fail (text != NULL); - g_signal_emit (engine, engine_signals[UPDATE_AUXILIARY_TEXT], 0, text, visible); + g_signal_emit (engine, + engine_signals[UPDATE_AUXILIARY_TEXT], + 0, + text, + visible); _g_object_unref_if_floating (text); return; } @@ -606,11 +626,16 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy, g_variant_get (parameters, "(vb)", &arg0, &visible); g_return_if_fail (arg0 != NULL); - IBusLookupTable *table = IBUS_LOOKUP_TABLE (ibus_serializable_deserialize (arg0)); + IBusLookupTable *table = + IBUS_LOOKUP_TABLE (ibus_serializable_deserialize (arg0)); g_variant_unref (arg0); g_return_if_fail (table != NULL); - g_signal_emit (engine, engine_signals[UPDATE_LOOKUP_TABLE], 0, table, visible); + g_signal_emit (engine, + engine_signals[UPDATE_LOOKUP_TABLE], + 0, + table, + visible); _g_object_unref_if_floating (table); return; } @@ -620,11 +645,15 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy, g_variant_get (parameters, "(v)", &arg0); g_return_if_fail (arg0 != NULL); - IBusPropList *prop_list = IBUS_PROP_LIST (ibus_serializable_deserialize (arg0)); + IBusPropList *prop_list = + IBUS_PROP_LIST (ibus_serializable_deserialize (arg0)); g_variant_unref (arg0); g_return_if_fail (prop_list != NULL); - g_signal_emit (engine, engine_signals[REGISTER_PROPERTIES], 0, prop_list); + g_signal_emit (engine, + engine_signals[REGISTER_PROPERTIES], + 0, + prop_list); _g_object_unref_if_floating (prop_list); return; } @@ -634,7 +663,8 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy, g_variant_get (parameters, "(v)", &arg0); g_return_if_fail (arg0 != NULL); - IBusProperty *prop = IBUS_PROPERTY (ibus_serializable_deserialize (arg0)); + IBusProperty *prop = + IBUS_PROPERTY (ibus_serializable_deserialize (arg0)); g_variant_unref (arg0); g_return_if_fail (prop != NULL); @@ -665,26 +695,45 @@ bus_engine_proxy_new_internal (const gchar *path, IBusEngineDesc *desc, GDBusConnection *connection) { + GDBusProxyFlags flags; + BusEngineProxy *engine; + BusIBusImpl *ibus = BUS_DEFAULT_IBUS; + GHashTable *hash_table = NULL; + EngineFocusCategory category = ENGINE_FOCUS_CATEGORY_NONE; + g_assert (path); g_assert (IBUS_IS_ENGINE_DESC (desc)); g_assert (G_IS_DBUS_CONNECTION (connection)); - GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START; - BusEngineProxy *engine = - (BusEngineProxy *) g_initable_new (BUS_TYPE_ENGINE_PROXY, - NULL, - NULL, - "desc", desc, - "g-connection", connection, - "g-interface-name", IBUS_INTERFACE_ENGINE, - "g-object-path", path, - "g-default-timeout", g_gdbus_timeout, - "g-flags", flags, - NULL); + flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START; + engine = (BusEngineProxy *) g_initable_new ( + BUS_TYPE_ENGINE_PROXY, + NULL, + NULL, + "desc", desc, + "g-connection", connection, + "g-interface-name", IBUS_INTERFACE_ENGINE, + "g-object-path", path, + "g-default-timeout", g_gdbus_timeout, + "g-flags", flags, + NULL); const gchar *layout = ibus_engine_desc_get_layout (desc); if (layout != NULL && layout[0] != '\0') { engine->keymap = ibus_keymap_get (layout); } + if (ibus) + hash_table = bus_ibus_impl_get_engine_focus_id_table (ibus); + if (hash_table) { + category = (EngineFocusCategory)GPOINTER_TO_INT ( + g_hash_table_lookup (hash_table, + ibus_engine_desc_get_name (desc))); + if (category == ENGINE_FOCUS_CATEGORY_HAS_ID) + engine->has_focus_id = TRUE; + else if (category == ENGINE_FOCUS_CATEGORY_NO_ID) + engine->has_focus_id = FALSE; + else + bus_engine_proxy_get_has_focus_id (engine); + } return engine; } @@ -740,7 +789,8 @@ engine_proxy_new_data_free (EngineProxyNewData *data) /** * create_engine_ready_cb: * - * A callback function to be called when bus_factory_proxy_create_engine finishes. + * A callback function to be called when bus_factory_proxy_create_engine + * finishes. * Create an BusEngineProxy object and call the GAsyncReadyCallback. */ static void @@ -775,8 +825,10 @@ create_engine_ready_cb (BusFactoryProxy *factory, /** * notify_factory_cb: * - * A callback function to be called when bus_component_start() emits "notify::factory" signal within 5 seconds. - * Call bus_factory_proxy_create_engine to create the engine proxy asynchronously. + * A callback function to be called when bus_component_start() emits + * "notify::factory" signal within 5 seconds. + * Call bus_factory_proxy_create_engine to create the engine proxy + * asynchronously. */ static void notify_factory_cb (BusComponent *component, @@ -798,22 +850,25 @@ notify_factory_cb (BusComponent *component, data->handler_id = 0; } - /* We *have to* disconnect the cancelled_cb here, since g_dbus_proxy_call - * calls create_engine_ready_cb even if the proxy call is cancelled, and - * in this case, create_engine_ready_cb itself will return error using - * g_task_return_error(). */ + /* We *have to* disconnect the cancelled_cb here, since + * g_dbus_proxy_call calls create_engine_ready_cb even if the proxy + * call is cancelled, and in this case, create_engine_ready_cb itself + * will return error using g_task_return_error(). + */ if (data->cancellable && data->cancelled_handler_id != 0) { - g_cancellable_disconnect (data->cancellable, data->cancelled_handler_id); + g_cancellable_disconnect (data->cancellable, + data->cancelled_handler_id); data->cancelled_handler_id = 0; } /* Create engine from factory. */ - bus_factory_proxy_create_engine (data->factory, - data->desc, - data->timeout, - data->cancellable, - (GAsyncReadyCallback) create_engine_ready_cb, - data); + bus_factory_proxy_create_engine ( + data->factory, + data->desc, + data->timeout, + data->cancellable, + (GAsyncReadyCallback) create_engine_ready_cb, + data); } /* If factory is NULL, we will continue wait for * factory notify signal or timeout */ @@ -822,7 +877,8 @@ notify_factory_cb (BusComponent *component, /** * timeout_cb: * - * A callback function to be called when bus_component_start() does not emit "notify::factory" signal within 5 seconds. + * A callback function to be called when bus_component_start() does not emit + * "notify::factory" signal within 5 seconds. * Call the GAsyncReadyCallback and stop the 5 sec timer. */ static gboolean @@ -927,16 +983,18 @@ bus_engine_proxy_new (IBusEngineDesc *desc, /* The factory is ready. We'll create the engine proxy directly. */ g_object_ref (data->factory); - /* We don't have to connect to cancelled_cb here, since g_dbus_proxy_call - * calls create_engine_ready_cb even if the proxy call is cancelled, and - * in this case, create_engine_ready_cb itself can return error using - * g_task_return_error(). */ - bus_factory_proxy_create_engine (data->factory, - data->desc, - timeout, - cancellable, - (GAsyncReadyCallback) create_engine_ready_cb, - data); + /* We don't have to connect to cancelled_cb here, since + * g_dbus_proxy_call calls create_engine_ready_cb even if the proxy + * call is cancelled, and in this case, create_engine_ready_cb itself + * can return error using g_task_return_error(). + */ + bus_factory_proxy_create_engine ( + data->factory, + data->desc, + timeout, + cancellable, + (GAsyncReadyCallback) create_engine_ready_cb, + data); } } @@ -978,8 +1036,11 @@ bus_engine_proxy_process_key_event (BusEngineProxy *engine, { g_assert (BUS_IS_ENGINE_PROXY (engine)); - if (keycode != 0 && bus_ibus_impl_is_use_sys_layout (BUS_DEFAULT_IBUS) == FALSE) { - /* Since use_sys_layout is false, we don't rely on XKB. Try to convert keyval from keycode by using our own mapping. */ + if (keycode != 0 && + bus_ibus_impl_is_use_sys_layout (BUS_DEFAULT_IBUS) == FALSE) { + /* Since use_sys_layout is false, we don't rely on XKB. Try to convert + * keyval from keycode by using our own mapping. + */ IBusKeymap *keymap = engine->keymap; if (keymap == NULL) keymap = BUS_DEFAULT_KEYMAP; @@ -1142,7 +1203,8 @@ void bus_engine_proxy_set_surrounding_text (BusEngineProxy *engine, g_strcmp0 (text->text, engine->surrounding_text->text) != 0 || cursor_pos != engine->surrounding_cursor_pos || anchor_pos != engine->selection_anchor_pos) { - GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text); + GVariant *variant = + ibus_serializable_serialize ((IBusSerializable *)text); if (engine->surrounding_text) g_object_unref (engine->surrounding_text); engine->surrounding_text = (IBusText *) g_object_ref_sink (text); @@ -1201,6 +1263,61 @@ bus_engine_proxy_set_content_type (BusEngineProxy *engine, g_variant_unref (content_type); } +static void +_get_has_focus_id_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + GHashTable *hash_table = (GHashTable*)user_data; + BusEngineProxy *engine; + GError *error = NULL; + GVariant *result; + + g_return_if_fail (BUS_IS_ENGINE_PROXY (object)); + engine = BUS_ENGINE_PROXY (object); + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), res, &error); + + if (result != NULL) { + GVariant *variant = NULL; + gpointer value; + g_variant_get (result, "(v)", &variant); + engine->has_focus_id = g_variant_get_boolean (variant); + g_variant_unref (variant); + g_variant_unref (result); + value = GINT_TO_POINTER (engine->has_focus_id + ? ENGINE_FOCUS_CATEGORY_HAS_ID + : ENGINE_FOCUS_CATEGORY_NO_ID); + g_hash_table_replace ( + hash_table, + (gpointer)ibus_engine_desc_get_name (engine->desc), + value); + } + g_hash_table_unref (hash_table); +} + +static void +bus_engine_proxy_get_has_focus_id (BusEngineProxy *engine) +{ + BusIBusImpl *ibus = BUS_DEFAULT_IBUS; + GHashTable *hash_table; + + g_assert (BUS_IS_ENGINE_PROXY (engine)); + g_assert (ibus); + + hash_table = bus_ibus_impl_get_engine_focus_id_table (ibus); + g_assert (hash_table); + g_dbus_proxy_call ((GDBusProxy *) engine, + "org.freedesktop.DBus.Properties.Get", + g_variant_new ("(ss)", + IBUS_INTERFACE_ENGINE, + "FocusId"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + _get_has_focus_id_cb, + g_hash_table_ref (hash_table)); +} + /* a macro to generate a function to call a nullary D-Bus method. */ #define DEFINE_FUNCTION(Name, name) \ void \ @@ -1223,11 +1340,24 @@ DEFINE_FUNCTION (CursorDown, cursor_down) #undef DEFINE_FUNCTION void -bus_engine_proxy_focus_in (BusEngineProxy *engine) +bus_engine_proxy_focus_in (BusEngineProxy *engine, + const gchar *object_path, + const gchar *client) { g_assert (BUS_IS_ENGINE_PROXY (engine)); - if (!engine->has_focus) { - engine->has_focus = TRUE; + if (engine->has_focus) + return; + engine->has_focus = TRUE; + if (engine->has_focus_id) { + g_dbus_proxy_call ((GDBusProxy *)engine, + "FocusInId", + g_variant_new ("(ss)", object_path, client), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL, + NULL); + } else { g_dbus_proxy_call ((GDBusProxy *)engine, "FocusIn", NULL, @@ -1240,11 +1370,23 @@ bus_engine_proxy_focus_in (BusEngineProxy *engine) } void -bus_engine_proxy_focus_out (BusEngineProxy *engine) +bus_engine_proxy_focus_out (BusEngineProxy *engine, + const gchar *object_path) { g_assert (BUS_IS_ENGINE_PROXY (engine)); - if (engine->has_focus) { - engine->has_focus = FALSE; + if (!engine->has_focus) + return; + engine->has_focus = FALSE; + if (engine->has_focus_id) { + g_dbus_proxy_call ((GDBusProxy *)engine, + "FocusOutId", + g_variant_new ("(s)", object_path), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL, + NULL); + } else { g_dbus_proxy_call ((GDBusProxy *)engine, "FocusOut", NULL, diff --git a/bus/engineproxy.h b/bus/engineproxy.h index a3006b47..957b7851 100644 --- a/bus/engineproxy.h +++ b/bus/engineproxy.h @@ -2,7 +2,7 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2018 Takao Fujiwara + * Copyright (C) 2018-2022 Takao Fujiwara * Copyright (C) 2008-2018 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -126,20 +126,26 @@ void bus_engine_proxy_set_cursor_location /** * bus_engine_proxy_focus_in: * @engine: A #BusEngineProxy. + * @object_path: An object path. + * @client: A client name. * * Call "FocusIn" method of an engine asynchronously. Do nothing if * the engine already has a focus. */ -void bus_engine_proxy_focus_in (BusEngineProxy *engine); +void bus_engine_proxy_focus_in (BusEngineProxy *engine, + const gchar *object_path, + const gchar *client); /** * bus_engine_proxy_focus_out: * @engine: A #BusEngineProxy. + * @object_path: An object path. * * Call "FocusOut" method of an engine asynchronously. Do nothing if * the engine does not have a focus. */ -void bus_engine_proxy_focus_out (BusEngineProxy *engine); +void bus_engine_proxy_focus_out (BusEngineProxy *engine, + const gchar *object_path); /** * bus_engine_proxy_reset: diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c index 49a138fe..8a443545 100644 --- a/bus/ibusimpl.c +++ b/bus/ibusimpl.c @@ -72,6 +72,8 @@ struct _BusIBusImpl { * IBusEngineDesc object. */ GHashTable *engine_table; + GHashTable *engine_focus_id_table; + BusInputContext *focused_context; BusPanelProxy *panel; BusPanelProxy *emoji_extension; @@ -596,6 +598,7 @@ bus_ibus_impl_init (BusIBusImpl *ibus) ibus->use_global_engine = TRUE; ibus->global_engine_name = NULL; ibus->global_previous_engine_name = NULL; + ibus->engine_focus_id_table = g_hash_table_new (g_str_hash, g_str_equal); /* focus the fake_context, if use_global_engine is enabled. */ if (ibus->use_global_engine) @@ -2384,3 +2387,13 @@ bus_ibus_impl_get_focused_input_context (BusIBusImpl *ibus) return ibus->focused_context; } + +GHashTable * +bus_ibus_impl_get_engine_focus_id_table (BusIBusImpl *ibus) +{ + + g_assert (BUS_IS_IBUS_IMPL (ibus)); + + return ibus->engine_focus_id_table; +} + diff --git a/bus/ibusimpl.h b/bus/ibusimpl.h index 0bb18daf..cbe6856d 100644 --- a/bus/ibusimpl.h +++ b/bus/ibusimpl.h @@ -2,7 +2,8 @@ /* vim:set et sts=4: */ /* bus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2008-2013 Red Hat, Inc. + * Copyright (C) 2022 Takao Fujiwara + * 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 @@ -58,6 +59,13 @@ G_BEGIN_DECLS typedef struct _BusIBusImpl BusIBusImpl; typedef struct _BusIBusImplClass BusIBusImplClass; +typedef enum +{ + ENGINE_FOCUS_CATEGORY_NONE = 0, + ENGINE_FOCUS_CATEGORY_NO_ID, + ENGINE_FOCUS_CATEGORY_HAS_ID +} EngineFocusCategory; + GType bus_ibus_impl_get_type (void); /** @@ -81,6 +89,7 @@ gboolean bus_ibus_impl_is_embed_preedit_text (BusIBusImpl *ibus); BusInputContext *bus_ibus_impl_get_focused_input_context (BusIBusImpl *ibus); - +GHashTable *bus_ibus_impl_get_engine_focus_id_table + (BusIBusImpl *ibus); G_END_DECLS #endif diff --git a/bus/inputcontext.c b/bus/inputcontext.c index 8d84fd05..72041ecb 100644 --- a/bus/inputcontext.c +++ b/bus/inputcontext.c @@ -846,7 +846,8 @@ _ic_process_key_event_reply_cb (GObject *source, /** * _ic_process_key_event: * - * Implement the "ProcessKeyEvent" method call of the org.freedesktop.IBus.InputContext interface. + * Implement the "ProcessKeyEvent" method call of the + * org.freedesktop.IBus.InputContext interface. */ static void _ic_process_key_event (BusInputContext *context, @@ -860,11 +861,13 @@ _ic_process_key_event (BusInputContext *context, g_variant_get (parameters, "(uuu)", &keyval, &keycode, &modifiers); if (G_UNLIKELY (!context->has_focus)) { /* workaround: set focus if context does not have focus */ - BusInputContext *focused_context = bus_ibus_impl_get_focused_input_context (BUS_DEFAULT_IBUS); + BusInputContext *focused_context = + bus_ibus_impl_get_focused_input_context (BUS_DEFAULT_IBUS); if (focused_context == NULL || focused_context->fake == TRUE || context->fake == FALSE) { - /* grab focus, if context is a real IC or current focused IC is fake */ + /* grab focus, if context is a real IC or current focused IC is + * fake */ bus_input_context_focus_in (context); } } @@ -914,7 +917,8 @@ _ic_process_key_event (BusInputContext *context, data); } else { - g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", FALSE)); + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(b)", FALSE)); } } @@ -1438,7 +1442,9 @@ bus_input_context_focus_in (BusInputContext *context) context->prev_modifiers = 0; if (context->engine) { - bus_engine_proxy_focus_in (context->engine); + const gchar *path = + ibus_service_get_object_path ((IBusService *)context); + bus_engine_proxy_focus_in (context->engine, path, context->client); bus_engine_proxy_enable (context->engine); bus_engine_proxy_set_capabilities (context->engine, context->capabilities); bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h); @@ -1538,7 +1544,9 @@ bus_input_context_focus_out (BusInputContext *context) bus_input_context_register_properties (context, props_empty); if (context->engine) { - bus_engine_proxy_focus_out (context->engine); + const gchar *path = + ibus_service_get_object_path ((IBusService *)context); + bus_engine_proxy_focus_out (context->engine, path); } context->has_focus = FALSE; @@ -2376,11 +2384,19 @@ bus_input_context_enable (BusInputContext *context) if (context->engine == NULL) return; - bus_engine_proxy_focus_in (context->engine); - bus_engine_proxy_enable (context->engine); - bus_engine_proxy_set_capabilities (context->engine, context->capabilities); - bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h); - bus_engine_proxy_set_content_type (context->engine, context->purpose, context->hints); + { + const gchar *path = + ibus_service_get_object_path ((IBusService *)context); + bus_engine_proxy_focus_in (context->engine, path, context->client); + bus_engine_proxy_enable (context->engine); + bus_engine_proxy_set_capabilities (context->engine, + context->capabilities); + bus_engine_proxy_set_cursor_location (context->engine, + context->x, context->y, + context->w, context->h); + bus_engine_proxy_set_content_type (context->engine, + context->purpose, context->hints); + } } void @@ -2397,7 +2413,9 @@ bus_input_context_disable (BusInputContext *context) bus_input_context_register_properties (context, props_empty); if (context->engine) { - bus_engine_proxy_focus_out (context->engine); + const gchar *path = + ibus_service_get_object_path ((IBusService *)context); + bus_engine_proxy_focus_out (context->engine, path); bus_engine_proxy_disable (context->engine); } } @@ -2445,6 +2463,8 @@ bus_input_context_unset_engine (BusInputContext *context) if (context->engine) { gint i; + const gchar *path = + ibus_service_get_object_path ((IBusService *)context); /* uninstall signal handlers for the engine. */ for (i = 0; i < G_N_ELEMENTS(engine_signals); i++) { g_signal_handlers_disconnect_by_func (context->engine, @@ -2453,7 +2473,7 @@ bus_input_context_unset_engine (BusInputContext *context) /* focus out engine so that the next call of bus_engine_proxy_focus_in() will take effect and trigger RegisterProperties. */ - bus_engine_proxy_focus_out (context->engine); + bus_engine_proxy_focus_out (context->engine, path); g_object_unref (context->engine); context->engine = NULL; } @@ -2488,7 +2508,9 @@ bus_input_context_set_engine (BusInputContext *context, context); } if (context->has_focus) { - bus_engine_proxy_focus_in (context->engine); + const gchar *path = + ibus_service_get_object_path ((IBusService *)context); + bus_engine_proxy_focus_in (context->engine, path, context->client); bus_engine_proxy_enable (context->engine); bus_engine_proxy_set_capabilities (context->engine, context->capabilities); bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h); diff --git a/src/ibusengine.c b/src/ibusengine.c index 7e844838..7c797103 100644 --- a/src/ibusengine.c +++ b/src/ibusengine.c @@ -2,7 +2,7 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2018-2021 Takao Fujiwara + * Copyright (C) 2018-2022 Takao Fujiwara * Copyright (C) 2008-2021 Red Hat, Inc. * * This library is free software; you can redistribute it and/or @@ -37,7 +37,9 @@ enum { PROCESS_KEY_EVENT, FOCUS_IN, + FOCUS_IN_ID, FOCUS_OUT, + FOCUS_OUT_ID, RESET, ENABLE, DISABLE, @@ -61,6 +63,7 @@ enum { enum { PROP_0, PROP_ENGINE_NAME, + PROP_HAS_FOCUS_ID, }; @@ -82,6 +85,7 @@ struct _IBusEnginePrivate { GHashTable *extension_keybindings; gboolean enable_extension; gchar *current_extension_name; + gboolean has_focus_id; }; @@ -104,7 +108,8 @@ static void ibus_engine_service_method_call GDBusConnection *connection, const gchar *sender, const gchar *object_path, - const gchar *interface_name, + const gchar + *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation @@ -132,7 +137,12 @@ static gboolean ibus_engine_process_key_event guint keycode, guint state); static void ibus_engine_focus_in (IBusEngine *engine); +static void ibus_engine_focus_in_id (IBusEngine *engine, + const gchar *object_path, + const gchar *client); static void ibus_engine_focus_out (IBusEngine *engine); +static void ibus_engine_focus_out_id (IBusEngine *engine, + const gchar *object_path); static void ibus_engine_reset (IBusEngine *engine); static void ibus_engine_enable (IBusEngine *engine); static void ibus_engine_disable (IBusEngine *engine); @@ -170,7 +180,8 @@ static void ibus_engine_set_surrounding_text static void ibus_engine_process_hand_writing_event (IBusEngine *engine, const gdouble *coordinates, - guint coordinates_len); + guint + coordinates_len); static void ibus_engine_cancel_hand_writing (IBusEngine *engine, guint n_strokes); @@ -230,7 +241,15 @@ static const gchar introspection_xml[] = " " " " " " + " " + " " + " " + " " + " " " " + " " + " " + " " " " " " " " @@ -283,6 +302,7 @@ static const gchar introspection_xml[] = " " /* FIXME properties */ " " + " " " " ""; @@ -324,7 +344,9 @@ ibus_engine_class_init (IBusEngineClass *class) class->process_key_event = ibus_engine_process_key_event; class->focus_in = ibus_engine_focus_in; + class->focus_in_id = ibus_engine_focus_in_id; class->focus_out = ibus_engine_focus_out; + class->focus_out_id = ibus_engine_focus_out_id; class->reset = ibus_engine_reset; class->enable = ibus_engine_enable; class->disable = ibus_engine_disable; @@ -360,6 +382,15 @@ ibus_engine_class_init (IBusEngineClass *class) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_HAS_FOCUS_ID, + g_param_spec_boolean ("has-focus-id", + "has focus id", + "Has focus ID", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + /* install signals */ /** * IBusEngine::process-key-event: @@ -378,7 +409,8 @@ ibus_engine_class_init (IBusEngineClass *class) * Returns: %TRUE for successfully process the key; %FALSE otherwise. * See also: ibus_input_context_process_key_event(). * - * Argument @user_data is ignored in this function. + * Argument @user_data is ignored in this function. + * */ engine_signals[PROCESS_KEY_EVENT] = g_signal_new (I_("process-key-event"), @@ -402,7 +434,8 @@ ibus_engine_class_init (IBusEngineClass *class) * in extended class to receive this signal. * * See also: ibus_input_context_focus_in() - * Argument @user_data is ignored in this function. + * Argument @user_data is ignored in this function. + * */ engine_signals[FOCUS_IN] = g_signal_new (I_("focus-in"), @@ -414,6 +447,58 @@ ibus_engine_class_init (IBusEngineClass *class) G_TYPE_NONE, 0); + /** + * IBusEngine::focus-in-id: + * @engine: An IBusEngine. + * @object_path: An object path. + * @client: An client name. + * + * Emitted when the client application get the focus. + * Implement the member function IBusEngineClass::focus_in + * in extended class to receive this signal. + * @object_path is a unique id by input context. + * @client indicates a client type: + * 'fake': focus is on desktop background or other programs where no + * input is possible + * 'xim': old X11 programs like xterm, emacs, ... + * GTK3 programs in a Gnome Xorg session when GTK_IM_MODULE + * is unset also use xim + * 'gtk-im:<client-name>': Gtk2 input module is used + * 'gtk3-im:<client-name>': Gtk3 input module is used + * 'gtk4-im:<client-name>': Gtk4 input module is used + * In case of the Gtk input modules, the name of the + * client is also shown after the “:”, for example + * like 'gtk3-im:firefox', 'gtk4-im:gnome-text-editor', … + * 'gnome-shell': Entries handled by gnome-shell + * (like the command line dialog opened with Alt+F2 + * or the search field when pressing the Super key.) + * When GTK_IM_MODULE is unset in a Gnome Wayland session + * all programs which would show 'gtk3-im' or 'gtk4-im' + * with GTK_IM_MODULE=ibus then show 'gnome-shell' + * instead. + * 'Qt': Qt4 programs like keepassx-2.0.3 … + * 'QIBusInputContext': Qt5 programs like keepassxc-2.7.1, anki-2.1.15 + * telegram-desktop-3.7.3, + * + * You need to set #IBusEngine::has-focus-id property to %TRUE when you + * construct an #IBusEngine to use this class method. + * + * See also: ibus_input_context_focus_in() + * Argument @user_data is ignored in this function. + * + */ + engine_signals[FOCUS_IN_ID] = + g_signal_new (I_("focus-in-id"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (IBusEngineClass, focus_in_id), + NULL, NULL, + _ibus_marshal_VOID__STRING_STRING, + G_TYPE_NONE, + 2, + G_TYPE_STRING, + G_TYPE_STRING); + /** * IBusEngine::focus-out: * @engine: An IBusEngine. @@ -423,7 +508,8 @@ ibus_engine_class_init (IBusEngineClass *class) * in extended class to receive this signal. * * See also: ibus_input_context_focus_out() - * Argument @user_data is ignored in this function. + * Argument @user_data is ignored in this function. + * */ engine_signals[FOCUS_OUT] = g_signal_new (I_("focus-out"), @@ -435,6 +521,33 @@ ibus_engine_class_init (IBusEngineClass *class) G_TYPE_NONE, 0); + /** + * IBusEngine::focus-out-id: + * @engine: An IBusEngine. + * @object_path: An object path. + * + * Emitted when the client application lost the focus. + * Implement the member function IBusEngineClass::focus_out + * in extended class to receive this signal. + * @object_path is a unique id by input context. + * You need to set #IBusEngine::has-focus-id property to %TRUE when you + * construct an #IBusEngine to use this class method. + * + * See also: ibus_input_context_focus_out() + * Argument @user_data is ignored in this function. + * + */ + engine_signals[FOCUS_OUT_ID] = + g_signal_new (I_("focus-out-id"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (IBusEngineClass, focus_out_id), + NULL, NULL, + _ibus_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + /** * IBusEngine::reset: * @engine: An IBusEngine. @@ -872,6 +985,9 @@ ibus_engine_set_property (IBusEngine *engine, case PROP_ENGINE_NAME: engine->priv->engine_name = g_value_dup_string (value); break; + case PROP_HAS_FOCUS_ID: + engine->priv->has_focus_id = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec); } @@ -887,7 +1003,9 @@ ibus_engine_get_property (IBusEngine *engine, case PROP_ENGINE_NAME: g_value_set_string (value, engine->priv->engine_name); break; - + case PROP_HAS_FOCUS_ID: + g_value_set_boolean (value, engine->priv->has_focus_id); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec); } @@ -1176,6 +1294,30 @@ ibus_engine_service_method_call (IBusService *service, } } + if (g_strcmp0 (method_name, "FocusInId") == 0) { + gchar *object_path = NULL; + gchar *client = NULL; + g_variant_get (parameters, "(&s&s)", &object_path, &client); + g_signal_emit (engine, + engine_signals[FOCUS_IN_ID], + 0, + object_path, + client); + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + + if (g_strcmp0 (method_name, "FocusOutId") == 0) { + gchar *object_path = NULL; + g_variant_get (parameters, "(&s)", &object_path); + g_signal_emit (engine, + engine_signals[FOCUS_OUT_ID], + 0, + object_path); + g_dbus_method_invocation_return_value (invocation, NULL); + return; + } + if (g_strcmp0 (method_name, "CandidateClicked") == 0) { guint index, button, state; g_variant_get (parameters, "(uuu)", &index, &button, &state); @@ -1303,6 +1445,23 @@ ibus_engine_service_method_call (IBusService *service, g_return_if_reached (); } +/** + * _ibus_engine_has_focus_id: + * + * Implement the "FocusId" method call of the org.freedesktop.IBus interface. + */ +static GVariant * +_ibus_engine_has_focus_id (IBusEngine *engine, + GDBusConnection *connection, + GError **error) +{ + if (error) { + *error = NULL; + } + + return g_variant_new_boolean (engine->priv->has_focus_id); +} + static GVariant * ibus_engine_service_get_property (IBusService *service, GDBusConnection *connection, @@ -1312,7 +1471,18 @@ ibus_engine_service_get_property (IBusService *service, const gchar *property_name, GError **error) { - return IBUS_SERVICE_CLASS (ibus_engine_parent_class)-> + int i; + static const struct { + const gchar *method_name; + GVariant * (* method_callback) (IBusEngine *, + GDBusConnection *, + GError **); + } methods [] = { + { "FocusId", _ibus_engine_has_focus_id }, + }; + + if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) { + return IBUS_SERVICE_CLASS (ibus_engine_parent_class)-> service_get_property (service, connection, sender, @@ -1320,6 +1490,19 @@ ibus_engine_service_get_property (IBusService *service, interface_name, property_name, error); + } + + for (i = 0; i < G_N_ELEMENTS (methods); i++) { + if (g_strcmp0 (methods[i].method_name, property_name) == 0) { + return methods[i].method_callback ((IBusEngine *) service, + connection, + error); + } + } + + g_warning ("service_get_property received an unknown property: %s", + property_name ? property_name : "(null)"); + return NULL; } static gboolean @@ -1386,31 +1569,39 @@ ibus_engine_process_key_event (IBusEngine *engine, static void ibus_engine_focus_in (IBusEngine *engine) { - // g_debug ("focus-in"); +} + +static void +ibus_engine_focus_in_id (IBusEngine *engine, + const gchar *object_path, + const gchar *client) +{ } static void ibus_engine_focus_out (IBusEngine *engine) { - // g_debug ("focus-out"); +} + +static void +ibus_engine_focus_out_id (IBusEngine *engine, + const gchar *object_path) +{ } static void ibus_engine_reset (IBusEngine *engine) { - // g_debug ("reset"); } static void ibus_engine_enable (IBusEngine *engine) { - // g_debug ("enable"); } static void ibus_engine_disable (IBusEngine *engine) { - // g_debug ("disable"); } static void diff --git a/src/ibusengine.h b/src/ibusengine.h index 43eaa554..6af0e856 100644 --- a/src/ibusengine.h +++ b/src/ibusengine.h @@ -2,7 +2,8 @@ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2013 Peng Huang - * Copyright (C) 2008-2013 Red Hat, Inc. + * Copyright (C) 2012-2022 Takao Fujiwara + * 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 @@ -153,10 +154,15 @@ struct _IBusEngineClass { (IBusEngine *engine, guint purpose, guint hints); + void (* focus_in_id) (IBusEngine *engine, + const gchar *object_path, + const gchar *client); + void (* focus_out_id) (IBusEngine *engine, + const gchar *object_path); /*< private >*/ /* padding */ - gpointer pdummy[4]; + gpointer pdummy[2]; }; GType ibus_engine_get_type (void); diff --git a/src/ibusmarshalers.list b/src/ibusmarshalers.list index aa9ea82a..7489f842 100644 --- a/src/ibusmarshalers.list +++ b/src/ibusmarshalers.list @@ -19,6 +19,7 @@ VOID:OBJECT,UINT,UINT VOID:OBJECT,BOOLEAN VOID:BOXED,BOOLEAN VOID:BOXED +VOID:STRING,STRING VOID:STRING,STRING,VARIANT VOID:STRING,STRING,STRING VOID:UINT -- 2.35.3 From 59c13597918db98ec8120ccdac09f1e2dc576e1b Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Thu, 7 Jul 2022 08:22:48 +0900 Subject: [PATCH] src/tests: Unset G_MESSAGES_DEBUG for gsettings in xkb-latin-layouts gsettings cannot get the key value when G_MESSAGES_DEBUG is enabled. Add denylist.txt to engine/Makefile.am --- engine/Makefile.am | 3 ++- src/tests/xkb-latin-layouts | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/engine/Makefile.am b/engine/Makefile.am index 03867f52..7256fbc8 100644 --- a/engine/Makefile.am +++ b/engine/Makefile.am @@ -4,7 +4,7 @@ # # Copyright (c) 2010-2016, Google Inc. All rights reserved. # Copyright (c) 2007-2016 Peng Huang -# Copyright (c) 2013-2020 Takao Fujiwara +# Copyright (c) 2013-2021 Takao Fujiwara # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -88,6 +88,7 @@ CLEANFILES = \ $(NULL) EXTRA_DIST = \ + denylist.txt \ gensimple.py \ iso639converter.py \ simple.xml.in \ diff --git a/src/tests/xkb-latin-layouts b/src/tests/xkb-latin-layouts index f8dced6b..92464234 100755 --- a/src/tests/xkb-latin-layouts +++ b/src/tests/xkb-latin-layouts @@ -82,9 +82,16 @@ finit() test_xkb_keymaps() { + # G_MESSAGES_DEBUG=all or G_MESSAGES_DEBUG=GLib-GIO-DEBUG would append + # debug messages to gsettings output and could not get the result correctly. + backup_G_MESSAGES_DEBUG="$G_MESSAGES_DEBUG" + unset G_MESSAGES_DEBUG # Loop over top level schemas since "gsettings list-recursively" only # looks for direct children. xkb_latin_layouts=`gsettings get org.freedesktop.ibus.general xkb-latin-layouts` + if [ x"$backup_G_MESSAGES_DEBUG" != x ] ; then + export G_MESSAGES_DEBUG=$backup_G_MESSAGES_DEBUG + fi while read keymap ; do eval keymap="$keymap" HAS_VARIANT=$($ECHO "$keymap" | grep '(' 2> /dev/null) ||: -- 2.35.3 From d47dbfada41aa4fb5df9f7cffe873786fc4849cc Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Mon, 25 Jul 2022 17:22:21 +0900 Subject: [PATCH] client/x11: Enhance Xutf8TextListToTextProperty XCompoundTextStyle depends on the current locale and some locales fail to to get the compound text style. If Xutf8TextListToTextProperty() fails, now ibus-x11 tries to get the compound text style with UTF-8 encoding. BUG=https://github.com/ibus/ibus/issues/2422 --- client/x11/main.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/client/x11/main.c b/client/x11/main.c index fe30c1d6..6057cc03 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 - * Copyright (C) 2015-2021 Takao Fujiwara + * Copyright (C) 2015-2022 Takao Fujiwara * Copyright (C) 2007-2015 Red Hat, Inc. * * main.c: @@ -48,6 +48,8 @@ #include +#define ESC_SEQUENCE_ISO10646_1 "\033%G" + #define LOG(level, fmt_args...) \ if (g_debug_level >= (level)) { \ g_debug (fmt_args); \ @@ -254,9 +256,17 @@ _xim_preedit_callback_draw (XIMS xims, X11IC *x11ic, const gchar *preedit_string text.feedback = feedback; if (len > 0) { - Xutf8TextListToTextProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), - (char **)&preedit_string, - 1, XCompoundTextStyle, &tp); + int ret = Xutf8TextListToTextProperty ( + GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), + (char **)&preedit_string, + 1, XCompoundTextStyle, &tp); + if (ret == EXIT_FAILURE) { + XFree (tp.value); + tp.value = (unsigned char *)g_strdup_printf ( + "%s%s", + ESC_SEQUENCE_ISO10646_1, + preedit_string); + } text.encoding_is_wchar = 0; text.length = strlen ((char*)tp.value); text.string.multi_byte = (char*)tp.value; @@ -883,9 +893,26 @@ _context_commit_text_cb (IBusInputContext *context, XTextProperty tp; IMCommitStruct cms = {0}; - - Xutf8TextListToTextProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), - (gchar **)&(text->text), 1, XCompoundTextStyle, &tp); + int ret; + + ret = Xutf8TextListToTextProperty ( + GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), + (gchar **)&(text->text), 1, XCompoundTextStyle, &tp); + /* XCompoundTextStyle uses the encoding escaped sequence + encoded chars + * matched to the specified multibyte characters: text->text, and + * libX11.so sorts the encoding sets by locale. + * If an encoded string fails to be matched, ibus-x11 specifies the + * ISO10641-1 encoding and that escaped sequence is "\033%G": + * https://gitlab.freedesktop.org/xorg/lib/libx11/-/blob/master/src/xlibi18n/lcCT.c + * , and the encoding is UTF-8 with utf8_wctomb(): + * https://gitlab.freedesktop.org/xorg/lib/libx11/-/blob/master/src/xlibi18n/lcUniConv/utf8.h + */ + if (ret == EXIT_FAILURE) { + XFree (tp.value); + tp.value = (unsigned char *)g_strdup_printf ("%s%s", + ESC_SEQUENCE_ISO10646_1, + text->text); + } cms.major_code = XIM_COMMIT; cms.icid = x11ic->icid; -- 2.35.3 From 53d8a826a62f2b43d7361f719fb72e26da8732f8 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Fri, 12 Aug 2022 11:41:16 +0900 Subject: [PATCH] data/dconf: Revert Emoji shoftcut key to Super-space IBus provides the D-Bus method to override IBus emoji UI and i think Super-period is better than Ctrl-period for the emoji shortcut key to compare MS-Window, Macintosh. IBus emoji UI connects to the input method and provides the language emoji annotations. Seems moving GTK Cotrol-period to gnome-shell Suer-period is difficult at present. BUG=https://github.com/ibus/ibus/issues/2390 BUG=https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5728 --- data/dconf/org.freedesktop.ibus.gschema.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/dconf/org.freedesktop.ibus.gschema.xml b/data/dconf/org.freedesktop.ibus.gschema.xml index 0ece2b4f..4d3b7ae2 100644 --- a/data/dconf/org.freedesktop.ibus.gschema.xml +++ b/data/dconf/org.freedesktop.ibus.gschema.xml @@ -248,7 +248,7 @@ The shortcut keys for turning Unicode typing on or off - [ '<Control>period', '<Control>semicolon' ] + [ '<Super>period' ] Emoji shortcut keys for gtk_accelerator_parse The shortcut keys for turning emoji typing on or off -- 2.37.1