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

Side by Side Diff: chrome/browser/chromeos/input_method/ibus_controller_impl.cc

Issue 11280159: Remove ibus dependency from PanelService. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 8 years 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/input_method/ibus_controller_impl.h" 5 #include "chrome/browser/chromeos/input_method/ibus_controller_impl.h"
6 6
7 #include <algorithm> // for std::reverse. 7 #include <algorithm> // for std::reverse.
8 #include <cstdio> 8 #include <cstdio>
9 #include <cstring> // for std::strcmp. 9 #include <cstring> // for std::strcmp.
10 #include <set> 10 #include <set>
(...skipping 11 matching lines...) Expand all
22 #include "base/string_split.h" 22 #include "base/string_split.h"
23 #include "base/stringprintf.h" 23 #include "base/stringprintf.h"
24 #include "chrome/browser/chromeos/input_method/input_method_config.h" 24 #include "chrome/browser/chromeos/input_method/input_method_config.h"
25 #include "chrome/browser/chromeos/input_method/input_method_property.h" 25 #include "chrome/browser/chromeos/input_method/input_method_property.h"
26 #include "chrome/browser/chromeos/input_method/input_method_util.h" 26 #include "chrome/browser/chromeos/input_method/input_method_util.h"
27 #include "chromeos/dbus/dbus_thread_manager.h" 27 #include "chromeos/dbus/dbus_thread_manager.h"
28 #include "chromeos/dbus/ibus/ibus_client.h" 28 #include "chromeos/dbus/ibus/ibus_client.h"
29 #include "chromeos/dbus/ibus/ibus_config_client.h" 29 #include "chromeos/dbus/ibus/ibus_config_client.h"
30 #include "chromeos/dbus/ibus/ibus_constants.h" 30 #include "chromeos/dbus/ibus/ibus_constants.h"
31 #include "chromeos/dbus/ibus/ibus_input_context_client.h" 31 #include "chromeos/dbus/ibus/ibus_input_context_client.h"
32 #include "chromeos/dbus/ibus/ibus_panel_service.h"
33 #include "chromeos/dbus/ibus/ibus_property.h"
32 #include "content/public/browser/browser_thread.h" 34 #include "content/public/browser/browser_thread.h"
33 #include "ui/aura/client/aura_constants.h" 35 #include "ui/aura/client/aura_constants.h"
34 #include "ui/aura/root_window.h" 36 #include "ui/aura/root_window.h"
35 #include "ui/base/ime/input_method_ibus.h" 37 #include "ui/base/ime/input_method_ibus.h"
36 38
37 // TODO(nona): Remove libibus dependency from this file. Then, write unit tests
38 // for all functions in this file. crbug.com/26334
39 #if defined(HAVE_IBUS)
40 #include <ibus.h>
41 #endif
42
43 namespace { 39 namespace {
44 40
45 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the 41 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the
46 // property with |new_prop|. Returns true if such a property is found. 42 // property with |new_prop|. Returns true if such a property is found.
47 bool FindAndUpdateProperty( 43 bool FindAndUpdateProperty(
48 const chromeos::input_method::InputMethodProperty& new_prop, 44 const chromeos::input_method::InputMethodProperty& new_prop,
49 chromeos::input_method::InputMethodPropertyList* prop_list) { 45 chromeos::input_method::InputMethodPropertyList* prop_list) {
50 for (size_t i = 0; i < prop_list->size(); ++i) { 46 for (size_t i = 0; i < prop_list->size(); ++i) {
51 chromeos::input_method::InputMethodProperty& prop = prop_list->at(i); 47 chromeos::input_method::InputMethodProperty& prop = prop_list->at(i);
52 if (prop.key == new_prop.key) { 48 if (prop.key == new_prop.key) {
53 prop = new_prop; 49 prop = new_prop;
54 return true; 50 return true;
55 } 51 }
56 } 52 }
57 return false; 53 return false;
58 } 54 }
59 55
60 void ConfigSetValueErrorCallback() { 56 void ConfigSetValueErrorCallback() {
61 DVLOG(1) << "IBusConfig: SetValue is failed."; 57 DVLOG(1) << "IBusConfig: SetValue is failed.";
62 } 58 }
63 59
64 } // namespace 60 } // namespace
65 61
66 namespace chromeos { 62 namespace chromeos {
67 namespace input_method { 63 namespace input_method {
68 64
69 #if defined(HAVE_IBUS)
70 const char kPanelObjectKey[] = "panel-object";
71
72 namespace { 65 namespace {
73 66
74 const char* Or(const char* str1, const char* str2) {
75 return str1 ? str1 : str2;
76 }
77
78 // Returns true if |key| is blacklisted. 67 // Returns true if |key| is blacklisted.
79 bool PropertyKeyIsBlacklisted(const char* key) { 68 bool PropertyKeyIsBlacklisted(const std::string& key) {
80 // The list of input method property keys that we don't handle. 69 // The list of input method property keys that we don't handle.
81 static const char* kInputMethodPropertyKeysBlacklist[] = { 70 static const char* kInputMethodPropertyKeysBlacklist[] = {
82 "setup", // used in ibus-m17n. 71 "setup", // used in ibus-m17n.
83 "status", // used in ibus-m17n. 72 "status", // used in ibus-m17n.
84 }; 73 };
85 for (size_t i = 0; i < arraysize(kInputMethodPropertyKeysBlacklist); ++i) { 74 for (size_t i = 0; i < arraysize(kInputMethodPropertyKeysBlacklist); ++i) {
86 if (!std::strcmp(key, kInputMethodPropertyKeysBlacklist[i])) 75 if (key == kInputMethodPropertyKeysBlacklist[i])
87 return true; 76 return true;
88 } 77 }
89 return false; 78 return false;
90 } 79 }
91 80
92 // Returns true if |prop| has children.
93 bool PropertyHasChildren(IBusProperty* prop) {
94 return prop && ibus_property_get_sub_props(prop) &&
95 ibus_prop_list_get(ibus_property_get_sub_props(prop), 0);
96 }
97
98 // This function is called by and FlattenProperty() and converts IBus 81 // This function is called by and FlattenProperty() and converts IBus
99 // representation of a property, |ibus_prop|, to our own and push_back the 82 // representation of a property, |ibus_prop|, to our own and push_back the
100 // result to |out_prop_list|. This function returns true on success, and 83 // result to |out_prop_list|. This function returns true on success, and
101 // returns false if sanity checks for |ibus_prop| fail. 84 // returns false if sanity checks for |ibus_prop| fail.
102 bool ConvertProperty(IBusProperty* ibus_prop, 85 bool ConvertProperty(const ibus::IBusProperty& ibus_prop,
103 InputMethodPropertyList* out_prop_list) { 86 InputMethodPropertyList* out_prop_list) {
104 DCHECK(ibus_prop);
105 DCHECK(out_prop_list); 87 DCHECK(out_prop_list);
106 88 DCHECK(ibus_prop.key().empty());
107 const IBusPropType type = ibus_property_get_prop_type(ibus_prop); 89 ibus::IBusProperty::IBusPropertyType type = ibus_prop.type();
108 const IBusPropState state = ibus_property_get_state(ibus_prop);
109 const IBusText* tooltip = ibus_property_get_tooltip(ibus_prop);
110 const IBusText* label = ibus_property_get_label(ibus_prop);
111 const gchar* key = ibus_property_get_key(ibus_prop);
112 DCHECK(key);
113 90
114 // Sanity checks. 91 // Sanity checks.
115 const bool has_sub_props = PropertyHasChildren(ibus_prop); 92 const bool has_sub_props = !ibus_prop.sub_properties().empty();
116 if (has_sub_props && (type != PROP_TYPE_MENU)) { 93 if (has_sub_props && (type != ibus::IBusProperty::IBUS_PROPERTY_TYPE_MENU)) {
117 DVLOG(1) << "The property has sub properties, " 94 DVLOG(1) << "The property has sub properties, "
118 << "but the type of the property is not PROP_TYPE_MENU"; 95 << "but the type of the property is not PROP_TYPE_MENU";
119 return false; 96 return false;
120 } 97 }
121 if ((!has_sub_props) && (type == PROP_TYPE_MENU)) { 98 if ((!has_sub_props) &&
99 (type == ibus::IBusProperty::IBUS_PROPERTY_TYPE_MENU)) {
122 // This is usually not an error. ibus-daemon sometimes sends empty props. 100 // This is usually not an error. ibus-daemon sometimes sends empty props.
123 DVLOG(1) << "Property list is empty"; 101 DVLOG(1) << "Property list is empty";
124 return false; 102 return false;
125 } 103 }
126 if (type == PROP_TYPE_SEPARATOR || type == PROP_TYPE_MENU) { 104 if (type == ibus::IBusProperty::IBUS_PROPERTY_TYPE_SEPARATOR ||
105 type == ibus::IBusProperty::IBUS_PROPERTY_TYPE_MENU) {
127 // This is not an error, but we don't push an item for these types. 106 // This is not an error, but we don't push an item for these types.
128 return true; 107 return true;
129 } 108 }
130 109
131 const bool is_selection_item = (type == PROP_TYPE_RADIO);
132
133 bool is_selection_item_checked = false;
134 if (state == PROP_STATE_INCONSISTENT) {
135 DVLOG(1) << "The property is in PROP_STATE_INCONSISTENT, "
136 << "which is not supported.";
137 } else if ((!is_selection_item) && (state == PROP_STATE_CHECKED)) {
138 DVLOG(1) << "PROP_STATE_CHECKED is meaningful only if the type is "
139 << "PROP_TYPE_RADIO.";
140 } else {
141 is_selection_item_checked = (state == PROP_STATE_CHECKED);
142 }
143
144 if (!key)
145 DVLOG(1) << "key is NULL";
146 if (tooltip && !tooltip->text) {
147 DVLOG(1) << "tooltip is NOT NULL, but tooltip->text IS NULL: key="
148 << Or(key, "");
149 }
150 if (label && !label->text) {
151 DVLOG(1) << "label is NOT NULL, but label->text IS NULL: key="
152 << Or(key, "");
153 }
154
155 // This label will be localized later. 110 // This label will be localized later.
156 // See chrome/browser/chromeos/input_method/input_method_util.cc. 111 // See chrome/browser/chromeos/input_method/input_method_util.cc.
157 std::string label_to_use = (tooltip && tooltip->text) ? tooltip->text : ""; 112 std::string label_to_use;
158 if (label_to_use.empty()) { 113 if (!ibus_prop.tooltip().empty())
159 // Usually tooltips are more descriptive than labels. 114 label_to_use = ibus_prop.tooltip();
160 label_to_use = (label && label->text) ? label->text : ""; 115 else if (!ibus_prop.label().empty())
161 } 116 label_to_use = ibus_prop.label();
162 if (label_to_use.empty()) { 117 else
163 DVLOG(1) << "The tooltip and label are both empty. Use " << key; 118 label_to_use = ibus_prop.key();
164 label_to_use = Or(key, "");
165 }
166 119
167 out_prop_list->push_back(InputMethodProperty(key, 120 out_prop_list->push_back(InputMethodProperty(
168 label_to_use, 121 ibus_prop.key(),
169 is_selection_item, 122 label_to_use,
170 is_selection_item_checked)); 123 (type == ibus::IBusProperty::IBUS_PROPERTY_TYPE_RADIO),
124 ibus_prop.checked()));
171 return true; 125 return true;
172 } 126 }
173 127
174 // Converts |ibus_prop| to |out_prop_list|. Please note that |ibus_prop| 128 // Converts |ibus_prop| to |out_prop_list|. Please note that |ibus_prop|
175 // may or may not have children. See the comment for FlattenPropertyList 129 // may or may not have children. See the comment for FlattenPropertyList
176 // for details. Returns true if no error is found. 130 // for details. Returns true if no error is found.
177 bool FlattenProperty(IBusProperty* ibus_prop, 131 bool FlattenProperty(const ibus::IBusProperty& ibus_prop,
178 InputMethodPropertyList* out_prop_list) { 132 InputMethodPropertyList* out_prop_list) {
179 DCHECK(ibus_prop);
180 DCHECK(out_prop_list); 133 DCHECK(out_prop_list);
181 134
182 const gchar* key = ibus_property_get_key(ibus_prop);
183
184 // Filter out unnecessary properties. 135 // Filter out unnecessary properties.
185 if (PropertyKeyIsBlacklisted(key)) 136 if (PropertyKeyIsBlacklisted(ibus_prop.key()))
186 return true; 137 return true;
187 138
188 // Convert |prop| to InputMethodProperty and push it to |out_prop_list|. 139 // Convert |prop| to InputMethodProperty and push it to |out_prop_list|.
189 if (!ConvertProperty(ibus_prop, out_prop_list)) 140 if (!ConvertProperty(ibus_prop, out_prop_list))
190 return false; 141 return false;
191 142
192 // Process childrens iteratively (if any). Push all sub properties to the 143 // Process childrens iteratively (if any). Push all sub properties to the
193 // stack. 144 // stack.
194 if (PropertyHasChildren(ibus_prop)) { 145 if (!ibus_prop.sub_properties().empty()) {
195 for (int i = 0;; ++i) { 146 const ibus::IBusPropertyList& sub_props = ibus_prop.sub_properties();
196 IBusProperty* sub_prop = 147 for (size_t i = 0; i < sub_props.size(); ++i) {
197 ibus_prop_list_get(ibus_property_get_sub_props(ibus_prop), i); 148 if (!FlattenProperty(*sub_props[i], out_prop_list))
198 if (!sub_prop)
199 break;
200 if (!FlattenProperty(sub_prop, out_prop_list))
201 return false; 149 return false;
202 } 150 }
203 } 151 }
204 return true; 152 return true;
205 } 153 }
206 154
207 // Converts IBus representation of a property list, |ibus_prop_list| to our 155 // Converts IBus representation of a property list, |ibus_prop_list| to our
208 // own. This function also flatten the original list (actually it's a tree). 156 // own. This function also flatten the original list (actually it's a tree).
209 // Returns true if no error is found. The conversion to our own type is 157 // Returns true if no error is found. The conversion to our own type is
210 // necessary since our language switcher in Chrome tree don't (or can't) know 158 // necessary since our language switcher in Chrome tree don't (or can't) know
211 // IBus types. Here is an example: 159 // IBus types. Here is an example:
212 // 160 //
213 // ====================================================================== 161 // ======================================================================
214 // Input: 162 // Input:
215 // 163 //
216 // --- Item-1 164 // --- Item-1
217 // |- Item-2 165 // |- Item-2
218 // |- SubMenuRoot --- Item-3-1 166 // |- SubMenuRoot --- Item-3-1
219 // | |- Item-3-2 167 // | |- Item-3-2
220 // | |- Item-3-3 168 // | |- Item-3-3
221 // |- Item-4 169 // |- Item-4
222 // 170 //
223 // (Note: Item-3-X is a selection item since they're on a sub menu.) 171 // (Note: Item-3-X is a selection item since they're on a sub menu.)
224 // 172 //
225 // Output: 173 // Output:
226 // 174 //
227 // Item-1, Item-2, Item-3-1, Item-3-2, Item-3-3, Item-4 175 // Item-1, Item-2, Item-3-1, Item-3-2, Item-3-3, Item-4
228 // (Note: SubMenuRoot does not appear in the output.) 176 // (Note: SubMenuRoot does not appear in the output.)
229 // ====================================================================== 177 // ======================================================================
230 bool FlattenPropertyList(IBusPropList* ibus_prop_list, 178 bool FlattenPropertyList(const ibus::IBusPropertyList& ibus_prop_list,
231 InputMethodPropertyList* out_prop_list) { 179 InputMethodPropertyList* out_prop_list) {
232 DCHECK(ibus_prop_list);
233 DCHECK(out_prop_list); 180 DCHECK(out_prop_list);
234 181
235 IBusProperty* fake_root_prop = ibus_property_new("Dummy.Key", 182 bool result = true;
236 PROP_TYPE_MENU, 183 for (size_t i = 0; i < ibus_prop_list.size(); ++i) {
237 NULL, /* label */ 184 result &= FlattenProperty(*ibus_prop_list[i], out_prop_list);
238 "", /* icon */ 185 }
239 NULL, /* tooltip */
240 FALSE, /* sensitive */
241 FALSE, /* visible */
242 PROP_STATE_UNCHECKED,
243 ibus_prop_list);
244 g_return_val_if_fail(fake_root_prop, false);
245 // Increase the ref count so it won't get deleted when |fake_root_prop|
246 // is deleted.
247 g_object_ref(ibus_prop_list);
248 const bool result = FlattenProperty(fake_root_prop, out_prop_list);
249 g_object_unref(fake_root_prop);
250
251 return result; 186 return result;
252 } 187 }
253 188
254 // Debug print function.
255 const char* PropTypeToString(int prop_type) {
256 switch (static_cast<IBusPropType>(prop_type)) {
257 case PROP_TYPE_NORMAL:
258 return "NORMAL";
259 case PROP_TYPE_TOGGLE:
260 return "TOGGLE";
261 case PROP_TYPE_RADIO:
262 return "RADIO";
263 case PROP_TYPE_MENU:
264 return "MENU";
265 case PROP_TYPE_SEPARATOR:
266 return "SEPARATOR";
267 }
268 return "UNKNOWN";
269 }
270
271 // Debug print function.
272 const char* PropStateToString(int prop_state) {
273 switch (static_cast<IBusPropState>(prop_state)) {
274 case PROP_STATE_UNCHECKED:
275 return "UNCHECKED";
276 case PROP_STATE_CHECKED:
277 return "CHECKED";
278 case PROP_STATE_INCONSISTENT:
279 return "INCONSISTENT";
280 }
281 return "UNKNOWN";
282 }
283
284 // Debug print function.
285 std::string Spacer(int n) {
286 return std::string(n, ' ');
287 }
288
289 std::string PrintPropList(IBusPropList *prop_list, int tree_level);
290
291 // Debug print function.
292 std::string PrintProp(IBusProperty *prop, int tree_level) {
293 if (!prop)
294 return "";
295
296 const IBusPropType type = ibus_property_get_prop_type(prop);
297 const IBusPropState state = ibus_property_get_state(prop);
298 const IBusText* tooltip = ibus_property_get_tooltip(prop);
299 const IBusText* label = ibus_property_get_label(prop);
300 const gchar* key = ibus_property_get_key(prop);
301
302 std::stringstream stream;
303 stream << Spacer(tree_level) << "=========================" << std::endl;
304 stream << Spacer(tree_level) << "key: " << Or(key, "<none>")
305 << std::endl;
306 stream << Spacer(tree_level) << "label: "
307 << ((label && label->text) ? label->text : "<none>")
308 << std::endl;
309 stream << Spacer(tree_level) << "tooptip: "
310 << ((tooltip && tooltip->text)
311 ? tooltip->text : "<none>") << std::endl;
312 stream << Spacer(tree_level) << "sensitive: "
313 << (ibus_property_get_sensitive(prop) ? "YES" : "NO") << std::endl;
314 stream << Spacer(tree_level) << "visible: "
315 << (ibus_property_get_visible(prop) ? "YES" : "NO") << std::endl;
316 stream << Spacer(tree_level) << "type: " << PropTypeToString(type)
317 << std::endl;
318 stream << Spacer(tree_level) << "state: " << PropStateToString(state)
319 << std::endl;
320 stream << Spacer(tree_level) << "sub_props: "
321 << (PropertyHasChildren(prop) ? "" : "<none>") << std::endl;
322 stream << PrintPropList(ibus_property_get_sub_props(prop), tree_level + 1);
323 stream << Spacer(tree_level) << "=========================" << std::endl;
324
325 return stream.str();
326 }
327
328 // Debug print function.
329 std::string PrintPropList(IBusPropList *prop_list, int tree_level) {
330 if (!prop_list)
331 return "";
332
333 std::stringstream stream;
334 for (int i = 0;; ++i) {
335 IBusProperty* prop = ibus_prop_list_get(prop_list, i);
336 if (!prop)
337 break;
338 stream << PrintProp(prop, tree_level);
339 }
340 return stream.str();
341 }
342
343 class IBusAddressWatcher { 189 class IBusAddressWatcher {
344 public: 190 public:
345 class IBusAddressFileWatcherDelegate 191 class IBusAddressFileWatcherDelegate
346 : public base::files::FilePathWatcher::Delegate { 192 : public base::files::FilePathWatcher::Delegate {
347 public: 193 public:
348 IBusAddressFileWatcherDelegate( 194 IBusAddressFileWatcherDelegate(
349 const std::string& ibus_address, 195 const std::string& ibus_address,
350 IBusControllerImpl* controller, 196 IBusControllerImpl* controller,
351 IBusAddressWatcher* watcher) 197 IBusAddressWatcher* watcher)
352 : ibus_address_(ibus_address), 198 : ibus_address_(ibus_address),
353 controller_(controller), 199 controller_(controller),
354 watcher_(watcher) { 200 watcher_(watcher) {
355 DCHECK(watcher); 201 DCHECK(watcher);
356 DCHECK(!ibus_address.empty()); 202 DCHECK(!ibus_address.empty());
357 } 203 }
358 204
359 virtual ~IBusAddressFileWatcherDelegate() {}
360
361 virtual void OnFilePathChanged(const FilePath& file_path) OVERRIDE { 205 virtual void OnFilePathChanged(const FilePath& file_path) OVERRIDE {
362 if (!watcher_->IsWatching()) 206 if (!watcher_->IsWatching())
363 return; 207 return;
364 bool success = content::BrowserThread::PostTask( 208 bool success = content::BrowserThread::PostTask(
365 content::BrowserThread::UI, 209 content::BrowserThread::UI,
366 FROM_HERE, 210 FROM_HERE,
367 base::Bind( 211 base::Bind(
368 &IBusControllerImpl::IBusDaemonInitializationDone, 212 &IBusControllerImpl::IBusDaemonInitializationDone,
369 controller_, 213 controller_,
370 ibus_address_)); 214 ibus_address_));
371 DCHECK(success); 215 DCHECK(success);
372 watcher_->StopSoon(); 216 watcher_->StopSoon();
373 } 217 }
374 218
219 protected:
220 virtual ~IBusAddressFileWatcherDelegate() {}
221
375 private: 222 private:
376 // The ibus-daemon address. 223 // The ibus-daemon address.
377 const std::string ibus_address_; 224 const std::string ibus_address_;
378 IBusControllerImpl* controller_; 225 IBusControllerImpl* controller_;
379 IBusAddressWatcher* watcher_; 226 IBusAddressWatcher* watcher_;
380 227
381 DISALLOW_COPY_AND_ASSIGN(IBusAddressFileWatcherDelegate); 228 DISALLOW_COPY_AND_ASSIGN(IBusAddressFileWatcherDelegate);
382 }; 229 };
383 230
384 static void Start(const std::string& ibus_address, 231 static void Start(const std::string& ibus_address,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 IBusAddressWatcher() 276 IBusAddressWatcher()
430 : watcher_(NULL) {} 277 : watcher_(NULL) {}
431 base::files::FilePathWatcher* watcher_; 278 base::files::FilePathWatcher* watcher_;
432 279
433 DISALLOW_COPY_AND_ASSIGN(IBusAddressWatcher); 280 DISALLOW_COPY_AND_ASSIGN(IBusAddressWatcher);
434 }; 281 };
435 282
436 } // namespace 283 } // namespace
437 284
438 IBusControllerImpl::IBusControllerImpl() 285 IBusControllerImpl::IBusControllerImpl()
439 : ibus_(NULL), 286 : process_handle_(base::kNullProcessHandle),
440 process_handle_(base::kNullProcessHandle),
441 ibus_daemon_status_(IBUS_DAEMON_STOP), 287 ibus_daemon_status_(IBUS_DAEMON_STOP),
442 input_method_(NULL), 288 input_method_(NULL),
443 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { 289 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
444 } 290 }
445 291
446 IBusControllerImpl::~IBusControllerImpl() { 292 IBusControllerImpl::~IBusControllerImpl() {
447 // Disconnect signals so the handler functions will not be called with
448 // |this| which is already freed.
449 if (ibus_) {
450 g_signal_handlers_disconnect_by_func(
451 ibus_,
452 reinterpret_cast<gpointer>(G_CALLBACK(BusConnectedThunk)),
453 this);
454 // Disconnect signals for the panel service as well.
455 // When Chrome is shutting down, g_object_get_data fails and returns NULL.
456 // TODO(nona): Investigate the reason of failure(crosbug.com/129142).
457 void* attached_data = g_object_get_data(G_OBJECT(ibus_), kPanelObjectKey);
458 if (!attached_data)
459 return;
460 if (!G_TYPE_CHECK_INSTANCE_TYPE(attached_data, IBUS_TYPE_PANEL_SERVICE))
461 return;
462 IBusPanelService* ibus_panel_service = IBUS_PANEL_SERVICE(attached_data);
463 if (ibus_panel_service) {
464 g_signal_handlers_disconnect_by_func(
465 ibus_panel_service,
466 reinterpret_cast<gpointer>(G_CALLBACK(RegisterPropertiesThunk)),
467 this);
468 g_signal_handlers_disconnect_by_func(
469 ibus_panel_service,
470 reinterpret_cast<gpointer>(G_CALLBACK(UpdatePropertyThunk)),
471 this);
472 }
473 }
474 } 293 }
475 294
476 bool IBusControllerImpl::Start() { 295 bool IBusControllerImpl::Start() {
477 MaybeInitializeIBusBus();
478 if (IBusConnectionsAreAlive()) 296 if (IBusConnectionsAreAlive())
479 return true; 297 return true;
480 if (ibus_daemon_status_ == IBUS_DAEMON_STOP || 298 if (ibus_daemon_status_ == IBUS_DAEMON_STOP ||
481 ibus_daemon_status_ == IBUS_DAEMON_SHUTTING_DOWN) { 299 ibus_daemon_status_ == IBUS_DAEMON_SHUTTING_DOWN) {
482 return StartIBusDaemon(); 300 return StartIBusDaemon();
483 } 301 }
484 return true; 302 return true;
485 } 303 }
486 304
487 void IBusControllerImpl::Reset() { 305 void IBusControllerImpl::Reset() {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 // 357 //
540 // When |id| and |current_input_method_id_| are the same, the properties 358 // When |id| and |current_input_method_id_| are the same, the properties
541 // shouldn't be cleared. If we do that, something wrong happens in step #4 359 // shouldn't be cleared. If we do that, something wrong happens in step #4
542 // below: 360 // below:
543 // 1. Enable "xkb:us::eng" and "mozc". Switch to "mozc". 361 // 1. Enable "xkb:us::eng" and "mozc". Switch to "mozc".
544 // 2. Focus Omnibox. IME properties for mozc are sent to Chrome. 362 // 2. Focus Omnibox. IME properties for mozc are sent to Chrome.
545 // 3. Switch to "xkb:us::eng". No function in this file is called. 363 // 3. Switch to "xkb:us::eng". No function in this file is called.
546 // 4. Switch back to "mozc". ChangeInputMethod("mozc") is called, but it's 364 // 4. Switch back to "mozc". ChangeInputMethod("mozc") is called, but it's
547 // basically NOP since ibus-daemon's current IME is already "mozc". 365 // basically NOP since ibus-daemon's current IME is already "mozc".
548 // IME properties are not sent to Chrome for the same reason. 366 // IME properties are not sent to Chrome for the same reason.
549 if (id != current_input_method_id_) 367 if (id != current_input_method_id_) {
550 RegisterProperties(NULL, NULL); 368 const ibus::IBusPropertyList empty_list;
369 RegisterProperties(empty_list);
370 }
551 371
552 current_input_method_id_ = id; 372 current_input_method_id_ = id;
553 373
554 if (!IBusConnectionsAreAlive()) { 374 if (!IBusConnectionsAreAlive()) {
555 DVLOG(1) << "ChangeInputMethod: IBus connection is not alive (yet)."; 375 DVLOG(1) << "ChangeInputMethod: IBus connection is not alive (yet).";
556 // |id| will become usable shortly since Start() has already been called. 376 // |id| will become usable shortly since Start() has already been called.
557 // Just return true. 377 // Just return true.
558 } else { 378 } else {
559 SendChangeInputMethodRequest(id); 379 SendChangeInputMethodRequest(id);
560 } 380 }
(...skipping 24 matching lines...) Expand all
585 405
586 IBusInputContextClient* client 406 IBusInputContextClient* client
587 = DBusThreadManager::Get()->GetIBusInputContextClient(); 407 = DBusThreadManager::Get()->GetIBusInputContextClient();
588 if (client) 408 if (client)
589 client->PropertyActivate(key, 409 client->PropertyActivate(key,
590 static_cast<ibus::IBusPropertyState>(is_radio)); 410 static_cast<ibus::IBusPropertyState>(is_radio));
591 return true; 411 return true;
592 } 412 }
593 413
594 bool IBusControllerImpl::IBusConnectionsAreAlive() { 414 bool IBusControllerImpl::IBusConnectionsAreAlive() {
595 return (ibus_daemon_status_ == IBUS_DAEMON_RUNNING) && 415 return ibus_daemon_status_ == IBUS_DAEMON_RUNNING;
596 ibus_ && ibus_bus_is_connected(ibus_);
597 }
598
599 void IBusControllerImpl::MaybeRestoreConnections() {
600 if (IBusConnectionsAreAlive())
601 return;
602 if (IBusConnectionsAreAlive()) {
603 DVLOG(1) << "ibus-daemon and ibus-memconf processes are ready.";
604 ConnectPanelServiceSignals();
605 if (!current_input_method_id_.empty())
606 SendChangeInputMethodRequest(current_input_method_id_);
607 }
608 }
609
610 void IBusControllerImpl::MaybeInitializeIBusBus() {
611 if (ibus_)
612 return;
613
614 ibus_init();
615 // Establish IBus connection between ibus-daemon to change the current input
616 // method engine, properties, and so on.
617 ibus_ = ibus_bus_new();
618 DCHECK(ibus_);
619
620 // Register callback functions for IBusBus signals.
621 ConnectBusSignals();
622
623 if (ibus_bus_is_connected(ibus_)) {
624 DVLOG(1) << "IBus connection is ready: ibus-daemon is already running?";
625 BusConnected(ibus_);
626 }
627 } 416 }
628 417
629 void IBusControllerImpl::SendChangeInputMethodRequest(const std::string& id) { 418 void IBusControllerImpl::SendChangeInputMethodRequest(const std::string& id) {
630 // Change the global engine *asynchronously*. 419 // Change the global engine *asynchronously*.
631 IBusClient* client = DBusThreadManager::Get()->GetIBusClient(); 420 IBusClient* client = DBusThreadManager::Get()->GetIBusClient();
632 if (client) 421 if (client)
633 client->SetGlobalEngine(id.c_str(), base::Bind(&base::DoNothing)); 422 client->SetGlobalEngine(id.c_str(), base::Bind(&base::DoNothing));
634 } 423 }
635 424
636 bool IBusControllerImpl::SetInputMethodConfigInternal( 425 bool IBusControllerImpl::SetInputMethodConfigInternal(
(...skipping 27 matching lines...) Expand all
664 key.second, 453 key.second,
665 value.string_list_value, 454 value.string_list_value,
666 base::Bind(&ConfigSetValueErrorCallback)); 455 base::Bind(&ConfigSetValueErrorCallback));
667 return true; 456 return true;
668 default: 457 default:
669 DVLOG(1) << "SendInputMethodConfig: unknown value.type"; 458 DVLOG(1) << "SendInputMethodConfig: unknown value.type";
670 return false; 459 return false;
671 } 460 }
672 } 461 }
673 462
674 void IBusControllerImpl::ConnectBusSignals() { 463 void IBusControllerImpl::RegisterProperties(
675 if (!ibus_) 464 const ibus::IBusPropertyList& ibus_prop_list) {
676 return;
677
678 // We use g_signal_connect_after here since the callback should be called
679 // *after* the IBusBusDisconnectedCallback in chromeos_input_method_ui.cc
680 // is called. chromeos_input_method_ui.cc attaches the panel service object
681 // to |ibus_|, and the callback in this file use the attached object.
682 g_signal_connect_after(ibus_,
683 "connected",
684 G_CALLBACK(BusConnectedThunk),
685 this);
686 }
687
688 void IBusControllerImpl::ConnectPanelServiceSignals() {
689 if (!ibus_)
690 return;
691
692 IBusPanelService* ibus_panel_service = IBUS_PANEL_SERVICE(
693 g_object_get_data(G_OBJECT(ibus_), kPanelObjectKey));
694 if (!ibus_panel_service) {
695 DVLOG(1) << "IBusPanelService is NOT available.";
696 return;
697 }
698 // We don't _ref() or _weak_ref() the panel service object, since we're not
699 // interested in the life time of the object.
700 g_signal_connect(ibus_panel_service,
701 "register-properties",
702 G_CALLBACK(RegisterPropertiesThunk),
703 this);
704 g_signal_connect(ibus_panel_service,
705 "update-property",
706 G_CALLBACK(UpdatePropertyThunk),
707 this);
708 }
709
710 void IBusControllerImpl::BusConnected(IBusBus* bus) {
711 DVLOG(1) << "IBus connection is established.";
712 MaybeRestoreConnections();
713 }
714
715 void IBusControllerImpl::RegisterProperties(IBusPanelService* panel,
716 IBusPropList* ibus_prop_list) {
717 // Note: |panel| can be NULL. See ChangeInputMethod(). 465 // Note: |panel| can be NULL. See ChangeInputMethod().
718 DVLOG(1) << "RegisterProperties" << (ibus_prop_list ? "" : " (clear)");
719
720 current_property_list_.clear(); 466 current_property_list_.clear();
721 if (ibus_prop_list) { 467 if (!FlattenPropertyList(ibus_prop_list, &current_property_list_))
722 // You can call 468 current_property_list_.clear(); // Clear properties on errors.
723 // DVLOG(1) << "\n" << PrintPropList(ibus_prop_list, 0);
724 // here to dump |ibus_prop_list|.
725 if (!FlattenPropertyList(ibus_prop_list, &current_property_list_)) {
726 // Clear properties on errors.
727 current_property_list_.clear();
728 }
729 }
730 FOR_EACH_OBSERVER(Observer, observers_, PropertyChanged()); 469 FOR_EACH_OBSERVER(Observer, observers_, PropertyChanged());
731 } 470 }
732 471
733 void IBusControllerImpl::UpdateProperty(IBusPanelService* panel, 472 void IBusControllerImpl::UpdateProperty(const ibus::IBusProperty& ibus_prop) {
734 IBusProperty* ibus_prop) {
735 DVLOG(1) << "UpdateProperty";
736 DCHECK(ibus_prop);
737
738 // You can call
739 // DVLOG(1) << "\n" << PrintProp(ibus_prop, 0);
740 // here to dump |ibus_prop|.
741
742 InputMethodPropertyList prop_list; // our representation. 473 InputMethodPropertyList prop_list; // our representation.
743 if (!FlattenProperty(ibus_prop, &prop_list)) { 474 if (!FlattenProperty(ibus_prop, &prop_list)) {
744 // Don't update the UI on errors. 475 // Don't update the UI on errors.
745 DVLOG(1) << "Malformed properties are detected"; 476 DVLOG(1) << "Malformed properties are detected";
746 return; 477 return;
747 } 478 }
748 479
749 // Notify the change. 480 // Notify the change.
750 if (!prop_list.empty()) { 481 if (!prop_list.empty()) {
751 for (size_t i = 0; i < prop_list.size(); ++i) { 482 for (size_t i = 0; i < prop_list.size(); ++i) {
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
854 // Stop() or OnIBusDaemonExit() has already been called. 585 // Stop() or OnIBusDaemonExit() has already been called.
855 return; 586 return;
856 } 587 }
857 chromeos::DBusThreadManager::Get()->InitIBusBus(ibus_address); 588 chromeos::DBusThreadManager::Get()->InitIBusBus(ibus_address);
858 controller->ibus_daemon_status_ = IBUS_DAEMON_RUNNING; 589 controller->ibus_daemon_status_ = IBUS_DAEMON_RUNNING;
859 590
860 ui::InputMethodIBus* input_method_ibus = controller->GetInputMethod(); 591 ui::InputMethodIBus* input_method_ibus = controller->GetInputMethod();
861 DCHECK(input_method_ibus); 592 DCHECK(input_method_ibus);
862 input_method_ibus->OnConnected(); 593 input_method_ibus->OnConnected();
863 594
864 // Restores previous input method at the beggining of connection. 595 DBusThreadManager::Get()->GetIBusPanelService()->SetUpPropertyHandler(
596 controller);
597
598 // Restore previous input method at the beggining of connection.
865 if (!controller->current_input_method_id_.empty()) { 599 if (!controller->current_input_method_id_.empty()) {
866 controller->SendChangeInputMethodRequest( 600 controller->SendChangeInputMethodRequest(
867 controller->current_input_method_id_); 601 controller->current_input_method_id_);
868 } 602 }
869 603
870 DBusThreadManager::Get()->GetIBusConfigClient()->InitializeAsync( 604 DBusThreadManager::Get()->GetIBusConfigClient()->InitializeAsync(
871 base::Bind(&IBusControllerImpl::OnIBusConfigClientInitialized, 605 base::Bind(&IBusControllerImpl::OnIBusConfigClientInitialized,
872 controller->weak_ptr_factory_.GetWeakPtr())); 606 controller->weak_ptr_factory_.GetWeakPtr()));
873 607
874 FOR_EACH_OBSERVER(Observer, controller->observers_, OnConnected()); 608 FOR_EACH_OBSERVER(Observer, controller->observers_, OnConnected());
(...skipping 30 matching lines...) Expand all
905 FOR_EACH_OBSERVER(Observer, controller->observers_, OnDisconnected()); 639 FOR_EACH_OBSERVER(Observer, controller->observers_, OnDisconnected());
906 640
907 if (on_exit_state == IBUS_DAEMON_SHUTTING_DOWN) { 641 if (on_exit_state == IBUS_DAEMON_SHUTTING_DOWN) {
908 // Normal exitting, so do nothing. 642 // Normal exitting, so do nothing.
909 return; 643 return;
910 } 644 }
911 645
912 LOG(ERROR) << "The ibus-daemon crashed. Re-launching..."; 646 LOG(ERROR) << "The ibus-daemon crashed. Re-launching...";
913 controller->StartIBusDaemon(); 647 controller->StartIBusDaemon();
914 } 648 }
915 #endif // defined(HAVE_IBUS)
916 649
917 // static 650 // static
918 bool IBusControllerImpl::FindAndUpdatePropertyForTesting( 651 bool IBusControllerImpl::FindAndUpdatePropertyForTesting(
919 const chromeos::input_method::InputMethodProperty& new_prop, 652 const chromeos::input_method::InputMethodProperty& new_prop,
920 chromeos::input_method::InputMethodPropertyList* prop_list) { 653 chromeos::input_method::InputMethodPropertyList* prop_list) {
921 return FindAndUpdateProperty(new_prop, prop_list); 654 return FindAndUpdateProperty(new_prop, prop_list);
922 } 655 }
923 656
924 } // namespace input_method 657 } // namespace input_method
925 } // namespace chromeos 658 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/input_method/ibus_controller_impl.h ('k') | chrome/browser/chromeos/input_method/ibus_ui_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698