Path: blob/trunk/cpp/imehandler/linux/src/ibushandler.cpp
2868 views
/*1Copyright 2011 WebDriver committers2Copyright 2011 Google Inc.34Licensed under the Apache License, Version 2.0 (the "License");5you may not use this file except in compliance with the License.6You may obtain a copy of the License at78http://www.apache.org/licenses/LICENSE-2.0910Unless required by applicable law or agreed to in writing, software11distributed under the License is distributed on an "AS IS" BASIS,12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13See the License for the specific language governing permissions and14limitations under the License.1516Author: [email protected]17*/1819#include <ibus.h>20#include <gtk/gtk.h>21#include <assert.h>2223// Note: should be included after including ibus. because ibus24// typedefs IBusBus rather than declare it as a class, so25// forward declaration is tricky.26#include "ibushandler.h"2728#include <string>29#include <vector>30#include <algorithm>31323334/*35* Initialize ibus and assures it is connected.36*/37IBusHandler::IBusHandler() : bus_(NULL), ibus_available_(false) {38const gchar* ibus_address = ibus_get_address();39// The ibus_available_ field indicates whether ibus is available40// or not. Attempt to determine this by getting the address of41// the ibus engine. If it's null then no engine is running.42if (ibus_address == NULL) {43ibus_available_ = false;44} else {45ibus_init();46bus_ = ibus_bus_new();47assert(ibus_bus_is_connected(bus_));48ibus_available_ = true;49}50}5152IBusHandler::~IBusHandler() {53}5455/*56* Returns the name of the global engine currently set.57*/58std::string IBusHandler::GetActiveEngine() const {59std::string engine_name = "";6061if (! ibus_available_) {62return engine_name;63}6465// Get the descriptor of the current global engine.66IBusEngineDesc* desc = ibus_bus_get_global_engine(bus_);67if (desc) {68// We copy the name of the global engine.69engine_name = std::string(desc->name);70g_object_unref(desc);71}72return engine_name;73}7475/*76* Get the current input context for the current bus connection.77*/78IBusInputContext* IBusHandler::GetCurrentInputContext() const {79gchar* context_name = ibus_bus_current_input_context(bus_);80if (context_name == NULL) {81// This happens on systems where ibus-gtk integration is not properly82// installed (most notably with 32-bit Firefox on a 64-bit machine).83// return NULL context so the library can gracefully return false.84return NULL;85}8687IBusConnection* conn = ibus_bus_get_connection(bus_);88assert(conn != NULL);89IBusInputContext* context = ibus_input_context_get_input_context(90context_name, conn);91// We don't need the context name anymore, we have to release it.92g_free(context_name);93return context;94}9596/*97* returns true if IME input is active, false otherwise.98*/99bool IBusHandler::IsActivated() const {100if (! ibus_available_) {101return false;102}103104IBusInputContext* context = GetCurrentInputContext();105if(context == NULL) {106return false;107}108109return ibus_input_context_is_enabled(context);110};111112/*113* Deactivates the current input context, hence switching back to the previous114* engine before activation.115*/116void IBusHandler::Deactivate() {117if (! ibus_available_) {118return;119}120121IBusInputContext* context = GetCurrentInputContext();122if(context == NULL) {123return;124}125126ibus_input_context_disable(context);127}128129/*130* Returns the names of all the available engines in the system.131*/132std::vector<std::string> IBusHandler::GetAvailableEngines() const {133std::vector<std::string> loaded_engines;134135if (! ibus_available_) {136return loaded_engines;137}138139GList* engines = ibus_bus_list_engines(bus_);140if (engines == NULL) {141// No engines available.142return loaded_engines;143}144145for (GList* engine = g_list_first(engines); engine != NULL ;146engine = g_list_next(engine)) {147IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data);148loaded_engines.push_back(desc->name);149g_object_unref(desc);150}151152g_list_free(engines);153return loaded_engines;154}155156/*157* Returns the names of all the preloaded engines.158*/159std::vector<std::string> IBusHandler::GetInstalledEngines() const {160std::vector<std::string> installed_engines;161162if (! ibus_available_) {163return installed_engines;164}165166GList* engines = ibus_bus_list_active_engines(bus_);167if (engines == NULL) {168// No engines available.169return installed_engines;170}171172for (GList* engine = g_list_first(engines); engine != NULL ;173engine = g_list_next(engine)) {174IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data);175installed_engines.push_back(desc->name);176g_object_unref(desc);177}178179g_list_free(engines);180return installed_engines;181}182183/*184* Sets the engines to be loaded by the ibus daemon, only those set via this185* method can be then activated.186* Note that there is a slight delay between the configuration values being set187* and the actual propagation into the ibus daemon (accessed via bus_ member),188* so direct call to GetInstalledEngines just after this method could return189* past results for isntance. A 1 second pause (see tests) is generally enough.190*/191int IBusHandler::LoadEngines(const std::vector<std::string>& engine_names) {192int nb_loaded_engines = 0;193194if (! ibus_available_) {195return nb_loaded_engines;196}197198// We want to avoid strange states where no engines are loaded, hence we199// simply ignore the call if an empty vector is passed as parameter.200if (!engine_names.empty()) {201GValue gvalue = {0};202g_value_init(&gvalue, G_TYPE_VALUE_ARRAY);203// TODO: Where is the array freed?204GValueArray* array = g_value_array_new(engine_names.size());205std::vector<std::string> available_engines = GetAvailableEngines();206for (std::vector<std::string>::const_iterator it = engine_names.begin() ;207it != engine_names.end() ; ++it) {208// We load the engines only if they are installed on the system.209if (std::find(available_engines.begin(), available_engines.end(), *it) !=210available_engines.end()) {211GValue array_element = {0};212g_value_init(&array_element, G_TYPE_STRING);213g_value_set_string(&array_element, it->c_str());214g_value_array_append(array, &array_element);215++nb_loaded_engines;216}217}218// If we made at least one change, then we override the current219// configuration.220if (nb_loaded_engines > 0) {221g_value_take_boxed(&gvalue, array);222IBusConfig* conf = ibus_bus_get_config(bus_);223ibus_config_set_value(conf, "general", "preload_engines", &gvalue);224}225g_value_unset(&gvalue);226}227return nb_loaded_engines;228}229230/*231* Sets the engine designed by its name to be the global engine232*/233bool IBusHandler::ActivateEngine(const std::string& engine_name) {234if (! ibus_available_) {235return false;236}237238bool retval = false;239240std::vector<std::string> available_engines = GetInstalledEngines();241// We activate only the engines that were preloaded or loaded by a call to242// LoadEngines before to ensure a valid state of the ibus system.243if (std::find(available_engines.begin(), available_engines.end(), engine_name)244!= available_engines.end()) {245retval = ibus_bus_set_global_engine(bus_, engine_name.c_str());246}247248IBusInputContext* context = GetCurrentInputContext();249if ((retval) && (context != NULL)) {250ibus_input_context_enable(context);251}252253return retval;254}255256/* To use the library with dlopen. */257extern "C" {258ImeHandler* create() {259return new IBusHandler;260}261262void destroy(ImeHandler* h) {263delete h;264}265}266267268