1 /*
2 * Smart Common Input Method
3 *
4 * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
5 *
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307 USA
21 *
22 * $Id: scim_backend.cpp,v 1.38.2.1 2006/09/24 16:00:52 suzhe Exp $
23 *
24 */
25
26 #define Uses_SCIM_FILTER_MANAGER
27 #define Uses_SCIM_BACKEND
28 #define Uses_SCIM_IMENGINE
29 #define Uses_SCIM_IMENGINE_MODULE
30 #define Uses_SCIM_CONFIG_PATH
31 #define Uses_STL_ALGORITHM
32 #include "scim_private.h"
33 #include "scim.h"
34 #include "scim_stl_map.h"
35
36 namespace scim {
37
38 #if SCIM_USE_STL_EXT_HASH_MAP
39 typedef __gnu_cxx::hash_map <String, IMEngineFactoryPointer, scim_hash_string > IMEngineFactoryRepository;
40 #elif SCIM_USE_STL_HASH_MAP
41 typedef std::hash_map <String, IMEngineFactoryPointer, scim_hash_string > IMEngineFactoryRepository;
42 #else
43 typedef std::map <String, IMEngineFactoryPointer> IMEngineFactoryRepository;
44 #endif
45
46 typedef std::vector <IMEngineFactoryPointer> IMEngineFactoryPointerVector;
47
48 class LocaleEqual
49 {
50 String m_lhs;
51 public:
LocaleEqual(const String & lhs)52 LocaleEqual (const String &lhs) : m_lhs (lhs) { }
53
operator ()(const String & rhs) const54 bool operator () (const String &rhs) const {
55 if (m_lhs == rhs) return true;
56 if (scim_get_locale_language (m_lhs) == scim_get_locale_language (rhs) &&
57 scim_get_locale_encoding (m_lhs) == scim_get_locale_encoding (rhs) &&
58 m_lhs.find ('.') != String::npos && rhs.find ('.') != String::npos)
59 return true;
60 return false;
61 }
62 };
63
64 class IMEngineFactoryPointerLess
65 {
66 public:
operator ()(const IMEngineFactoryPointer & lhs,const IMEngineFactoryPointer & rhs) const67 bool operator () (const IMEngineFactoryPointer &lhs, const IMEngineFactoryPointer &rhs) const {
68 return (lhs->get_language () < rhs->get_language ()) ||
69 (lhs->get_language () == rhs->get_language () && lhs->get_name () < rhs->get_name ());
70 }
71 };
72
73 class BackEndBase::BackEndBaseImpl
74 {
75 IMEngineFactoryRepository m_factory_repository;
76 String m_supported_unicode_locales;
77 ConfigPointer m_config;
78
79 public:
BackEndBaseImpl(const ConfigPointer & config)80 BackEndBaseImpl (const ConfigPointer &config)
81 : m_config (config)
82 {
83 String locales;
84
85 // Set the default supported locales.
86 locales = scim_global_config_read (SCIM_GLOBAL_CONFIG_SUPPORTED_UNICODE_LOCALES, String ("en_US.UTF-8"));
87
88 std::vector <String> locale_list;
89 std::vector <String> real_list;
90
91 scim_split_string_list (locale_list, locales);
92
93 for (std::vector <String>::iterator i = locale_list.begin (); i!= locale_list.end (); ++i) {
94 *i = scim_validate_locale (*i);
95 if (i->length () && scim_get_locale_encoding (*i) == "UTF-8" &&
96 std::find_if (real_list.begin (), real_list.end (), LocaleEqual (*i)) == real_list.end ())
97 real_list.push_back (*i);
98 }
99
100 m_supported_unicode_locales = scim_combine_string_list (real_list);
101 }
102
clear()103 void clear ()
104 {
105 m_factory_repository.clear ();
106 }
107
get_all_locales() const108 String get_all_locales () const
109 {
110 String locale;
111
112 std::vector <String> locale_list;
113 std::vector <String> real_list;
114
115 IMEngineFactoryRepository::const_iterator it;
116
117 for (it = m_factory_repository.begin (); it != m_factory_repository.end (); ++it) {
118 if (locale.length () == 0)
119 locale += it->second->get_locales ();
120 else
121 locale += (String (",") + it->second->get_locales ());
122 }
123
124 if (m_supported_unicode_locales.length ())
125 locale += (String (",") + m_supported_unicode_locales);
126
127 scim_split_string_list (locale_list, locale);
128
129 for (std::vector <String>::iterator i = locale_list.begin (); i!= locale_list.end (); i++) {
130 locale = scim_validate_locale (*i);
131 if (locale.length () &&
132 std::find_if (real_list.begin (), real_list.end (), LocaleEqual (locale)) == real_list.end ())
133 real_list.push_back (locale);
134 }
135
136 return scim_combine_string_list (real_list);
137 }
138
get_factory(const String & uuid) const139 IMEngineFactoryPointer get_factory (const String &uuid) const
140 {
141 IMEngineFactoryRepository::const_iterator it = m_factory_repository.find (uuid);
142
143 if (it != m_factory_repository.end ())
144 return it->second;
145
146 return IMEngineFactoryPointer (0);
147 }
148
get_factories_for_encoding(std::vector<IMEngineFactoryPointer> & factories,const String & encoding) const149 uint32 get_factories_for_encoding (std::vector<IMEngineFactoryPointer> &factories,
150 const String &encoding) const
151 {
152 IMEngineFactoryRepository::const_iterator it;
153
154 factories.clear ();
155
156 for (it = m_factory_repository.begin (); it != m_factory_repository.end (); ++it) {
157 if ((encoding.length () == 0 || it->second->validate_encoding (encoding)))
158 factories.push_back (it->second);
159 }
160
161 sort_factories (factories);
162
163 return factories.size ();
164 }
165
get_factories_for_language(std::vector<IMEngineFactoryPointer> & factories,const String & language) const166 uint32 get_factories_for_language (std::vector<IMEngineFactoryPointer> &factories,
167 const String &language) const
168 {
169 IMEngineFactoryRepository::const_iterator it;
170
171 factories.clear ();
172
173 for (it = m_factory_repository.begin (); it != m_factory_repository.end (); ++it) {
174 if ((language.length () == 0 || it->second->get_language () == language))
175 factories.push_back (it->second);
176 }
177
178 sort_factories (factories);
179
180 return factories.size ();
181 }
182
get_default_factory(const String & language,const String & encoding) const183 IMEngineFactoryPointer get_default_factory (const String &language, const String &encoding) const
184 {
185 if (!language.length ()) return IMEngineFactoryPointer ();
186
187 IMEngineFactoryPointerVector factories;
188
189 if (get_factories_for_encoding (factories, encoding) > 0) {
190 IMEngineFactoryPointer lang_first;
191 IMEngineFactoryPointerVector::iterator it;
192
193 String def_uuid;
194
195 def_uuid = m_config->read (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) +
196 String ("/") + language,
197 String (""));
198
199 // Match by Normalized language exactly.
200 for (it = factories.begin (); it != factories.end (); ++it) {
201 if (scim_get_normalized_language ((*it)->get_language ()) == language && lang_first.null ())
202 lang_first = *it;
203
204 if ((*it)->get_uuid () == def_uuid)
205 return *it;
206 }
207
208 if (!lang_first.null ()) return lang_first;
209
210 // Match by short language name.
211 for (it = factories.begin (); it != factories.end (); ++it)
212 if ((*it)->get_language () == language.substr (0,2))
213 return *it;
214
215 return factories [0];
216 }
217
218 return IMEngineFactoryPointer ();
219 }
220
set_default_factory(const String & language,const String & uuid)221 void set_default_factory (const String &language, const String &uuid)
222 {
223 if (!language.length () || !uuid.length ()) return;
224
225 IMEngineFactoryPointerVector factories;
226 if (get_factories_for_encoding (factories, "") > 0) {
227 IMEngineFactoryPointerVector::iterator it;
228 for (it = factories.begin (); it != factories.end (); ++it) {
229 if ((*it)->get_uuid () == uuid) {
230 m_config->write (String (SCIM_CONFIG_DEFAULT_IMENGINE_FACTORY) + String ("/") + language, uuid);
231 return;
232 }
233 }
234 }
235 }
236
get_next_factory(const String & language,const String & encoding,const String & cur_uuid) const237 IMEngineFactoryPointer get_next_factory (const String &language, const String &encoding, const String &cur_uuid) const
238 {
239 IMEngineFactoryPointerVector factories;
240
241 if (get_factories_for_encoding (factories, encoding) > 0) {
242 IMEngineFactoryPointer lang_first;
243 IMEngineFactoryPointerVector::iterator it, itl;
244
245 for (it = factories.begin (); it != factories.end (); ++it) {
246 if ((language.length () == 0 || (*it)->get_language () == language) && lang_first.null ())
247 lang_first = *it;
248
249 if ((*it)->get_uuid () == cur_uuid) {
250 for (itl = it + 1; itl != factories.end (); ++itl) {
251 if (language.length () == 0 || (*itl)->get_language () == language)
252 return *itl;
253 }
254 if (!lang_first.null ()) return lang_first;
255
256 return factories [0];
257 }
258 }
259 }
260
261 return IMEngineFactoryPointer ();
262 }
263
get_previous_factory(const String & language,const String & encoding,const String & cur_uuid) const264 IMEngineFactoryPointer get_previous_factory (const String &language, const String &encoding, const String &cur_uuid) const
265 {
266 IMEngineFactoryPointerVector factories;
267
268 if (get_factories_for_encoding (factories, encoding) > 0) {
269 IMEngineFactoryPointer lang_last;
270 IMEngineFactoryPointerVector::iterator it, itl;
271
272 for (it = factories.begin (); it != factories.end (); ++it) {
273 if ((language.length () == 0 || (*it)->get_language () == language))
274 lang_last = *it;
275 }
276
277 for (it = factories.begin (); it != factories.end (); ++it) {
278 if ((*it)->get_uuid () == cur_uuid) {
279 for (itl = it; itl != factories.begin (); --itl) {
280 if (language.length () == 0 || (*(itl-1))->get_language () == language)
281 return *(itl-1);
282 }
283
284 if (!lang_last.null ()) return lang_last;
285
286 return factories [factories.size () - 1];
287 }
288 }
289 }
290
291 return IMEngineFactoryPointer ();
292 }
293
add_factory(const IMEngineFactoryPointer & factory)294 bool add_factory (const IMEngineFactoryPointer &factory)
295 {
296 if (!factory.null ()) {
297 String uuid = factory->get_uuid ();
298
299 if (uuid.length () && m_factory_repository.find (uuid) == m_factory_repository.end ()) {
300 m_factory_repository [uuid] = factory;
301 return true;
302 }
303 }
304
305 return false;
306 }
307
308 private:
sort_factories(std::vector<IMEngineFactoryPointer> & factories) const309 void sort_factories (std::vector<IMEngineFactoryPointer> &factories) const
310 {
311 std::sort (factories.begin (), factories.end (), IMEngineFactoryPointerLess ());
312 }
313 };
314
BackEndBase(const ConfigPointer & config)315 BackEndBase::BackEndBase (const ConfigPointer &config)
316 : m_impl (new BackEndBase::BackEndBaseImpl (config))
317 {
318 }
319
~BackEndBase()320 BackEndBase::~BackEndBase ()
321 {
322 delete m_impl;
323 }
324
325 String
get_all_locales() const326 BackEndBase::get_all_locales () const
327 {
328 return m_impl->get_all_locales ();
329 }
330
331 IMEngineFactoryPointer
get_factory(const String & uuid) const332 BackEndBase::get_factory (const String &uuid) const
333 {
334 return m_impl->get_factory (uuid);
335 }
336
337 uint32
get_factories_for_encoding(std::vector<IMEngineFactoryPointer> & factories,const String & encoding) const338 BackEndBase::get_factories_for_encoding (std::vector<IMEngineFactoryPointer> &factories, const String &encoding) const
339 {
340 return m_impl->get_factories_for_encoding (factories, encoding);
341 }
342
343 uint32
get_factories_for_language(std::vector<IMEngineFactoryPointer> & factories,const String & language) const344 BackEndBase::get_factories_for_language (std::vector<IMEngineFactoryPointer> &factories, const String &language) const
345 {
346 return m_impl->get_factories_for_language (factories, language);
347 }
348
349 IMEngineFactoryPointer
get_default_factory(const String & language,const String & encoding) const350 BackEndBase::get_default_factory (const String &language, const String &encoding) const
351 {
352 return m_impl->get_default_factory (language, encoding);
353 }
354
355 void
set_default_factory(const String & language,const String & uuid)356 BackEndBase::set_default_factory (const String &language, const String &uuid)
357 {
358 m_impl->set_default_factory (language, uuid);
359 }
360
361 IMEngineFactoryPointer
get_next_factory(const String & language,const String & encoding,const String & cur_uuid) const362 BackEndBase::get_next_factory (const String &language, const String &encoding, const String &cur_uuid) const
363 {
364 return m_impl->get_next_factory (language, encoding, cur_uuid);
365 }
366
367 IMEngineFactoryPointer
get_previous_factory(const String & language,const String & encoding,const String & cur_uuid) const368 BackEndBase::get_previous_factory (const String &language, const String &encoding, const String &cur_uuid) const
369 {
370 return m_impl->get_previous_factory (language, encoding, cur_uuid);
371 }
372
373 bool
add_factory(const IMEngineFactoryPointer & factory)374 BackEndBase::add_factory (const IMEngineFactoryPointer &factory)
375 {
376 return m_impl->add_factory (factory);
377 }
378
379 void
clear()380 BackEndBase::clear ()
381 {
382 m_impl->clear ();
383 }
384
385 // Implementation of CommonBackEnd.
386 struct CommonBackEnd::CommonBackEndImpl {
387 IMEngineModule *m_engine_modules;
388 FilterManager *m_filter_manager;
389
CommonBackEndImplscim::CommonBackEnd::CommonBackEndImpl390 CommonBackEndImpl () : m_engine_modules (0), m_filter_manager (0) { }
391 };
392
CommonBackEnd(const ConfigPointer & config,const std::vector<String> & modules)393 CommonBackEnd::CommonBackEnd (const ConfigPointer &config,
394 const std::vector<String> &modules)
395 : BackEndBase (config),
396 m_impl (new CommonBackEndImpl)
397 {
398 IMEngineFactoryPointer factory;
399 std::vector<String> disabled_factories;
400 std::vector<String> new_modules = modules;
401
402 int all_factories_count = 0;
403 int module_factories_count = 0;
404
405 if (config.null ()) return;
406
407 // Get disabled factories list.
408 disabled_factories = scim_global_config_read (SCIM_GLOBAL_CONFIG_DISABLED_IMENGINE_FACTORIES, disabled_factories);
409
410 // Put socket module to the end of list.
411 for (std::vector<String>::iterator it = new_modules.begin (); it != new_modules.end (); ++it) {
412 if (*it == "socket") {
413 new_modules.erase (it);
414 new_modules.push_back ("socket");
415 break;
416 }
417 }
418
419 // Try to load all IMEngine modules
420 try {
421 m_impl->m_engine_modules = new IMEngineModule [new_modules.size ()];
422 m_impl->m_filter_manager = new FilterManager (config);
423 } catch (const std::exception & err) {
424 std::cerr << err.what () << "\n";
425 return;
426 }
427
428 //load IMEngine modules
429 for (size_t i = 0; i < new_modules.size (); ++i) {
430 SCIM_DEBUG_BACKEND (1) << "Loading IMEngine module: " << new_modules [i] << " ...\n";
431
432 module_factories_count = 0;
433
434 if (m_impl->m_engine_modules [i].load (new_modules [i], config) &&
435 m_impl->m_engine_modules [i].valid ()) {
436 for (size_t j=0; j < m_impl->m_engine_modules [i].number_of_factories (); ++j) {
437
438 // Try to load a IMEngine Factory.
439 try {
440 factory = m_impl->m_engine_modules [i].create_factory (j);
441 } catch (const std::exception & err) {
442 std::cerr << err.what () << "\n";
443 factory.reset ();
444 }
445
446 if (!factory.null ()) {
447 // Check if it's disabled.
448 if (std::find (disabled_factories.begin (),
449 disabled_factories.end (),
450 factory->get_uuid ()) == disabled_factories.end ()) {
451
452 // Add it into disabled list to prevent from loading again.
453 disabled_factories.push_back (factory->get_uuid ());
454
455 // Only load filter for none socket IMEngines.
456 if (new_modules [i] != "socket")
457 factory = m_impl->m_filter_manager->attach_filters_to_factory (factory);
458
459 add_factory (factory);
460
461 all_factories_count ++;
462 module_factories_count ++;
463
464 SCIM_DEBUG_BACKEND (1) << " Loading IMEngine Factory " << j << " : " << "OK\n";
465 } else {
466 SCIM_DEBUG_BACKEND (1) << " Loading IMEngine Factory " << j << " : " << "Disabled\n";
467 factory.reset ();
468 }
469 } else {
470 SCIM_DEBUG_BACKEND (1) << " Loading IMEngine Factory " << j << " : " << "Failed\n";
471 }
472 }
473 if (module_factories_count) {
474 SCIM_DEBUG_BACKEND (1) << new_modules [i] << " IMEngine module is successfully loaded.\n";
475 } else {
476 SCIM_DEBUG_BACKEND (1) << "No Factory loaded from " << new_modules [i] << " IMEngine module!\n";
477 m_impl->m_engine_modules [i].unload ();
478 }
479 } else {
480 SCIM_DEBUG_BACKEND (1) << "Failed to load " << new_modules [i] << " IMEngine module.\n";
481 }
482 }
483
484 factory = new ComposeKeyFactory ();
485
486 if (all_factories_count == 0 ||
487 std::find (disabled_factories.begin (),
488 disabled_factories.end (),
489 factory->get_uuid ()) == disabled_factories.end ()) {
490 factory = m_impl->m_filter_manager->attach_filters_to_factory (factory);
491 add_factory (factory);
492 }
493 }
494
~CommonBackEnd()495 CommonBackEnd::~CommonBackEnd ()
496 {
497 clear ();
498
499 delete [] m_impl->m_engine_modules;
500 delete m_impl->m_filter_manager;
501 delete m_impl;
502 }
503
504
505 } // namespace scim
506
507 /*
508 vi:ts=4:nowrap:ai:expandtab
509 */
510