Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/cpp/imehandler/linux/src/ibushandler.cpp
2868 views
1
/*
2
Copyright 2011 WebDriver committers
3
Copyright 2011 Google Inc.
4
5
Licensed under the Apache License, Version 2.0 (the "License");
6
you may not use this file except in compliance with the License.
7
You may obtain a copy of the License at
8
9
http://www.apache.org/licenses/LICENSE-2.0
10
11
Unless required by applicable law or agreed to in writing, software
12
distributed under the License is distributed on an "AS IS" BASIS,
13
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
See the License for the specific language governing permissions and
15
limitations under the License.
16
17
Author: [email protected]
18
*/
19
20
#include <ibus.h>
21
#include <gtk/gtk.h>
22
#include <assert.h>
23
24
// Note: should be included after including ibus. because ibus
25
// typedefs IBusBus rather than declare it as a class, so
26
// forward declaration is tricky.
27
#include "ibushandler.h"
28
29
#include <string>
30
#include <vector>
31
#include <algorithm>
32
33
34
35
/*
36
* Initialize ibus and assures it is connected.
37
*/
38
IBusHandler::IBusHandler() : bus_(NULL), ibus_available_(false) {
39
const gchar* ibus_address = ibus_get_address();
40
// The ibus_available_ field indicates whether ibus is available
41
// or not. Attempt to determine this by getting the address of
42
// the ibus engine. If it's null then no engine is running.
43
if (ibus_address == NULL) {
44
ibus_available_ = false;
45
} else {
46
ibus_init();
47
bus_ = ibus_bus_new();
48
assert(ibus_bus_is_connected(bus_));
49
ibus_available_ = true;
50
}
51
}
52
53
IBusHandler::~IBusHandler() {
54
}
55
56
/*
57
* Returns the name of the global engine currently set.
58
*/
59
std::string IBusHandler::GetActiveEngine() const {
60
std::string engine_name = "";
61
62
if (! ibus_available_) {
63
return engine_name;
64
}
65
66
// Get the descriptor of the current global engine.
67
IBusEngineDesc* desc = ibus_bus_get_global_engine(bus_);
68
if (desc) {
69
// We copy the name of the global engine.
70
engine_name = std::string(desc->name);
71
g_object_unref(desc);
72
}
73
return engine_name;
74
}
75
76
/*
77
* Get the current input context for the current bus connection.
78
*/
79
IBusInputContext* IBusHandler::GetCurrentInputContext() const {
80
gchar* context_name = ibus_bus_current_input_context(bus_);
81
if (context_name == NULL) {
82
// This happens on systems where ibus-gtk integration is not properly
83
// installed (most notably with 32-bit Firefox on a 64-bit machine).
84
// return NULL context so the library can gracefully return false.
85
return NULL;
86
}
87
88
IBusConnection* conn = ibus_bus_get_connection(bus_);
89
assert(conn != NULL);
90
IBusInputContext* context = ibus_input_context_get_input_context(
91
context_name, conn);
92
// We don't need the context name anymore, we have to release it.
93
g_free(context_name);
94
return context;
95
}
96
97
/*
98
* returns true if IME input is active, false otherwise.
99
*/
100
bool IBusHandler::IsActivated() const {
101
if (! ibus_available_) {
102
return false;
103
}
104
105
IBusInputContext* context = GetCurrentInputContext();
106
if(context == NULL) {
107
return false;
108
}
109
110
return ibus_input_context_is_enabled(context);
111
};
112
113
/*
114
* Deactivates the current input context, hence switching back to the previous
115
* engine before activation.
116
*/
117
void IBusHandler::Deactivate() {
118
if (! ibus_available_) {
119
return;
120
}
121
122
IBusInputContext* context = GetCurrentInputContext();
123
if(context == NULL) {
124
return;
125
}
126
127
ibus_input_context_disable(context);
128
}
129
130
/*
131
* Returns the names of all the available engines in the system.
132
*/
133
std::vector<std::string> IBusHandler::GetAvailableEngines() const {
134
std::vector<std::string> loaded_engines;
135
136
if (! ibus_available_) {
137
return loaded_engines;
138
}
139
140
GList* engines = ibus_bus_list_engines(bus_);
141
if (engines == NULL) {
142
// No engines available.
143
return loaded_engines;
144
}
145
146
for (GList* engine = g_list_first(engines); engine != NULL ;
147
engine = g_list_next(engine)) {
148
IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data);
149
loaded_engines.push_back(desc->name);
150
g_object_unref(desc);
151
}
152
153
g_list_free(engines);
154
return loaded_engines;
155
}
156
157
/*
158
* Returns the names of all the preloaded engines.
159
*/
160
std::vector<std::string> IBusHandler::GetInstalledEngines() const {
161
std::vector<std::string> installed_engines;
162
163
if (! ibus_available_) {
164
return installed_engines;
165
}
166
167
GList* engines = ibus_bus_list_active_engines(bus_);
168
if (engines == NULL) {
169
// No engines available.
170
return installed_engines;
171
}
172
173
for (GList* engine = g_list_first(engines); engine != NULL ;
174
engine = g_list_next(engine)) {
175
IBusEngineDesc* desc = IBUS_ENGINE_DESC (engine->data);
176
installed_engines.push_back(desc->name);
177
g_object_unref(desc);
178
}
179
180
g_list_free(engines);
181
return installed_engines;
182
}
183
184
/*
185
* Sets the engines to be loaded by the ibus daemon, only those set via this
186
* method can be then activated.
187
* Note that there is a slight delay between the configuration values being set
188
* and the actual propagation into the ibus daemon (accessed via bus_ member),
189
* so direct call to GetInstalledEngines just after this method could return
190
* past results for isntance. A 1 second pause (see tests) is generally enough.
191
*/
192
int IBusHandler::LoadEngines(const std::vector<std::string>& engine_names) {
193
int nb_loaded_engines = 0;
194
195
if (! ibus_available_) {
196
return nb_loaded_engines;
197
}
198
199
// We want to avoid strange states where no engines are loaded, hence we
200
// simply ignore the call if an empty vector is passed as parameter.
201
if (!engine_names.empty()) {
202
GValue gvalue = {0};
203
g_value_init(&gvalue, G_TYPE_VALUE_ARRAY);
204
// TODO: Where is the array freed?
205
GValueArray* array = g_value_array_new(engine_names.size());
206
std::vector<std::string> available_engines = GetAvailableEngines();
207
for (std::vector<std::string>::const_iterator it = engine_names.begin() ;
208
it != engine_names.end() ; ++it) {
209
// We load the engines only if they are installed on the system.
210
if (std::find(available_engines.begin(), available_engines.end(), *it) !=
211
available_engines.end()) {
212
GValue array_element = {0};
213
g_value_init(&array_element, G_TYPE_STRING);
214
g_value_set_string(&array_element, it->c_str());
215
g_value_array_append(array, &array_element);
216
++nb_loaded_engines;
217
}
218
}
219
// If we made at least one change, then we override the current
220
// configuration.
221
if (nb_loaded_engines > 0) {
222
g_value_take_boxed(&gvalue, array);
223
IBusConfig* conf = ibus_bus_get_config(bus_);
224
ibus_config_set_value(conf, "general", "preload_engines", &gvalue);
225
}
226
g_value_unset(&gvalue);
227
}
228
return nb_loaded_engines;
229
}
230
231
/*
232
* Sets the engine designed by its name to be the global engine
233
*/
234
bool IBusHandler::ActivateEngine(const std::string& engine_name) {
235
if (! ibus_available_) {
236
return false;
237
}
238
239
bool retval = false;
240
241
std::vector<std::string> available_engines = GetInstalledEngines();
242
// We activate only the engines that were preloaded or loaded by a call to
243
// LoadEngines before to ensure a valid state of the ibus system.
244
if (std::find(available_engines.begin(), available_engines.end(), engine_name)
245
!= available_engines.end()) {
246
retval = ibus_bus_set_global_engine(bus_, engine_name.c_str());
247
}
248
249
IBusInputContext* context = GetCurrentInputContext();
250
if ((retval) && (context != NULL)) {
251
ibus_input_context_enable(context);
252
}
253
254
return retval;
255
}
256
257
/* To use the library with dlopen. */
258
extern "C" {
259
ImeHandler* create() {
260
return new IBusHandler;
261
}
262
263
void destroy(ImeHandler* h) {
264
delete h;
265
}
266
}
267
268