// 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 #include #include #include #include #include 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; }