Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Unified Diff: chromeos_language.cc

Issue 521058: Support intra-IME switching. Cros part. (Closed)
Patch Set: addressed issues Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chromeos_language.h ('k') | load.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chromeos_language.cc
diff --git a/chromeos_language.cc b/chromeos_language.cc
index ef8fa104af02c1527d7ec232589c2180d9c212ec..58366875ba4b492353e607e823f0363f38e7ce3e 100644
--- a/chromeos_language.cc
+++ b/chromeos_language.cc
@@ -4,10 +4,13 @@
#include "chromeos_language.h"
-#include <base/logging.h>
#include <ibus.h>
+#include <dbus/dbus-glib-lowlevel.h> // for dbus_g_connection_get_connection.
#include <algorithm> // for std::sort.
+#include <sstream>
+#include <stack>
+#include <utility>
#include "chromeos/dbus/dbus.h"
#include "chromeos/glib/object.h"
@@ -18,6 +21,13 @@ const char kCandidateWindowService[] = "org.freedesktop.IBus.Panel";
const char kCandidateWindowObjectPath[] = "/org/chromium/Chrome/LanguageBar";
const char kCandidateWindowInterface[] = "org.freedesktop.IBus.Panel";
+// The list of IME property keys that we don't handle.
+const char* kImePropertyKeysBlacklist[] = {
+ "setup", // menu for showing setup dialog used in anthy and hangul.
+ "chewing_settings_prop", // menu for showing setup dialog used in chewing.
+ "status", // used in m17n.
+};
+
// Copies IME names in |engines| to |out|.
void AddIMELanguages(const GList* engines, chromeos::InputLanguageList* out) {
DCHECK(out);
@@ -41,6 +51,271 @@ void AddXKBLayouts(chromeos::InputLanguageList* out) {
"" /* no icon */)); // mock
}
+// Returns IBusInputContext for |input_context_path|. NULL on errors.
+IBusInputContext* GetInputContext(
+ const std::string& input_context_path, IBusBus* ibus) {
+ IBusInputContext* context = ibus_input_context_get_input_context(
+ input_context_path.c_str(), ibus_bus_get_connection(ibus));
+ if (!context) {
+ LOG(ERROR) << "IBusInputContext is null: " << input_context_path;
+ }
+ return context;
+}
+
+// Returns true if |key| is blacklisted.
+bool KeyIsBlacklisted(const char* key) {
+ for (size_t i = 0; i < arraysize(kImePropertyKeysBlacklist); ++i) {
+ if (!std::strcmp(key, kImePropertyKeysBlacklist[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Returns true if |prop| has children.
+bool PropertyHasChildren(IBusProperty* prop) {
+ return prop && prop->sub_props && ibus_prop_list_get(prop->sub_props, 0);
+}
+
+// This function is called by and FlattenProperty() and converts IBus
+// representation of a property, |ibus_prop|, to our own and push_back the
+// result to |out_prop_list|. This function returns true on success, and
+// returns false if sanity checks for |ibus_prop| fail.
+bool ConvertProperty(IBusProperty* ibus_prop,
+ int selection_item_id,
+ chromeos::ImePropertyList* out_prop_list) {
+ DCHECK(ibus_prop);
+ DCHECK(ibus_prop->key);
+ DCHECK(out_prop_list);
+
+ // Sanity checks.
+ const bool has_sub_props = PropertyHasChildren(ibus_prop);
+ if (has_sub_props && (ibus_prop->type != PROP_TYPE_MENU)) {
+ LOG(ERROR) << "The property has sub properties, "
+ << "but the type of the property is not PROP_TYPE_MENU";
+ return false;
+ }
+ if ((!has_sub_props) && (ibus_prop->type == PROP_TYPE_MENU)) {
+ LOG(ERROR) << "The property does not have sub properties, "
+ << "but the type of the property is PROP_TYPE_MENU";
+ return false;
+ }
+ if (ibus_prop->type == PROP_TYPE_SEPARATOR ||
+ ibus_prop->type == PROP_TYPE_MENU) {
+ // This is not an error, but we don't push an item for these types.
+ return true;
+ }
+
+ const bool is_selection_item = (ibus_prop->type == PROP_TYPE_RADIO);
+ selection_item_id
+ = is_selection_item ? selection_item_id : kInvalidSelectionItemId;
+
+ bool is_selection_item_checked = false;
+ if (ibus_prop->state == PROP_STATE_INCONSISTENT) {
+ LOG(WARNING) << "The property is in PROP_STATE_INCONSISTENT, "
+ << "which is not supported.";
+ } else if ((!is_selection_item) && (ibus_prop->state == PROP_STATE_CHECKED)) {
+ LOG(WARNING) << "PROP_STATE_CHECKED is meaningful only if the type is "
+ << "PROP_TYPE_RADIO.";
+ } else {
+ is_selection_item_checked = (ibus_prop->state == PROP_STATE_CHECKED);
+ }
+
+ // TODO(yusukes): Probably it's better to generate our own label from the key?
+ std::string label = (ibus_prop->tooltip ? ibus_prop->tooltip->text : "");
+ if (label.empty()) {
+ // Usually tooltips are more descriptive than labels.
+ label = (ibus_prop->label ? ibus_prop->label->text : "");
+ }
+ if (label.empty()) {
+ // ibus-pinyin has a property whose label and tooltip are empty. Fall back
+ // to the key.
+ label = ibus_prop->key;
+ }
+
+ out_prop_list->push_back(chromeos::ImeProperty(ibus_prop->key,
+ ibus_prop->icon,
+ label,
+ is_selection_item,
+ is_selection_item_checked,
+ selection_item_id));
+ return true;
+}
+
+// Converts |ibus_prop| to |out_prop_list|. Please note that |ibus_prop|
+// may or may not have children. See the comment for FlattenPropertyList
+// for details. Returns true if no error is found.
+bool FlattenProperty(
+ IBusProperty* ibus_prop, chromeos::ImePropertyList* out_prop_list) {
+ // TODO(yusukes): Find a good way to write unit tests for this function.
+ DCHECK(ibus_prop);
+ DCHECK(out_prop_list);
+
+ int selection_item_id = -1;
+ std::stack<std::pair<IBusProperty*, int> > prop_stack;
+ prop_stack.push(std::make_pair(ibus_prop, selection_item_id));
+
+ while (!prop_stack.empty()) {
+ IBusProperty* prop = prop_stack.top().first;
+ const int current_selection_item_id = prop_stack.top().second;
+ prop_stack.pop();
+
+ // Filter out unnecessary properties.
+ if (KeyIsBlacklisted(prop->key)) {
+ continue;
+ }
+
+ // Convert |prop| to ImeProperty and push it to |out_prop_list|.
+ if (!ConvertProperty(prop, current_selection_item_id, out_prop_list)) {
+ return false;
+ }
+
+ // Process childrens iteratively (if any). Push all sub properties to the
+ // stack.
+ if (PropertyHasChildren(prop)) {
+ ++selection_item_id;
+ for (int i = 0;; ++i) {
+ IBusProperty* sub_prop = ibus_prop_list_get(prop->sub_props, i);
+ if (!sub_prop) {
+ break;
+ }
+ prop_stack.push(std::make_pair(sub_prop, selection_item_id));
+ }
+ ++selection_item_id;
+ }
+ }
+ std::reverse(out_prop_list->begin(), out_prop_list->end());
+
+ return true;
+}
+
+// Converts IBus representation of a property list, |ibus_prop_list| to our
+// own. This function also flatten the original list (actually it's a tree).
+// Returns true if no error is found. The conversion to our own type is
+// necessary since our language switcher in Chrome tree don't (or can't) know
+// IBus types. Here is an example:
+//
+// ======================================================================
+// Input:
+//
+// --- Item-1
+// |- Item-2
+// |- SubMenuRoot --- Item-3-1
+// | |- Item-3-2
+// | |- Item-3-3
+// |- Item-4
+//
+// (Note: Item-3-X is a selection item since they're on a sub menu.)
+//
+// Output:
+//
+// Item-1, Item-2, Item-3-1, Item-3-2, Item-3-3, Item-4
+// (Note: SubMenuRoot does not appear in the output.)
+// ======================================================================
+bool FlattenPropertyList(
+ IBusPropList* ibus_prop_list, chromeos::ImePropertyList* out_prop_list) {
+ // TODO(yusukes): Find a good way to write unit tests for this function.
+ DCHECK(ibus_prop_list);
+ DCHECK(out_prop_list);
+
+ IBusProperty* fake_root_prop = ibus_property_new("Dummy.Key",
+ PROP_TYPE_MENU,
+ NULL, /* label */
+ "", /* icon */
+ NULL, /* tooltip */
+ FALSE, /* sensitive */
+ FALSE, /* visible */
+ PROP_STATE_UNCHECKED,
+ ibus_prop_list);
+
+ const bool result
+ = fake_root_prop && FlattenProperty(fake_root_prop, out_prop_list);
+ g_object_unref(fake_root_prop);
+
+ return result;
+}
+
+// Debug print functions.
+const char* PropTypeToString(int prop_type) {
+ switch (static_cast<IBusPropType>(prop_type)) {
+ case PROP_TYPE_NORMAL:
+ return "NORMAL";
+ case PROP_TYPE_TOGGLE:
+ return "TOGGLE";
+ case PROP_TYPE_RADIO:
+ return "RADIO";
+ case PROP_TYPE_MENU:
+ return "MENU";
+ case PROP_TYPE_SEPARATOR:
+ return "SEPARATOR";
+ }
+ return "UNKNOWN";
+}
+
+const char* PropStateToString(int prop_state) {
+ switch (static_cast<IBusPropState>(prop_state)) {
+ case PROP_STATE_UNCHECKED:
+ return "UNCHECKED";
+ case PROP_STATE_CHECKED:
+ return "CHECKED";
+ case PROP_STATE_INCONSISTENT:
+ return "INCONSISTENT";
+ }
+ return "UNKNOWN";
+}
+
+std::string Spacer(int n) {
+ return std::string(n, ' ');
+}
+
+std::string PrintPropList(IBusPropList *prop_list, int tree_level);
+std::string PrintProp(IBusProperty *prop, int tree_level) {
+ if (!prop) {
+ return "";
+ }
+
+ std::stringstream stream;
+ stream << Spacer(tree_level) << "=========================" << std::endl;
+ stream << Spacer(tree_level) << "key: " << (prop->key ? prop->key : "<none>")
+ << std::endl;
+ stream << Spacer(tree_level) << "icon: "
+ << (prop->icon ? prop->icon : "<none>") << std::endl;
+ stream << Spacer(tree_level) << "label: "
+ << (prop->label ? prop->label->text : "<none>") << std::endl;
+ stream << Spacer(tree_level) << "tooptip: "
+ << (prop->tooltip ? prop->tooltip->text : "<none>") << std::endl;
+ stream << Spacer(tree_level) << "sensitive: "
+ << (prop->sensitive ? "YES" : "NO") << std::endl;
+ stream << Spacer(tree_level) << "visible: " << (prop->visible ? "YES" : "NO")
+ << std::endl;
+ stream << Spacer(tree_level) << "type: " << PropTypeToString(prop->type)
+ << std::endl;
+ stream << Spacer(tree_level) << "state: " << PropStateToString(prop->state)
+ << std::endl;
+ stream << Spacer(tree_level) << "sub_props: "
+ << (PropertyHasChildren(prop) ? "" : "<none>") << std::endl;
+ stream << PrintPropList(prop->sub_props, tree_level + 1);
+ stream << Spacer(tree_level) << "=========================" << std::endl;
+
+ return stream.str();
+}
+
+std::string PrintPropList(IBusPropList *prop_list, int tree_level) {
+ if (!prop_list) {
+ return "";
+ }
+
+ std::stringstream stream;
+ for (int i = 0;; ++i) {
+ IBusProperty* prop = ibus_prop_list_get(prop_list, i);
+ if (!prop) {
+ break;
+ }
+ stream << PrintProp(prop, tree_level);
+ }
+ return stream.str();
+}
+
} // namespace
namespace chromeos {
@@ -48,17 +323,16 @@ namespace chromeos {
// A class that holds IBus and DBus connections.
class LanguageStatusConnection {
public:
- LanguageStatusConnection(LanguageStatusMonitorFunction monitor_function,
+ LanguageStatusConnection(LanguageStatusMonitorFunctions monitor_functions,
void* language_library)
- : monitor_function_(monitor_function),
+ : monitor_functions_(monitor_functions),
language_library_(language_library),
ibus_(NULL),
ibus_config_(NULL),
- dbus_focus_in_(NULL),
- dbus_focus_out_(NULL),
- dbus_state_changed_(NULL),
input_context_path_("") {
- DCHECK(monitor_function_);
+ DCHECK(monitor_functions_.current_language);
+ DCHECK(monitor_functions_.register_ime_properties);
+ DCHECK(monitor_functions_.update_ime_property);
DCHECK(language_library_);
}
@@ -70,15 +344,6 @@ class LanguageStatusConnection {
if (ibus_) {
g_object_unref(ibus_);
}
- if (dbus_focus_in_) {
- dbus::Disconnect(dbus_focus_in_);
- }
- if (dbus_focus_out_) {
- dbus::Disconnect(dbus_focus_out_);
- }
- if (dbus_state_changed_) {
- dbus::Disconnect(dbus_state_changed_);
- }
}
// Initializes IBus and DBus connections.
@@ -112,43 +377,33 @@ class LanguageStatusConnection {
return false;
}
-
// Establish a DBus connection between the candidate_window process for
- // Chromium OS to handle "FocusIn", "FocusOut", and "StateChanged" signals
- // from the process.
+ // Chromium OS to handle signals (e.g. "FocusIn") from the process.
const char* address = ibus_get_address();
- dbus::BusConnection dbus(dbus::GetPrivateBusConnection(address));
+ dbus_connection_.reset(
+ new dbus::BusConnection(dbus::GetPrivateBusConnection(address)));
LOG(INFO) << "Established private D-Bus connection to: '" << address << "'";
+ // Connect to the candidate_window. Note that dbus_connection_add_filter()
+ // does not work without calling dbus::Proxy().
+ // TODO(yusukes): Investigate how we can eliminate the call.
+
const bool kConnectToNameOwner = true;
// TODO(yusukes): dbus::Proxy instantiation might fail (and abort due to
// DCHECK failure) when candidate_window process does not exist yet.
// Would be better to add "bool dbus::Proxy::Init()" or something like that
// to handle such case?
- dbus::Proxy candidate_window(dbus,
- kCandidateWindowService,
- kCandidateWindowObjectPath,
- kCandidateWindowInterface,
- kConnectToNameOwner);
-
- if (!candidate_window) {
- LOG(ERROR) << "Can't construct proxy for the candidate window. "
- << "candidate window is not running?";
- return false;
- }
-
- dbus_focus_in_ = dbus::Monitor(candidate_window,
- "FocusIn",
- &LanguageStatusConnection::FocusIn,
- this);
- dbus_focus_out_ = dbus::Monitor(candidate_window,
- "FocusOut",
- &LanguageStatusConnection::FocusOut,
- this);
- dbus_state_changed_ = dbus::Monitor(candidate_window,
- "StateChanged",
- &LanguageStatusConnection::StateChanged,
- this);
+ dbus_proxy_.reset(new dbus::Proxy(*dbus_connection_,
+ kCandidateWindowService,
+ kCandidateWindowObjectPath,
+ kCandidateWindowInterface,
+ kConnectToNameOwner));
+
+ // Register DBus signal handler.
+ dbus_connection_add_filter(
+ dbus_g_connection_get_connection(dbus_connection_->g_connection()),
+ &LanguageStatusConnection::DispatchSignalFromCandidateWindow,
+ this, NULL);
// TODO(yusukes): Investigate what happens if IBus/DBus connections are
// suddenly closed.
@@ -191,36 +446,46 @@ class LanguageStatusConnection {
return language_list;
}
- // Called by cros API ChromeOSChangeLanguage().
- void SwitchXKB(const char* name) {
- // TODO(yusukes): implement XKB switching.
-
+ // Called by cros API ChromeOS(Activate|Deactive)ImeProperty().
+ void ActivateOrDeactiveImeProperty(const char* key, bool active) {
if (input_context_path_.empty()) {
LOG(ERROR) << "Input context is unknown";
return;
}
- IBusInputContext* context
- = ibus_input_context_get_input_context(input_context_path_.c_str(),
- ibus_bus_get_connection(ibus_));
- ibus_input_context_disable(context);
+ IBusInputContext* context = GetInputContext(input_context_path_, ibus_);
+ if (!context) {
+ return;
+ }
+ ibus_input_context_property_activate(
+ context, key, (active ? PROP_STATE_CHECKED : PROP_STATE_UNCHECKED));
g_object_unref(context);
+
UpdateUI();
}
- // Called by cros API ChromeOSChangeLanguage() as well.
- void SwitchIME(const char* name) {
- if (input_context_path_.empty()) {
- LOG(ERROR) << "Input context is unknown";
- return;
+ // Called by cros API ChromeOSChangeLanguage().
+ void ChangeLanguage(LanguageCategory category, const char* name) {
+ // Clear all IME properties unconditionally.
+ // - When switching to XKB, it's necessary since XKB layout does not have
+ // IME properties.
+ // - When switching to IME and a text area is focused, it's okay to clear
+ // IME properties here since RegisterProperties signal for the new IME
+ // will be sent anyway.
+ // - When switching to IME and no text area is focused, RegisterProperties
+ // signal for the new IME will NOT be sent until a text area is focused.
+ // Therefore, we have to clear the old IME properties here to keep the
+ // IME switcher status consistent.
+ RegisterProperties(NULL);
+
+ switch (category) {
+ case LANGUAGE_CATEGORY_XKB:
+ SwitchToXKB(name);
+ break;
+ case LANGUAGE_CATEGORY_IME:
+ SwitchToIME(name);
+ break;
}
-
- IBusInputContext* context
- = ibus_input_context_get_input_context(input_context_path_.c_str(),
- ibus_bus_get_connection(ibus_));
- ibus_input_context_set_engine(context, name);
- g_object_unref(context);
- UpdateUI();
}
// UpdateMode is used for specifying whether we are activating or
@@ -287,9 +552,10 @@ class LanguageStatusConnection {
}
InputLanguage* GetCurrentLanguage() {
- IBusInputContext* context
- = ibus_input_context_get_input_context(
- input_context_path_.c_str(), ibus_bus_get_connection(ibus_));
+ IBusInputContext* context = GetInputContext(input_context_path_, ibus_);
+ if (!context) {
+ return NULL;
+ }
const bool ime_is_enabled = ibus_input_context_is_enabled(context);
g_object_unref(context);
@@ -321,35 +587,97 @@ class LanguageStatusConnection {
}
private:
- // Handles "FocusIn" signal from candidate_window.
- static void FocusIn(void* object, const char* input_context_path) {
+ // Changes the current language to |name|, which is XKB layout.
+ void SwitchToXKB(const char* name) {
+ // TODO(yusukes): implement XKB switching.
+ if (input_context_path_.empty()) {
+ LOG(ERROR) << "Input context is unknown";
+ return;
+ }
+
+ IBusInputContext* context = GetInputContext(input_context_path_, ibus_);
+ if (!context) {
+ return;
+ }
+ ibus_input_context_disable(context);
+ g_object_unref(context);
+ UpdateUI();
+ }
+
+ // Changes the current language to |name|, which is IME.
+ void SwitchToIME(const char* name) {
+ if (input_context_path_.empty()) {
+ LOG(ERROR) << "Input context is unknown";
+ return;
+ }
+
+ IBusInputContext* context = GetInputContext(input_context_path_, ibus_);
+ if (!context) {
+ return;
+ }
+ ibus_input_context_set_engine(context, name);
+ g_object_unref(context);
+ UpdateUI();
+ }
+
+ // Handles "FocusIn" signal from the candidate_window process.
+ void FocusIn(const char* input_context_path) {
DCHECK(input_context_path) << "NULL context passed";
DLOG(INFO) << "FocusIn: " << input_context_path;
- DCHECK(object);
// Remember the current ic path.
- LanguageStatusConnection* self
- = static_cast<LanguageStatusConnection*>(object);
- self->input_context_path_ = input_context_path;
- self->UpdateUI(); // This is necessary since IME status is held per ic.
+ input_context_path_ = input_context_path;
+ UpdateUI(); // This is necessary since IME status is held per ic.
}
- // Handles "FocusOut" signal from candidate_window.
- static void FocusOut(void* object, const char* input_context_path) {
+ // Handles "FocusOut" signal from the candidate_window process.
+ void FocusOut(const char* input_context_path) {
DCHECK(input_context_path) << "NULL context passed";
DLOG(INFO) << "FocusOut: " << input_context_path;
- DCHECK(object);
}
- // Handles "StateChanged" signal from candidate_window process.
- static void StateChanged(void* object, const char* dummy) {
+ // Handles "StateChanged" signal from the candidate_window process.
+ void StateChanged() {
// TODO(yusukes): Modify common/chromeos/dbus/dbus.h so that we can handle
// signals without argument. Then remove the |dummy|.
DLOG(INFO) << "StateChanged";
- DCHECK(object);
- LanguageStatusConnection* self
- = static_cast<LanguageStatusConnection*>(object);
- self->UpdateUI();
+ UpdateUI();
+ }
+
+ // Handles "RegisterProperties" signal from the candidate_window process.
+ void RegisterProperties(IBusPropList* ibus_prop_list) {
+ DLOG(INFO) << "RegisterProperties" << (ibus_prop_list ? "" : " (clear)");
+
+ ImePropertyList prop_list; // our representation.
+ if (ibus_prop_list) {
+ // You can call
+ // LOG(INFO) << "\n" << PrintPropList(ibus_prop_list, 0);
+ // here to dump |ibus_prop_list|.
+ if (!FlattenPropertyList(ibus_prop_list, &prop_list)) {
+ LOG(WARNING) << "Malformed properties are detected";
+ }
+ }
+ // Notify the change.
+ monitor_functions_.register_ime_properties(language_library_, prop_list);
+ }
+
+ // Handles "UpdateProperty" signal from the candidate_window process.
+ void UpdateProperty(IBusProperty* ibus_prop) {
+ DLOG(INFO) << "UpdateProperty";
+ DCHECK(ibus_prop);
+
+ // You can call
+ // LOG(INFO) << "\n" << PrintProp(ibus_prop, 0);
+ // here to dump |ibus_prop|.
+
+ ImePropertyList prop_list; // our representation.
+ if (!FlattenProperty(ibus_prop, &prop_list)) {
+ LOG(WARNING) << "Malformed properties are detected";
+ }
+ // Notify the change.
+ if (!prop_list.empty()) {
+ monitor_functions_.update_ime_property(language_library_, prop_list);
+ }
}
// Retrieve IME/XKB status and notify them to the UI.
@@ -359,9 +687,10 @@ class LanguageStatusConnection {
return;
}
- IBusInputContext* context
- = ibus_input_context_get_input_context(
- input_context_path_.c_str(), ibus_bus_get_connection(ibus_));
+ IBusInputContext* context = GetInputContext(input_context_path_, ibus_);
+ if (!context) {
+ return;
+ }
InputLanguage current_language;
const bool ime_is_enabled = ibus_input_context_is_enabled(context);
@@ -391,24 +720,125 @@ class LanguageStatusConnection {
<< ", display_name:" << current_language.display_name;
// Notify the change to update UI.
- monitor_function_(language_library_, current_language);
+ monitor_functions_.current_language(language_library_, current_language);
g_object_unref(context);
}
- // A function pointer which points LanguageLibrary::LanguageChangedHandler
- // function. |monitor_funcion_| is called when Chrome UI needs to be updated.
- LanguageStatusMonitorFunction monitor_function_;
+ // Dispatches signals from candidate_window. In this function, we use the
+ // IBus's DBus binding (rather than the dbus-glib and its C++ wrapper).
+ // This is because arguments of "RegisterProperties" and "UpdateProperty"
+ // are fairly complex IBus types, and thus it's probably not a good idea
+ // to write a deserializer for these types from scratch using dbus-glib.
+ static DBusHandlerResult DispatchSignalFromCandidateWindow(
+ DBusConnection* connection, DBusMessage* message, void* object) {
+ DCHECK(message);
+ DCHECK(object);
+
+ LanguageStatusConnection* self
+ = static_cast<LanguageStatusConnection*>(object);
+ IBusError* error = NULL;
+
+ if (ibus_message_is_signal(message,
+ kCandidateWindowInterface,
+ "FocusIn")) {
+ gchar* input_context_path = NULL;
+ const gboolean retval = ibus_message_get_args(message, &error,
+ G_TYPE_STRING,
+ &input_context_path,
+ G_TYPE_INVALID);
+ if (!retval) {
+ LOG(ERROR) << "FocusIn";
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ self->FocusIn(input_context_path);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (ibus_message_is_signal(message,
+ kCandidateWindowInterface,
+ "FocusOut")) {
+ gchar* input_context_path = NULL;
+ const gboolean retval = ibus_message_get_args(message, &error,
+ G_TYPE_STRING,
+ &input_context_path,
+ G_TYPE_INVALID);
+ if (!retval) {
+ LOG(ERROR) << "FocusOut";
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ self->FocusOut(input_context_path);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (ibus_message_is_signal(message,
+ kCandidateWindowInterface,
+ "StateChanged")) {
+ const gboolean retval = ibus_message_get_args(message, &error,
+ /* no arguments */
+ G_TYPE_INVALID);
+ if (!retval) {
+ LOG(ERROR) << "StateChanged";
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ self->StateChanged();
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (ibus_message_is_signal(message,
+ kCandidateWindowInterface,
+ "RegisterProperties")) {
+ IBusPropList* prop_list = NULL;
+
+ // The ibus_message_get_args() function automagically deserializes the
+ // complex IBus structure.
+ const gboolean retval = ibus_message_get_args(message, &error,
+ IBUS_TYPE_PROP_LIST,
+ &prop_list,
+ G_TYPE_INVALID);
+
+ if (!retval) {
+ LOG(ERROR) << "RegisterProperties";
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ self->RegisterProperties(prop_list);
+ g_object_unref(prop_list);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (ibus_message_is_signal(message,
+ kCandidateWindowInterface,
+ "UpdateProperty")) {
+ IBusProperty* prop = NULL;
+ const gboolean retval = ibus_message_get_args(message, &error,
+ IBUS_TYPE_PROPERTY,
+ &prop,
+ G_TYPE_INVALID);
+ if (!retval) {
+ LOG(ERROR) << "UpdateProperty";
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ self->UpdateProperty(prop);
+ g_object_unref(prop);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ // A function pointers which point LanguageLibrary::XXXHandler functions.
+ // |monitor_funcions_| is used when libcros receives signals from the
+ // candidate_window.
+ LanguageStatusMonitorFunctions monitor_functions_;
+
// Points to a chromeos::LanguageLibrary object. |language_library_| is used
- // as the first argument of the |monitor_function_| function.
+ // as the first argument of the |monitor_functions_| functions.
void* language_library_;
// Connections to IBus and DBus.
- typedef dbus::MonitorConnection<void (const char*)>* DBusConnectionType;
IBusBus* ibus_;
IBusConfig* ibus_config_;
- DBusConnectionType dbus_focus_in_;
- DBusConnectionType dbus_focus_out_;
- DBusConnectionType dbus_state_changed_;
+ scoped_ptr<dbus::BusConnection> dbus_connection_;
+ scoped_ptr<dbus::Proxy> dbus_proxy_;
// Current input context path.
std::string input_context_path_;
@@ -423,10 +853,10 @@ class LanguageStatusConnection {
// get mangled.
extern "C"
LanguageStatusConnection* ChromeOSMonitorLanguageStatus(
- LanguageStatusMonitorFunction monitor_function, void* language_library) {
+ LanguageStatusMonitorFunctions monitor_functions, void* language_library) {
LOG(INFO) << "MonitorLanguageStatus";
LanguageStatusConnection* connection
- = new LanguageStatusConnection(monitor_function, language_library);
+ = new LanguageStatusConnection(monitor_functions, language_library);
if (!connection->Init()) {
LOG(WARNING) << "Failed to Init() LanguageStatusConnection. "
<< "Returning NULL";
@@ -468,25 +898,46 @@ InputLanguageList* ChromeOSGetSupportedLanguages(LanguageStatusConnection*
}
extern "C"
+void ChromeOSActivateImeProperty(
+ LanguageStatusConnection* connection, const char* key) {
+ DLOG(INFO) << "ActivateImeProperty";
+ DCHECK(key);
+ // TODO(yusukes): Add DCHECK(connection); here when candidate_window for
+ // Chrome OS gets ready.
+ if (!connection) {
+ LOG(WARNING) << "LanguageStatusConnection is NULL";
+ return;
+ }
+ connection->ActivateOrDeactiveImeProperty(key, true);
+}
+
+extern "C"
+void ChromeOSDeactivateImeProperty(
+ LanguageStatusConnection* connection, const char* key) {
+ DLOG(INFO) << "DeactivateImeProperty";
+ DCHECK(key);
+ // TODO(yusukes): Add DCHECK(connection); here when candidate_window for
+ // Chrome OS gets ready.
+ if (!connection) {
+ LOG(WARNING) << "LanguageStatusConnection is NULL";
+ return;
+ }
+ connection->ActivateOrDeactiveImeProperty(key, false);
+}
+
+extern "C"
void ChromeOSChangeLanguage(LanguageStatusConnection* connection,
LanguageCategory category,
const char* name) {
+ DCHECK(name);
+ DLOG(INFO) << "ChangeLanguage: " << name;
// TODO(yusukes): Add DCHECK(connection); here when candidate_window for
// Chrome OS gets ready.
if (!connection) {
LOG(WARNING) << "LanguageStatusConnection is NULL";
return;
}
- DCHECK(name);
- DLOG(INFO) << "ChangeLanguage: " << name << " [category " << category << "]";
- switch (category) {
- case LANGUAGE_CATEGORY_XKB:
- connection->SwitchXKB(name);
- break;
- case LANGUAGE_CATEGORY_IME:
- connection->SwitchIME(name);
- break;
- }
+ connection->ChangeLanguage(category, name);
}
// Helper function for ChromeOSActivateLanguage() and
« no previous file with comments | « chromeos_language.h ('k') | load.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698