diff options
author | fujiwarat <takao.fujiwara1@gmail.com> | 2022-07-19 22:58:09 +0900 |
---|---|---|
committer | fujiwarat <takao.fujiwara1@gmail.com> | 2022-07-19 22:58:09 +0900 |
commit | ab0d176477b17b1981879005846aaedc588f79cc (patch) | |
tree | 7b4fa88e4804ae86f29ed2ac2247cdc1bbfc4f28 | |
parent | 79e446ec99691d62ec2110c728e69da4c889eee2 (diff) | |
download | ibus-ab0d176477b17b1981879005846aaedc588f79cc.tar.gz |
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
-rw-r--r-- | po/ibus10.pot | 80 | ||||
-rw-r--r-- | tools/Makefile.am | 3 | ||||
-rw-r--r-- | tools/ibus.1.in | 30 | ||||
-rw-r--r-- | tools/main.vala | 261 |
4 files changed, 330 insertions, 44 deletions
diff --git a/po/ibus10.pot b/po/ibus10.pot index 3f9843dd..09c09be7 100644 --- a/po/ibus10.pot +++ b/po/ibus10.pot @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: ibus 1.5.26\n" "Report-Msgid-Bugs-To: https://github.com/ibus/ibus/issues\n" -"POT-Creation-Date: 2022-06-20 20:30+0900\n" -"PO-Revision-Date: 2022-06-20 20:30+0900\n" +"POT-Creation-Date: 2022-07-06 22:08+0900\n" +"PO-Revision-Date: 2022-07-06 22:08+0900\n" "Last-Translator: Takao Fujiwara <takao.fujiwara1@gmail.com>\n" "Language-Team: Source\n" "Language: \n" @@ -3099,129 +3099,145 @@ msgstr "" msgid "Supplementary Private Use Area-B" msgstr "" -#: tools/main.vala:51 +#: tools/main.vala:182 msgid "List engine name only" msgstr "" -#: tools/main.vala:67 tools/main.vala:192 tools/main.vala:202 +#: tools/main.vala:198 tools/main.vala:395 tools/main.vala:437 msgid "Can't connect to IBus.\n" msgstr "" -#: tools/main.vala:93 +#: tools/main.vala:224 #, c-format msgid "language: %s\n" msgstr "" -#: tools/main.vala:161 +#: tools/main.vala:294 msgid "No engine is set.\n" msgstr "" -#: tools/main.vala:169 +#: tools/main.vala:302 msgid "Set global engine failed.\n" msgstr "" -#: tools/main.vala:174 +#: tools/main.vala:307 msgid "Get global engine failed.\n" msgstr "" -#: tools/main.vala:217 +#: tools/main.vala:328 +msgid "Start or restart daemon with \"direct\" or \"systemd\" TYPE." +msgstr "" + +#: tools/main.vala:331 +msgid "Start or restart daemon with SYSTEMD_SERVICE file." +msgstr "" + +#: tools/main.vala:334 +msgid "Show debug messages." +msgstr "" + +#: tools/main.vala:454 msgid "Read the system registry cache." msgstr "" -#: tools/main.vala:219 +#: tools/main.vala:456 msgid "Read the registry cache FILE." msgstr "" -#: tools/main.vala:237 tools/main.vala:242 +#: tools/main.vala:474 tools/main.vala:479 msgid "The registry cache is invalid.\n" msgstr "" -#: tools/main.vala:257 +#: tools/main.vala:495 msgid "Write the system registry cache." msgstr "" -#: tools/main.vala:259 +#: tools/main.vala:497 msgid "Write the registry cache FILE." msgstr "" -#: tools/main.vala:295 +#: tools/main.vala:535 msgid "" "Use engine schema paths instead of ibus core, which can be comma-separated " "values." msgstr "" -#: tools/main.vala:381 +#: tools/main.vala:624 msgid "Resetting…" msgstr "" -#: tools/main.vala:399 +#: tools/main.vala:642 msgid "Done" msgstr "" -#: tools/main.vala:444 +#: tools/main.vala:691 msgid "Set or get engine" msgstr "" -#: tools/main.vala:445 +#: tools/main.vala:692 msgid "Exit ibus-daemon" msgstr "" -#: tools/main.vala:446 +#: tools/main.vala:693 msgid "Show available engines" msgstr "" -#: tools/main.vala:447 +#: tools/main.vala:694 msgid "(Not implemented)" msgstr "" -#: tools/main.vala:448 +#: tools/main.vala:695 msgid "Restart ibus-daemon" msgstr "" -#: tools/main.vala:449 +#: tools/main.vala:696 +msgid "Start ibus-daemon" +msgstr "" + +#: tools/main.vala:697 msgid "Show version" msgstr "" -#: tools/main.vala:450 +#: tools/main.vala:698 msgid "Show the content of registry cache" msgstr "" -#: tools/main.vala:451 +#: tools/main.vala:699 msgid "Create registry cache" msgstr "" -#: tools/main.vala:452 +#: tools/main.vala:700 msgid "Print the D-Bus address of ibus-daemon" msgstr "" -#: tools/main.vala:453 +#: tools/main.vala:701 msgid "Show the configuration values" msgstr "" -#: tools/main.vala:454 +#: tools/main.vala:702 msgid "Reset the configuration values" msgstr "" -#: tools/main.vala:456 +#: tools/main.vala:704 msgid "Save emoji on dialog to clipboard" msgstr "" -#: tools/main.vala:458 +#: tools/main.vala:706 msgid "Show this information" msgstr "" -#: tools/main.vala:464 +#: tools/main.vala:713 #, c-format msgid "" "Usage: %s COMMAND [OPTION...]\n" "\n" msgstr "" -#: tools/main.vala:465 +#: tools/main.vala:714 msgid "Commands:\n" msgstr "" -#: tools/main.vala:494 +#: tools/main.vala:744 #, c-format msgid "%s is unknown command!\n" msgstr "" 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 <shawn.p.huang@gmail.com> -# Copyright (c) 2015-2017 Takao Fujiwara <takao.fujiwara1@gmail.com> +# Copyright (c) 2015-2022 Takao Fujiwara <takao.fujiwara1@gmail.com> # 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 <takao.fujiwara1@gmail.com>, 2013-2017. .\" Copyright (c) Peng Huang <shawn.p.huang@gmail.com>, 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 <shawn.p.huang@gmail.com> - * Copyright(c) 2015-2020 Takao Fujiwara <takao.fujiwara1@gmail.com> + * Copyright(c) 2015-2022 Takao Fujiwara <takao.fujiwara1@gmail.com> * * 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<string> get_ibus_schemas() { string[] ids = {}; if (engine_id != null) { @@ -342,6 +582,7 @@ private GLib.SList<string> 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); |