| // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <assert.h> |
| #include <glib.h> |
| #include <ibus.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string> |
| |
| namespace { |
| |
| const gchar kDummySection[] = "aaa/bbb"; |
| const gchar kDummyConfigName[] = "ccc"; |
| |
| const gboolean kDummyValueBoolean = TRUE; |
| const gint kDummyValueInt = 12345; |
| const gdouble kDummyValueDouble = 2345.5432; |
| const gchar kDummyValueString[] = "dummy value"; |
| |
| const size_t kArraySize = 3; |
| const gboolean kDummyValueBooleanArray[kArraySize] = { FALSE, TRUE, FALSE }; |
| const gint kDummyValueIntArray[kArraySize] = { 123, 234, 345 }; |
| const gdouble kDummyValueDoubleArray[kArraySize] = { 111.22, 333.44, 555.66 }; |
| const gchar* kDummyValueStringArray[kArraySize] = { |
| "DUMMY_VALUE 1", "DUMMY_VALUE 2", "DUMMY_VALUE 3", |
| }; |
| |
| const char kGeneralSectionName[] = "general"; |
| const char kPreloadEnginesConfigName[] = "preload_engines"; |
| |
| // Converts |list_type_string| into its element type (e.g. "int_list" to "int"). |
| std::string GetElementType(const std::string& list_type_string) { |
| const std::string suffix = "_list"; |
| if (list_type_string.length() > suffix.length()) { |
| return list_type_string.substr( |
| 0, list_type_string.length() - suffix.length()); |
| } |
| return list_type_string; |
| } |
| |
| // Converts |type_string| into GVariantClass. |
| GVariantClass GetGVariantClassFromStringOrDie(const std::string& type_string) { |
| if (type_string == "boolean") { |
| return G_VARIANT_CLASS_BOOLEAN; |
| } else if (type_string == "int") { |
| return G_VARIANT_CLASS_INT32; |
| } else if (type_string == "double") { |
| return G_VARIANT_CLASS_DOUBLE; |
| } else if (type_string == "string") { |
| return G_VARIANT_CLASS_STRING; |
| } else if (GetElementType(type_string) != type_string) { |
| return G_VARIANT_CLASS_ARRAY; |
| } |
| printf("FAIL (unknown type: %s)\n", type_string.c_str()); |
| abort(); |
| } |
| |
| // Unsets a dummy value from ibus config service. |
| void UnsetConfigAndPrintResult(IBusConfig* ibus_config) { |
| if (ibus_config_unset(ibus_config, kDummySection, kDummyConfigName)) { |
| printf("OK\n"); |
| } else { |
| printf("FAIL\n"); |
| } |
| } |
| |
| // Sets a dummy value to ibus config service. You can specify a type of the |
| // dummy value by |type_string|. "boolean", "int", "double", or "string" are |
| // allowed. |
| void SetConfigAndPrintResult( |
| IBusConfig* ibus_config, const std::string& type_string) { |
| GVariant* variant = NULL; |
| GVariantClass klass = GetGVariantClassFromStringOrDie(type_string); |
| |
| switch (klass) { |
| case G_VARIANT_CLASS_BOOLEAN: |
| variant = g_variant_new_boolean(kDummyValueBoolean); |
| break; |
| case G_VARIANT_CLASS_INT32: |
| variant = g_variant_new_int32(kDummyValueInt); |
| break; |
| case G_VARIANT_CLASS_DOUBLE: |
| variant = g_variant_new_double(kDummyValueDouble); |
| break; |
| case G_VARIANT_CLASS_STRING: |
| variant = g_variant_new_string(kDummyValueString); |
| break; |
| case G_VARIANT_CLASS_ARRAY: { |
| const GVariantClass element_klass |
| = GetGVariantClassFromStringOrDie(GetElementType(type_string)); |
| g_assert(element_klass != G_VARIANT_CLASS_ARRAY); |
| |
| GVariantBuilder variant_builder; |
| for (size_t i = 0; i < kArraySize; ++i) { |
| switch (element_klass) { |
| case G_VARIANT_CLASS_BOOLEAN: |
| if (i == 0) { |
| g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("ab")); |
| } |
| g_variant_builder_add( |
| &variant_builder, "b", kDummyValueBooleanArray[i]); |
| break; |
| case G_VARIANT_CLASS_INT32: |
| if (i == 0) { |
| g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("ai")); |
| } |
| g_variant_builder_add( |
| &variant_builder, "i", kDummyValueIntArray[i]); |
| break; |
| case G_VARIANT_CLASS_DOUBLE: |
| if (i == 0) { |
| g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("ad")); |
| } |
| g_variant_builder_add( |
| &variant_builder, "d", kDummyValueDoubleArray[i]); |
| break; |
| case G_VARIANT_CLASS_STRING: |
| if (i == 0) { |
| g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("as")); |
| } |
| g_variant_builder_add( |
| &variant_builder, "s", kDummyValueStringArray[i]); |
| break; |
| default: |
| printf("FAIL\n"); |
| return; |
| } |
| } |
| variant = g_variant_builder_end(&variant_builder); |
| break; |
| } |
| default: |
| printf("FAIL\n"); |
| return; |
| } |
| if (!variant) { |
| printf("FAIL\n"); |
| return; |
| } |
| if (ibus_config_set_value( |
| ibus_config, kDummySection, kDummyConfigName, variant)) { |
| printf("OK\n"); |
| return; |
| } |
| printf("FAIL\n"); |
| } |
| |
| // Gets a dummy value from ibus config service. This function checks if the |
| // dummy value is |type_string| type. |
| void GetConfigAndPrintResult( |
| IBusConfig* ibus_config, const std::string& type_string) { |
| GVariant* variant = ibus_config_get_value( |
| ibus_config, kDummySection, kDummyConfigName); |
| if (!variant) { |
| printf("FAIL (not found)\n"); |
| return; |
| } |
| switch(g_variant_classify(variant)) { |
| case G_VARIANT_CLASS_BOOLEAN: { |
| if (g_variant_get_boolean(variant) != kDummyValueBoolean) { |
| printf("FAIL (value mismatch)\n"); |
| return; |
| } |
| break; |
| } |
| case G_VARIANT_CLASS_INT32: { |
| if (g_variant_get_int32(variant) != kDummyValueInt) { |
| printf("FAIL (value mismatch)\n"); |
| return; |
| } |
| break; |
| } |
| case G_VARIANT_CLASS_DOUBLE: { |
| if (g_variant_get_double(variant) != kDummyValueDouble) { |
| printf("FAIL (value mismatch)\n"); |
| return; |
| } |
| break; |
| } |
| case G_VARIANT_CLASS_STRING: { |
| const char* value = g_variant_get_string(variant, NULL); |
| if (value == NULL || |
| value != std::string(kDummyValueString)) { |
| printf("FAIL (value mismatch)\n"); |
| return; |
| } |
| break; |
| } |
| case G_VARIANT_CLASS_ARRAY: { |
| const GVariantType* variant_element_type |
| = g_variant_type_element(g_variant_get_type(variant)); |
| GVariantIter iter; |
| g_variant_iter_init(&iter, variant); |
| |
| size_t i; |
| GVariant* element = g_variant_iter_next_value(&iter); |
| for (i = 0; element; ++i) { |
| bool match = false; |
| if (g_variant_type_equal( |
| variant_element_type, G_VARIANT_TYPE_BOOLEAN)) { |
| const gboolean value = g_variant_get_boolean(element); |
| match = (value == kDummyValueBooleanArray[i]); |
| } else if (g_variant_type_equal( |
| variant_element_type, G_VARIANT_TYPE_INT32)) { |
| const gint32 value = g_variant_get_int32(element); |
| match = (value == kDummyValueIntArray[i]); |
| } else if (g_variant_type_equal( |
| variant_element_type, G_VARIANT_TYPE_DOUBLE)) { |
| const gdouble value = g_variant_get_double(element); |
| match = (value == kDummyValueDoubleArray[i]); |
| } else if (g_variant_type_equal( |
| variant_element_type, G_VARIANT_TYPE_STRING)) { |
| const char* value = g_variant_get_string(element, NULL); |
| match = (value && (value == std::string(kDummyValueStringArray[i]))); |
| } else { |
| printf("FAIL (list type mismatch)\n"); |
| return; |
| } |
| if (!match) { |
| printf("FAIL (value mismatch)\n"); |
| return; |
| } |
| g_variant_unref(element); |
| element = g_variant_iter_next_value(&iter); |
| } |
| if (i != kArraySize) { |
| printf("FAIL (invalid array)\n"); |
| return; |
| } |
| break; |
| } |
| default: |
| printf("FAIL (unknown type)\n"); |
| return; |
| } |
| printf("OK\n"); |
| } |
| |
| // Prints out the array. It is assumed that the array contains STRING values. |
| // On success, returns true |
| // On failure, prints out "FAIL (error message)" and returns false |
| bool PrintArray(GVariant* variant) { |
| if (g_variant_classify(variant) != G_VARIANT_CLASS_ARRAY) { |
| printf("FAIL (Not an array)\n"); |
| return false; |
| } |
| const GVariantType* variant_element_type |
| = g_variant_type_element(g_variant_get_type(variant)); |
| if (!g_variant_type_equal(variant_element_type, G_VARIANT_TYPE_STRING)) { |
| printf("FAIL (Array element type is not STRING)\n"); |
| return false; |
| } |
| GVariantIter iter; |
| g_variant_iter_init(&iter, variant); |
| GVariant* element = g_variant_iter_next_value(&iter); |
| while(element) { |
| const char* value = g_variant_get_string(element, NULL); |
| if (!value) { |
| printf("FAIL (Array element type is NULL)\n"); |
| return false; |
| } |
| printf("%s\n", value); |
| element = g_variant_iter_next_value(&iter); |
| } |
| return true; |
| } |
| |
| // Print out the list of unused config variables from ibus. |
| // On failure, prints out "FAIL (error message)" instead. |
| void PrintUnused(IBusConfig* ibus_config) { |
| GVariant* unread = NULL; |
| GVariant* unwritten = NULL; |
| if (!ibus_config_get_unused(ibus_config, &unread, &unwritten)) { |
| printf("FAIL (get_unused failed)\n"); |
| return; |
| } |
| |
| if (g_variant_classify(unread) != G_VARIANT_CLASS_ARRAY) { |
| printf("FAIL (unread is not an array)\n"); |
| g_variant_unref(unread); |
| g_variant_unref(unwritten); |
| return; |
| } |
| |
| if (g_variant_classify(unwritten) != G_VARIANT_CLASS_ARRAY) { |
| printf("FAIL (unwritten is not an array)\n"); |
| g_variant_unref(unread); |
| g_variant_unref(unwritten); |
| return; |
| } |
| |
| printf("Unread:\n"); |
| if (!PrintArray(unread)) { |
| g_variant_unref(unread); |
| g_variant_unref(unwritten); |
| return; |
| } |
| |
| printf("Unwritten:\n"); |
| if (!PrintArray(unwritten)) { |
| g_variant_unref(unread); |
| g_variant_unref(unwritten); |
| return; |
| } |
| |
| g_variant_unref(unread); |
| g_variant_unref(unwritten); |
| } |
| |
| // Set the preload engines to those named in the array |engines| of size |
| // |num_engines| and prints the result. |
| // |
| // Note that this only fails if it can't set the config value; it does not check |
| // that the names of the engines are valid. |
| void PreloadEnginesAndPrintResult(IBusConfig* ibus_config, int num_engines, |
| char** engines) { |
| GVariant* variant = NULL; |
| GVariantBuilder variant_builder; |
| g_variant_builder_init(&variant_builder, G_VARIANT_TYPE("as")); |
| for (int i = 0; i < num_engines; ++i) { |
| g_variant_builder_add(&variant_builder, "s", engines[i]); |
| } |
| variant = g_variant_builder_end(&variant_builder); |
| |
| if (ibus_config_set_value(ibus_config, kGeneralSectionName, |
| kPreloadEnginesConfigName, variant)) { |
| printf("OK\n"); |
| } else { |
| printf("FAIL\n"); |
| } |
| g_variant_unref(variant); |
| } |
| |
| // Sets |engine_name| as the active IME engine. |
| void ActivateEngineAndPrintResult(IBusBus* ibus, const char* engine_name) { |
| if (!ibus_bus_set_global_engine(ibus, engine_name)) { |
| printf("FAIL (could not start engine)\n"); |
| } else { |
| printf("OK\n"); |
| } |
| } |
| |
| // Prints the name of the active IME engine. |
| void PrintActiveEngine(IBusBus* ibus) { |
| IBusEngineDesc* engine_desc = ibus_bus_get_global_engine(ibus); |
| if (engine_desc) { |
| printf("%s\n", ibus_engine_desc_get_name(engine_desc)); |
| g_object_unref(engine_desc); |
| } else { |
| printf("FAIL (Could not get active engine)\n"); |
| } |
| } |
| |
| // Prints the names of the given engines. Takes the ownership of |engines|. |
| void PrintEngineNames(GList* engines) { |
| for (GList* cursor = engines; cursor; cursor = g_list_next(cursor)) { |
| IBusEngineDesc* engine_desc = IBUS_ENGINE_DESC(cursor->data); |
| assert(engine_desc); |
| printf("%s\n", ibus_engine_desc_get_name(engine_desc)); |
| g_object_unref(IBUS_ENGINE_DESC(cursor->data)); |
| } |
| g_list_free(engines); |
| } |
| |
| void PrintUsage(const char* argv0) { |
| printf("Usage: %s COMMAND\n", argv0); |
| printf("check_reachable Check if ibus-daemon is reachable\n"); |
| printf("list_engines List engine names (all engines)\n"); |
| printf("list_active_engines List active engine names\n"); |
| // TODO(yusukes): Add 2 parameters, config_key and config_value, to |
| // set_config and get_config commands. |
| printf("set_config (boolean|int|double|string|\n" |
| " boolean_list|int_list|double_list|string_list)\n" |
| " Set a dummy value to ibus config service\n"); |
| printf("get_config (boolean|int|double|string\n" |
| " boolean_list|int_list|double_list|string_list)\n" |
| " Get a dummy value from ibus config service\n"); |
| // TODO(yusukes): Add config_key parameter to unset_config. |
| printf("unset_config Unset a dummy value from ibus config service\n"); |
| printf("get_unused List all keys that never were used.\n"); |
| printf("preload_engines Preload the listed engines.\n"); |
| printf("activate_engine Activate the specified engine.\n"); |
| printf("get_active_engine Print the name of the current active engine.\n"); |
| } |
| |
| } // namespace |
| |
| int main(int argc, char **argv) { |
| if (argc == 1) { |
| PrintUsage(argv[0]); |
| return 1; |
| } |
| |
| ibus_init(); |
| bool connected = false; |
| IBusBus* ibus = ibus_bus_new(); |
| if (ibus) { |
| connected = ibus_bus_is_connected(ibus); |
| } |
| |
| const std::string command = argv[1]; |
| if (command == "check_reachable") { |
| printf("%s\n", connected ? "YES" : "NO"); |
| return 0; |
| } else if (!connected) { |
| printf("FAIL (Not connected)\n"); |
| return 0; |
| } |
| |
| // Other commands need the bus to be connected. |
| assert(ibus); |
| assert(connected); |
| GDBusConnection* ibus_connection = ibus_bus_get_connection(ibus); |
| assert(ibus_connection); |
| IBusConfig* ibus_config = ibus_config_new(ibus_connection, NULL, NULL); |
| assert(ibus_config); |
| |
| if (command == "list_engines") { |
| PrintEngineNames(ibus_bus_list_engines(ibus)); |
| } else if (command == "list_active_engines") { |
| PrintEngineNames(ibus_bus_list_active_engines(ibus)); |
| } else if (command == "set_config") { |
| if (argc != 3) { |
| PrintUsage(argv[0]); |
| return 1; |
| } |
| SetConfigAndPrintResult(ibus_config, argv[2]); |
| } else if (command == "get_config") { |
| if (argc != 3) { |
| PrintUsage(argv[0]); |
| return 1; |
| } |
| GetConfigAndPrintResult(ibus_config, argv[2]); |
| } else if (command == "unset_config") { |
| UnsetConfigAndPrintResult(ibus_config); |
| } else if (command == "get_unused") { |
| PrintUnused(ibus_config); |
| } else if (command == "preload_engines") { |
| if (argc < 3) { |
| PrintUsage(argv[0]); |
| return 1; |
| } |
| PreloadEnginesAndPrintResult(ibus_config, argc-2, &(argv[2])); |
| } else if (command == "activate_engine") { |
| if (argc != 3) { |
| PrintUsage(argv[0]); |
| return 1; |
| } |
| ActivateEngineAndPrintResult(ibus, argv[2]); |
| } else if (command == "get_active_engine") { |
| PrintActiveEngine(ibus); |
| } else { |
| PrintUsage(argv[0]); |
| return 1; |
| } |
| |
| return 0; |
| } |