/* vim:set et sts=4 sw=4: * * ibus - The Input Bus * * Copyright(c) 2013 Peng Huang * Copyright(c) 2015-2018 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 */ private const string IBUS_SCHEMAS_GENERAL = "org.freedesktop.ibus.general"; private const string IBUS_SCHEMAS_GENERAL_HOTKEY = "org.freedesktop.ibus.general.hotkey"; private const string IBUS_SCHEMAS_PANEL = "org.freedesktop.ibus.panel"; private const string IBUS_SCHEMAS_PANEL_EMOJI = "org.freedesktop.ibus.panel.emoji"; bool name_only = false; /* system() exists as a public API. */ bool is_system = false; string cache_file = null; string engine_id = null; class EngineList { public IBus.EngineDesc[] data = {}; } IBus.Bus? get_bus() { var bus = new IBus.Bus(); if (!bus.is_connected ()) return null; return bus; } int list_engine(string[] argv) { const OptionEntry[] options = { { "name-only", 0, 0, OptionArg.NONE, out name_only, N_("List engine name only"), null }, { null } }; var option = new OptionContext(); option.add_main_entries(options, Config.GETTEXT_PACKAGE); try { option.parse(ref argv); } catch (OptionError e) { stderr.printf("%s\n", e.message); return Posix.EXIT_FAILURE; } var bus = get_bus(); if (bus == null) { stderr.printf(_("Can't connect to IBus.\n")); return Posix.EXIT_FAILURE; } var engines = bus.list_engines(); if (name_only) { foreach (var engine in engines) { print("%s\n", engine.get_name()); } return Posix.EXIT_SUCCESS; } var map = new HashTable(GLib.str_hash, GLib.str_equal); foreach (var engine in engines) { var list = map.get(engine.get_language()); if (list == null) { list = new EngineList(); map.insert(engine.get_language(), list); } list.data += engine; } foreach (var language in map.get_keys()) { var list = map.get(language); print(_("language: %s\n"), IBus.get_language_name(language)); foreach (var engine in list.data) { print(" %s - %s\n", engine.get_name(), engine.get_longname()); } } return Posix.EXIT_SUCCESS; } private int exec_setxkbmap(IBus.EngineDesc engine) { string layout = engine.get_layout(); string variant = engine.get_layout_variant(); string option = engine.get_layout_option(); string standard_error = null; int exit_status = 0; string[] args = { "setxkbmap" }; if (layout != null && layout != "" && layout != "default") { args += "-layout"; args += layout; } if (variant != null && variant != "" && variant != "default") { args += "-variant"; args += variant; } if (option != null && option != "" && option != "default") { /*TODO: Need to get the session XKB options */ args += "-option"; args += "-option"; args += option; } if (args.length == 1) { return Posix.EXIT_FAILURE; } try { if (!GLib.Process.spawn_sync(null, args, null, GLib.SpawnFlags.SEARCH_PATH, null, null, out standard_error, out exit_status)) { warning("Switch xkb layout to %s failed.", engine.get_layout()); return Posix.EXIT_FAILURE; } } catch (GLib.SpawnError e) { warning("Execute setxkbmap failed: %s", e.message); return Posix.EXIT_FAILURE; } if (exit_status != 0) { warning("Execute setxkbmap failed: %s", standard_error ?? "(null)"); return Posix.EXIT_FAILURE; } return Posix.EXIT_SUCCESS; } int get_set_engine(string[] argv) { var bus = get_bus(); string engine = null; if (argv.length > 1) engine = argv[1]; if (engine == null) { var desc = bus.get_global_engine(); if (desc == null) { stderr.printf(_("No engine is set.\n")); return Posix.EXIT_FAILURE; } print("%s\n", desc.get_name()); return Posix.EXIT_SUCCESS; } if(!bus.set_global_engine(engine)) { stderr.printf(_("Set global engine failed.\n")); return Posix.EXIT_FAILURE; } var desc = bus.get_global_engine(); if (desc == null) { stderr.printf(_("Get global engine failed.\n")); return Posix.EXIT_FAILURE; } var settings = new GLib.Settings(IBUS_SCHEMAS_GENERAL); if (!settings.get_boolean("use-system-keyboard-layout")) return exec_setxkbmap(desc); 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")); return Posix.EXIT_FAILURE; } bus.exit(true); return Posix.EXIT_SUCCESS; } int exit_daemon(string[] argv) { var bus = get_bus(); if (bus == null) { stderr.printf(_("Can't connect to IBus.\n")); return Posix.EXIT_FAILURE; } bus.exit(false); 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, N_("Read the system registry cache."), null }, { "file", 0, 0, OptionArg.STRING, out cache_file, N_("Read the registry cache FILE."), "FILE" }, { null } }; var option = new OptionContext(); option.add_main_entries(options, Config.GETTEXT_PACKAGE); try { option.parse(ref argv); } catch (OptionError e) { stderr.printf("%s\n", e.message); return Posix.EXIT_FAILURE; } var registry = new IBus.Registry(); if (cache_file != null) { if (!registry.load_cache_file(cache_file)) { stderr.printf(_("The registry cache is invalid.\n")); return Posix.EXIT_FAILURE; } } else { if (!registry.load_cache(!is_system)) { stderr.printf(_("The registry cache is invalid.\n")); return Posix.EXIT_FAILURE; } } var output = new GLib.StringBuilder(); registry.output(output, 1); print ("%s\n", output.str); return Posix.EXIT_SUCCESS; } int write_cache (string[] argv) { const OptionEntry[] options = { { "system", 0, 0, OptionArg.NONE, out is_system, N_("Write the system registry cache."), null }, { "file", 0, 0, OptionArg.STRING, out cache_file, N_("Write the registry cache FILE."), "FILE" }, { null } }; var option = new OptionContext(); option.add_main_entries(options, Config.GETTEXT_PACKAGE); try { option.parse(ref argv); } catch (OptionError e) { stderr.printf("%s\n", e.message); return Posix.EXIT_FAILURE; } var registry = new IBus.Registry(); registry.load(); if (cache_file != null) { return registry.save_cache_file(cache_file) ? Posix.EXIT_SUCCESS : Posix.EXIT_FAILURE; } return registry.save_cache(!is_system) ? 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, N_("Use engine schema paths instead of ibus core, " + "which can be comma-separated values."), "ENGINE_ID" }, { null } }; var option = new OptionContext(); option.add_main_entries(options, Config.GETTEXT_PACKAGE); try { option.parse(ref argv); } catch (OptionError e) { stderr.printf("%s\n", e.message); return Posix.EXIT_FAILURE; } return Posix.EXIT_SUCCESS; } private GLib.SList get_ibus_schemas() { string[] ids = {}; if (engine_id != null) { ids = engine_id.split(","); } GLib.SList ibus_schemas = new GLib.SList(); GLib.SettingsSchemaSource schema_source = GLib.SettingsSchemaSource.get_default(); string[] list_schemas = {}; schema_source.list_schemas(true, out list_schemas, null); foreach (string schema in list_schemas) { if (ids.length != 0) { foreach (unowned string id in ids) { if (id == schema || schema.has_prefix("org.freedesktop.ibus.engine." + id)) { ibus_schemas.prepend(schema); break; } } } else if (schema.has_prefix("org.freedesktop.ibus") && !schema.has_prefix("org.freedesktop.ibus.engine")) { ibus_schemas.prepend(schema); } } if (ibus_schemas.length() == 0) { printerr("Not found schemas of \"org.freedesktop.ibus\"\n"); return ibus_schemas; } ibus_schemas.sort(GLib.strcmp); return ibus_schemas; } int read_config(string[] argv) { if (read_config_options(argv) == Posix.EXIT_FAILURE) return Posix.EXIT_FAILURE; GLib.SList ibus_schemas = get_ibus_schemas(); if (ibus_schemas.length() == 0) return Posix.EXIT_FAILURE; GLib.SettingsSchemaSource schema_source = GLib.SettingsSchemaSource.get_default(); var output = new GLib.StringBuilder(); foreach (string schema in ibus_schemas) { GLib.SettingsSchema settings_schema = schema_source.lookup(schema, false); GLib.Settings settings = new GLib.Settings(schema); output.append_printf("SCHEMA: %s\n", schema); foreach (string key in settings_schema.list_keys()) { GLib.Variant variant = settings.get_value(key); output.append_printf(" %s: %s\n", key, variant.print(true)); } } print("%s", output.str); return Posix.EXIT_SUCCESS; } int reset_config(string[] argv) { if (read_config_options(argv) == Posix.EXIT_FAILURE) return Posix.EXIT_FAILURE; GLib.SList ibus_schemas = get_ibus_schemas(); if (ibus_schemas.length() == 0) return Posix.EXIT_FAILURE; print("%s\n", _("Resetting…")); GLib.SettingsSchemaSource schema_source = GLib.SettingsSchemaSource.get_default(); foreach (string schema in ibus_schemas) { GLib.SettingsSchema settings_schema = schema_source.lookup(schema, false); GLib.Settings settings = new GLib.Settings(schema); print("SCHEMA: %s\n", schema); foreach (string key in settings_schema.list_keys()) { print(" %s\n", key); settings.reset(key); } } GLib.Settings.sync(); print("%s\n", _("Done")); return Posix.EXIT_SUCCESS; } #if EMOJI_DICT int emoji_dialog(string[] argv) { string cmd = Config.LIBEXECDIR + "/ibus-ui-emojier"; var file = File.new_for_path(cmd); if (!file.query_exists()) cmd = "../ui/gtk3/ibus-ui-emojier"; argv[0] = cmd; string[] env = Environ.get(); try { // Non-blocking Process.spawn_async(null, argv, env, SpawnFlags.SEARCH_PATH, null, null); } catch (SpawnError e) { stderr.printf("%s\n", e.message); return Posix.EXIT_FAILURE; } return Posix.EXIT_SUCCESS; } #endif int print_help(string[] argv) { print_usage(stdout); return Posix.EXIT_SUCCESS; } delegate int EntryFunc(string[] argv); struct CommandEntry { unowned string name; unowned string description; 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 }, { "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 }, { "address", N_("Print the D-Bus address of ibus-daemon"), print_address }, { "read-config", N_("Show the configuration values"), read_config }, { "reset-config", N_("Reset the configuration values"), reset_config }, #if EMOJI_DICT { "emoji", N_("Save emoji on dialog to clipboard "), emoji_dialog }, #endif { "help", N_("Show this information"), print_help } }; static string program_name; void print_usage(FileStream stream) { stream.printf(_("Usage: %s COMMAND [OPTION...]\n\n"), program_name); stream.printf(_("Commands:\n")); for (int i = 0; i < commands.length; i++) { stream.printf(" %-12s %s\n", commands[i].name, GLib.dgettext(null, commands[i].description)); } } public int main(string[] argv) { GLib.Intl.setlocale(GLib.LocaleCategory.ALL, ""); GLib.Intl.bindtextdomain(Config.GETTEXT_PACKAGE, Config.GLIB_LOCALE_DIR); GLib.Intl.bind_textdomain_codeset(Config.GETTEXT_PACKAGE, "UTF-8"); GLib.Intl.textdomain(Config.GETTEXT_PACKAGE); IBus.init(); program_name = Path.get_basename(argv[0]); if (argv.length < 2) { print_usage(stderr); return Posix.EXIT_FAILURE; } string[] new_argv = argv[1:argv.length]; new_argv[0] = "%s %s".printf(program_name, new_argv[0]); for (int i = 0; i < commands.length; i++) { if (commands[i].name == argv[1]) return commands[i].entry(new_argv); } stderr.printf(_("%s is unknown command!\n"), argv[1]); print_usage(stderr); return Posix.EXIT_FAILURE; }