aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/modules/immodules/scim/scim_imcontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ecore/src/modules/immodules/scim/scim_imcontext.cpp')
-rw-r--r--libraries/ecore/src/modules/immodules/scim/scim_imcontext.cpp2839
1 files changed, 2839 insertions, 0 deletions
diff --git a/libraries/ecore/src/modules/immodules/scim/scim_imcontext.cpp b/libraries/ecore/src/modules/immodules/scim/scim_imcontext.cpp
new file mode 100644
index 0000000..6cb72c2
--- /dev/null
+++ b/libraries/ecore/src/modules/immodules/scim/scim_imcontext.cpp
@@ -0,0 +1,2839 @@
1#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4
5#define Uses_SCIM_DEBUG
6#define Uses_SCIM_BACKEND
7#define Uses_SCIM_IMENGINE_MODULE
8#define Uses_SCIM_HOTKEY
9#define Uses_SCIM_PANEL_CLIENT
10
11#include <sys/types.h>
12#include <sys/wait.h>
13#include <sys/time.h>
14#include <sys/times.h>
15#include <unistd.h>
16#include <pthread.h>
17#include <Ecore_Evas.h>
18#include <Ecore_X.h>
19#include <Ecore.h>
20#include <Evas.h>
21
22#include <X11/Xlib.h>
23#include <X11/keysym.h>
24#include <X11/Xutil.h>
25
26#include <scim.h>
27#include "scim_imcontext.h"
28
29using namespace scim;
30
31struct _EcoreIMFContextISFImpl
32{
33 EcoreIMFContextISF *parent;
34 IMEngineInstancePointer si;
35 Ecore_X_Window client_window;
36 Evas *client_canvas;
37 Ecore_IMF_Input_Mode input_mode;
38 WideString preedit_string;
39 AttributeList preedit_attrlist;
40 Ecore_IMF_Autocapital_Type autocapital_type;
41 int preedit_caret;
42 int cursor_x;
43 int cursor_y;
44 int cursor_pos;
45 bool use_preedit;
46 bool is_on;
47 bool shared_si;
48 bool preedit_started;
49 bool preedit_updating;
50 bool need_commit_preedit;
51 bool uppercase;
52 bool prediction_allow;
53
54 EcoreIMFContextISFImpl *next;
55};
56
57/* Input Context handling functions. */
58static EcoreIMFContextISFImpl *new_ic_impl (EcoreIMFContextISF *parent);
59static void delete_ic_impl (EcoreIMFContextISFImpl *impl);
60static void delete_all_ic_impl (void);
61
62static EcoreIMFContextISF *find_ic (int id);
63
64
65/* private functions */
66static void panel_slot_reload_config (int context);
67static void panel_slot_exit (int context);
68static void panel_slot_update_lookup_table_page_size(int context,
69 int page_size);
70static void panel_slot_lookup_table_page_up (int context);
71static void panel_slot_lookup_table_page_down (int context);
72static void panel_slot_trigger_property (int context,
73 const String &property);
74static void panel_slot_process_helper_event (int context,
75 const String &target_uuid,
76 const String &helper_uuid,
77 const Transaction &trans);
78static void panel_slot_move_preedit_caret (int context,
79 int caret_pos);
80static void panel_slot_select_candidate (int context,
81 int cand_index);
82static void panel_slot_process_key_event (int context,
83 const KeyEvent &key);
84static void panel_slot_commit_string (int context,
85 const WideString &wstr);
86static void panel_slot_forward_key_event (int context,
87 const KeyEvent &key);
88static void panel_slot_request_help (int context);
89static void panel_slot_request_factory_menu (int context);
90static void panel_slot_change_factory (int context,
91 const String &uuid);
92
93static void panel_req_focus_in (EcoreIMFContextISF *ic);
94static void panel_req_update_factory_info (EcoreIMFContextISF *ic);
95static void panel_req_update_spot_location (EcoreIMFContextISF *ic);
96static void panel_req_show_help (EcoreIMFContextISF *ic);
97static void panel_req_show_factory_menu (EcoreIMFContextISF *ic);
98
99/* Panel iochannel handler*/
100static bool panel_initialize (void);
101static void panel_finalize (void);
102static Eina_Bool panel_iochannel_handler (void *data,
103 Ecore_Fd_Handler *fd_handler);
104
105/* utility functions */
106static bool filter_hotkeys (EcoreIMFContextISF *ic,
107 const KeyEvent &key);
108static void turn_on_ic (EcoreIMFContextISF *ic);
109static void turn_off_ic (EcoreIMFContextISF *ic);
110static void set_ic_capabilities (EcoreIMFContextISF *ic);
111
112static void initialize (void);
113static void finalize (void);
114
115static void open_next_factory (EcoreIMFContextISF *ic);
116static void open_previous_factory (EcoreIMFContextISF *ic);
117static void open_specific_factory (EcoreIMFContextISF *ic,
118 const String &uuid);
119static void initialize_modifier_bits (Display *display);
120static unsigned int scim_x11_keymask_scim_to_x11 (Display *display, uint16 scimkeymask);
121static XKeyEvent createKeyEvent (Display *display, Window &win,
122 Window &winRoot, bool press,
123 int keycode, int modifiers);
124static void _x_send_key_event (const KeyEvent &key);
125
126static void attach_instance (const IMEngineInstancePointer &si);
127
128/* slot functions */
129static void slot_show_preedit_string (IMEngineInstanceBase *si);
130static void slot_show_aux_string (IMEngineInstanceBase *si);
131static void slot_show_lookup_table (IMEngineInstanceBase *si);
132
133static void slot_hide_preedit_string (IMEngineInstanceBase *si);
134static void slot_hide_aux_string (IMEngineInstanceBase *si);
135static void slot_hide_lookup_table (IMEngineInstanceBase *si);
136
137static void slot_update_preedit_caret (IMEngineInstanceBase *si,
138 int caret);
139static void slot_update_preedit_string (IMEngineInstanceBase *si,
140 const WideString &str,
141 const AttributeList &attrs);
142static void slot_update_aux_string (IMEngineInstanceBase *si,
143 const WideString &str,
144 const AttributeList &attrs);
145static void slot_commit_string (IMEngineInstanceBase *si,
146 const WideString &str);
147static void slot_forward_key_event (IMEngineInstanceBase *si,
148 const KeyEvent &key);
149static void slot_update_lookup_table (IMEngineInstanceBase *si,
150 const LookupTable &table);
151
152static void slot_register_properties (IMEngineInstanceBase *si,
153 const PropertyList &properties);
154static void slot_update_property (IMEngineInstanceBase *si,
155 const Property &property);
156static void slot_beep (IMEngineInstanceBase *si);
157static void slot_start_helper (IMEngineInstanceBase *si,
158 const String &helper_uuid);
159static void slot_stop_helper (IMEngineInstanceBase *si,
160 const String &helper_uuid);
161static void slot_send_helper_event (IMEngineInstanceBase *si,
162 const String &helper_uuid,
163 const Transaction &trans);
164static bool slot_get_surrounding_text (IMEngineInstanceBase *si,
165 WideString &text,
166 int &cursor,
167 int maxlen_before,
168 int maxlen_after);
169static bool slot_delete_surrounding_text (IMEngineInstanceBase *si,
170 int offset,
171 int len);
172
173static void reload_config_callback (const ConfigPointer &config);
174
175static void fallback_commit_string_cb (IMEngineInstanceBase *si,
176 const WideString &str);
177
178static void caps_mode_check (Ecore_IMF_Context *ctx, Eina_Bool force);
179
180/* Local variables declaration */
181static String _language;
182static EcoreIMFContextISFImpl *_used_ic_impl_list = 0;
183static EcoreIMFContextISFImpl *_free_ic_impl_list = 0;
184static EcoreIMFContextISF *_ic_list = 0;
185
186static KeyboardLayout _keyboard_layout = SCIM_KEYBOARD_Default;
187static int _valid_key_mask = SCIM_KEY_AllMasks;
188
189static FrontEndHotkeyMatcher _frontend_hotkey_matcher;
190static IMEngineHotkeyMatcher _imengine_hotkey_matcher;
191
192static IMEngineInstancePointer _default_instance;
193
194static ConfigModule *_config_module = 0;
195static ConfigPointer _config;
196static BackEndPointer _backend;
197
198static EcoreIMFContextISF *_focused_ic = 0;
199
200static bool _scim_initialized = false;
201
202static int _instance_count = 0;
203static int _context_count = 0;
204
205static IMEngineFactoryPointer _fallback_factory;
206static IMEngineInstancePointer _fallback_instance;
207static PanelClient _panel_client;
208
209static Ecore_Fd_Handler *_panel_iochannel_read_handler = 0;
210static Ecore_Fd_Handler *_panel_iochannel_err_handler = 0;
211
212static Ecore_X_Window _client_window = 0;
213
214static bool _on_the_spot = true;
215static bool _shared_input_method = false;
216
217static Eina_Bool autocap_allow = EINA_FALSE;
218
219static Display *__current_display = 0;
220static int __current_alt_mask = Mod1Mask;
221static int __current_meta_mask = 0;
222static int __current_super_mask = 0;
223static int __current_hyper_mask = 0;
224static int __current_numlock_mask = Mod2Mask;
225
226// A hack to shutdown the immodule cleanly even if im_module_exit () is not called when exiting.
227class FinalizeHandler
228{
229public:
230 FinalizeHandler ()
231 {
232 SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::FinalizeHandler ()\n";
233 }
234 ~FinalizeHandler ()
235 {
236 SCIM_DEBUG_FRONTEND(1) << "FinalizeHandler::~FinalizeHandler ()\n";
237 isf_imf_context_shutdown ();
238 }
239};
240
241static FinalizeHandler _finalize_handler;
242
243static unsigned int
244utf8_offset_to_index(const char *str, int offset)
245{
246 int index = 0;
247 int i;
248 for (i = 0; i < offset; i++)
249 {
250 eina_unicode_utf8_get_next(str, &index);
251 }
252
253 return index;
254}
255
256static unsigned int
257get_time (void)
258{
259 unsigned int tint;
260 struct timeval tv;
261 struct timezone tz; /* is not used since ages */
262 gettimeofday (&tv, &tz);
263 tint = tv.tv_sec * 1000;
264 tint = tint / 1000 * 1000;
265 tint = tint + tv.tv_usec / 1000;
266 return tint;
267}
268
269/* Function Implementations */
270static EcoreIMFContextISFImpl *
271new_ic_impl (EcoreIMFContextISF *parent)
272{
273 EcoreIMFContextISFImpl *impl = NULL;
274
275 if (_free_ic_impl_list != NULL)
276 {
277 impl = _free_ic_impl_list;
278 _free_ic_impl_list = _free_ic_impl_list->next;
279 }
280 else
281 {
282 impl = new EcoreIMFContextISFImpl;
283 if (impl == NULL)
284 return NULL;
285 }
286
287 impl->uppercase = false;
288 impl->autocapital_type = ECORE_IMF_AUTOCAPITAL_TYPE_NONE;
289 impl->next = _used_ic_impl_list;
290 _used_ic_impl_list = impl;
291
292 impl->parent = parent;
293
294 return impl;
295}
296
297static void
298delete_ic_impl (EcoreIMFContextISFImpl *impl)
299{
300 EcoreIMFContextISFImpl *rec = _used_ic_impl_list, *last = 0;
301
302 for (; rec != 0; last = rec, rec = rec->next)
303 {
304 if (rec == impl)
305 {
306 if (last != 0)
307 last->next = rec->next;
308 else
309 _used_ic_impl_list = rec->next;
310
311 rec->next = _free_ic_impl_list;
312 _free_ic_impl_list = rec;
313
314 rec->parent = 0;
315 rec->si.reset ();
316 rec->client_window = 0;
317 rec->preedit_string = WideString ();
318 rec->preedit_attrlist.clear ();
319
320 return;
321 }
322 }
323}
324
325static void
326delete_all_ic_impl (void)
327{
328 EcoreIMFContextISFImpl *it = _used_ic_impl_list;
329
330 while (it != 0)
331 {
332 _used_ic_impl_list = it->next;
333 delete it;
334 it = _used_ic_impl_list;
335 }
336
337 it = _free_ic_impl_list;
338 while (it != 0)
339 {
340 _free_ic_impl_list = it->next;
341 delete it;
342 it = _free_ic_impl_list;
343 }
344}
345
346static EcoreIMFContextISF *
347find_ic (int id)
348{
349 EcoreIMFContextISFImpl *rec = _used_ic_impl_list;
350
351 while (rec != 0)
352 {
353 if (rec->parent && rec->parent->id == id)
354 return rec->parent;
355 rec = rec->next;
356 }
357
358 return 0;
359}
360
361static Eina_Bool
362analyze_surrounding_text(Ecore_IMF_Context *ctx)
363{
364 char *plain_str = NULL;
365 char *markup_str = NULL;
366 const char *puncs[3] = {". ", "! ", "? "};
367 Eina_Bool ret = EINA_FALSE;
368 int cursor_pos = 0;
369 int i = 0;
370 Eina_Unicode *tail = NULL;
371 Eina_Unicode *ustr = NULL;
372 Eina_Unicode *uni_puncs[3];
373 EcoreIMFContextISF *context_scim;
374
375 if (!ctx) return EINA_FALSE;
376 context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
377 if (!context_scim || !context_scim->impl) return EINA_FALSE;
378
379 switch (context_scim->impl->autocapital_type)
380 {
381 case ECORE_IMF_AUTOCAPITAL_TYPE_NONE:
382 return EINA_FALSE;
383 case ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER:
384 return EINA_TRUE;
385 default:
386 break;
387 }
388
389 for (i=0; i<3; i++)
390 uni_puncs[i] = eina_unicode_utf8_to_unicode(puncs[i], NULL);
391
392 ecore_imf_context_surrounding_get(ctx, &markup_str, &cursor_pos);
393 if (!markup_str) goto done;
394
395 if (cursor_pos == 0)
396 {
397 ret = EINA_TRUE;
398 goto done;
399 }
400
401 // Convert into plain string
402 plain_str = evas_textblock_text_markup_to_utf8(NULL, markup_str);
403 if (!plain_str) goto done;
404
405 // Convert string from utf8 to unicode
406 ustr = eina_unicode_utf8_to_unicode(plain_str, NULL);
407 if (!ustr) goto done;
408
409 if (cursor_pos >= 1)
410 {
411 if (context_scim->impl->autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_WORD)
412 {
413 if (ustr[cursor_pos-1] == ' ')
414 {
415 ret = EINA_TRUE;
416 goto done;
417 }
418 }
419
420 // Check paragraph separator <PS> and carrage return <br>
421 if ((ustr[cursor_pos-1] == 0x2029) || (ustr[cursor_pos-1] == '\n'))
422 {
423 ret = EINA_TRUE;
424 goto done;
425 }
426 }
427
428 // check punctuation
429 if (cursor_pos >= 2)
430 {
431 tail = eina_unicode_strndup(ustr+cursor_pos-2, 2);
432
433 if (tail)
434 {
435 for (i=0; i<3; i++)
436 {
437 if (!eina_unicode_strcmp(tail, uni_puncs[i]))
438 {
439 ret = EINA_TRUE;
440 break;
441 }
442 }
443 free(tail);
444 tail = NULL;
445 }
446 }
447
448done:
449 if (ustr) free(ustr);
450 if (markup_str) free(markup_str);
451 if (plain_str) free(plain_str);
452
453 for (i=0; i<3; i++)
454 if (uni_puncs[i]) free(uni_puncs[i]);
455
456 return ret;
457}
458
459static void
460caps_mode_check(Ecore_IMF_Context *ctx, Eina_Bool force)
461{
462 Eina_Bool uppercase;
463 EcoreIMFContextISF *context_scim;
464
465 if (!ctx) return;
466 context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
467
468 if (autocap_allow == EINA_FALSE)
469 return;
470
471 // Check autocapital type
472 if (!context_scim || !context_scim->impl)
473 return;
474
475 if (analyze_surrounding_text(ctx))
476 uppercase = EINA_TRUE;
477 else
478 uppercase = EINA_FALSE;
479
480 if (force)
481 context_scim->impl->uppercase = uppercase;
482 else
483 if (context_scim->impl->uppercase != uppercase)
484 context_scim->impl->uppercase = uppercase;
485}
486
487static void
488feed_key_event (Evas *evas, const char *str, Eina_Bool fake)
489{
490 char key_string[128] = {0};
491 unsigned int timestamp = 0;
492
493 if (!fake)
494 timestamp = get_time ();
495
496 if (strncmp (str, "KeyRelease+", 11) == 0)
497 {
498 strncpy(key_string, str + 11, strlen(str)-11);
499 evas_event_feed_key_up (evas, key_string, key_string, NULL, NULL, timestamp, NULL);
500 SCIM_DEBUG_FRONTEND(1) << " evas_event_feed_key_up ()...\n";
501 }
502 else
503 {
504 strncpy(key_string, str, strlen(str));
505 evas_event_feed_key_down (evas, key_string, key_string, NULL, NULL, timestamp, NULL);
506 SCIM_DEBUG_FRONTEND(1) << " evas_event_feed_key_down ()...\n";
507 }
508}
509
510/* Public functions */
511/**
512 * isf_imf_context_new
513 *
514 * This function will be called by Ecore IMF.
515 * Create a instance of type EcoreIMFContextISF.
516 *
517 * Return value: A pointer to the newly created EcoreIMFContextISF instance
518 */
519EAPI EcoreIMFContextISF *
520isf_imf_context_new (void)
521{
522 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
523 char *env;
524
525 Ecore_X_Display *display = ecore_x_display_get ();
526 if (!display)
527 {
528 std::cerr << "ecore_x_display_get () failed !!!";
529 return NULL;
530 }
531
532 EcoreIMFContextISF *context_scim = new EcoreIMFContextISF;
533 if (context_scim == NULL)
534 {
535 std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n";
536 return NULL;
537 }
538
539 context_scim->id = _context_count++;
540
541 if (!_scim_initialized)
542 {
543 initialize ();
544 _scim_initialized = true;
545 }
546
547 env = getenv("ECORE_IMF_AUTOCAPITAL_ALLOW");
548 if (env)
549 autocap_allow = !!atoi(env);
550
551 return context_scim;
552}
553
554/**
555 * isf_imf_shutdown
556 *
557 * It will be called when the scim im module is unloaded by ecore. It will do some
558 * cleanup job.
559 */
560EAPI void
561isf_imf_context_shutdown (void)
562{
563 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
564
565 if (_scim_initialized)
566 {
567 _scim_initialized = false;
568 finalize ();
569 }
570}
571
572EAPI void
573isf_imf_context_add (Ecore_IMF_Context *ctx)
574{
575 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
576
577 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get (ctx);
578
579 if (!context_scim) return;
580
581 context_scim->impl = NULL;
582
583 if (_backend.null ())
584 return;
585
586 IMEngineInstancePointer si;
587
588 // Use the default instance if "shared input method" mode is enabled.
589 if (_shared_input_method && !_default_instance.null ())
590 {
591 si = _default_instance;
592 SCIM_DEBUG_FRONTEND(2) << "use default instance: " << si->get_id () << " " << si->get_factory_uuid () << "\n";
593 }
594
595 // Not in "shared input method" mode, or no default instance, create an instance.
596 if (si.null ())
597 {
598 IMEngineFactoryPointer factory = _backend->get_default_factory (_language, "UTF-8");
599 if (factory.null ()) return;
600 si = factory->create_instance ("UTF-8", _instance_count++);
601 if (si.null ()) return;
602 attach_instance (si);
603 SCIM_DEBUG_FRONTEND(2) << "create new instance: " << si->get_id () << " " << si->get_factory_uuid () << "\n";
604 }
605
606 // If "shared input method" mode is enabled, and there is no default instance,
607 // then store this instance as default one.
608 if (_shared_input_method && _default_instance.null ())
609 {
610 SCIM_DEBUG_FRONTEND(2) << "update default instance.\n";
611 _default_instance = si;
612 }
613
614 context_scim->ctx = ctx;
615 context_scim->impl = new_ic_impl (context_scim);
616 if (context_scim->impl == NULL)
617 {
618 std::cerr << "memory allocation failed in " << __FUNCTION__ << "\n";
619 return;
620 }
621
622 context_scim->impl->si = si;
623 context_scim->impl->client_window = 0;
624 context_scim->impl->client_canvas = NULL;
625 context_scim->impl->preedit_caret = 0;
626 context_scim->impl->cursor_x = 0;
627 context_scim->impl->cursor_y = 0;
628 context_scim->impl->cursor_pos = -1;
629 context_scim->impl->is_on = false;
630 context_scim->impl->shared_si = _shared_input_method;
631 context_scim->impl->use_preedit = _on_the_spot;
632 context_scim->impl->preedit_started = false;
633 context_scim->impl->preedit_updating = false;
634 context_scim->impl->need_commit_preedit = false;
635
636 if (!_ic_list)
637 context_scim->next = NULL;
638 else
639 context_scim->next = _ic_list;
640 _ic_list = context_scim;
641
642 if (_shared_input_method)
643 context_scim->impl->is_on = _config->read (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
644
645 _panel_client.prepare (context_scim->id);
646 _panel_client.register_input_context (context_scim->id, si->get_factory_uuid ());
647 set_ic_capabilities (context_scim);
648 _panel_client.send ();
649
650 SCIM_DEBUG_FRONTEND(2) << "input context created: id = " << context_scim->id << "\n";
651}
652
653EAPI void
654isf_imf_context_del (Ecore_IMF_Context *ctx)
655{
656 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
657
658 if (!_ic_list) return;
659
660 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get (ctx);
661
662 if (context_scim)
663 {
664 if (context_scim->id != _ic_list->id)
665 {
666 EcoreIMFContextISF * pre = _ic_list;
667 EcoreIMFContextISF * cur = _ic_list->next;
668 while (cur != NULL)
669 {
670 if (cur->id == context_scim->id)
671 {
672 pre->next = cur->next;
673 break;
674 }
675 pre = cur;
676 cur = cur->next;
677 }
678 }
679 else
680 _ic_list = _ic_list->next;
681 }
682
683 if (context_scim && context_scim->impl)
684 {
685 _panel_client.prepare (context_scim->id);
686
687 if (context_scim == _focused_ic)
688 context_scim->impl->si->focus_out ();
689
690 // Delete the instance.
691 EcoreIMFContextISF *old_focused = _focused_ic;
692 _focused_ic = context_scim;
693 context_scim->impl->si.reset ();
694 _focused_ic = old_focused;
695
696 if (context_scim == _focused_ic)
697 {
698 _panel_client.turn_off (context_scim->id);
699 _panel_client.focus_out (context_scim->id);
700 }
701
702 _panel_client.remove_input_context (context_scim->id);
703 _panel_client.send ();
704
705 if (context_scim->impl->client_window)
706 isf_imf_context_client_window_set (ctx, NULL);
707
708 if (context_scim->impl)
709 {
710 delete_ic_impl (context_scim->impl);
711 context_scim->impl = 0;
712 }
713 }
714
715 if (context_scim == _focused_ic)
716 _focused_ic = 0;
717
718 if (context_scim)
719 {
720 delete context_scim;
721 context_scim = 0;
722 }
723}
724
725/**
726 * isf_imf_context_client_canvas_set
727 * @ctx: a #Ecore_IMF_Context
728 * @canvas: the client canvas
729 *
730 * This function will be called by Ecore IMF.
731 *
732 * Set the client canvas for the Input Method Context; this is the canvas
733 * in which the input appears.
734 *
735 * The canvas type can be determined by using the context canvas type.
736 * Actually only canvas with type "evas" (Evas *) is supported. This canvas
737 * may be used in order to correctly position status windows, and may also
738 * be used for purposes internal to the Input Method Context.
739 */
740EAPI void
741isf_imf_context_client_canvas_set (Ecore_IMF_Context *ctx, void *canvas)
742{
743 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
744
745 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
746
747 if (context_scim && context_scim->impl && context_scim->impl->client_canvas != (Evas*) canvas)
748 context_scim->impl->client_canvas = (Evas*)canvas;
749}
750
751/**
752 * isf_imf_context_client_window_set
753 * @ctx: a #Ecore_IMF_Context
754 * @window: the client window
755 *
756 * This function will be called by Ecore IMF.
757 *
758 * Set the client window for the Input Method Context; this is the Ecore_X_Window
759 * when using X11, Ecore_Win32_Window when using Win32, etc.
760 *
761 * This window is used in order to correctly position status windows,
762 * and may also be used for purposes internal to the Input Method Context.
763 */
764EAPI void
765isf_imf_context_client_window_set (Ecore_IMF_Context *ctx, void *window)
766{
767 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
768
769 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
770
771 if (context_scim && context_scim->impl && context_scim->impl->client_window != (Ecore_X_Window)((Ecore_Window)window))
772 {
773 context_scim->impl->client_window = (Ecore_X_Window)((Ecore_Window)window);
774
775 if ((context_scim->impl->client_window != 0) &&
776 (context_scim->impl->client_window != _client_window))
777 _client_window = context_scim->impl->client_window;
778 }
779}
780
781/**
782 * isf_imf_context_reset
783 * @ctx: a #Ecore_IMF_Context
784 *
785 * This function will be called by Ecore IMF.
786 *
787 * Notify the Input Method Context that a change such as a change in cursor
788 * position has been made. This will typically cause the Input Method Context
789 * to clear the preedit state.
790 */
791EAPI void
792isf_imf_context_reset (Ecore_IMF_Context *ctx)
793{
794 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
795
796 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
797
798 if (context_scim && context_scim->impl && context_scim == _focused_ic)
799 {
800 WideString wstr = context_scim->impl->preedit_string;
801
802 _panel_client.prepare (context_scim->id);
803 context_scim->impl->si->reset ();
804 _panel_client.send ();
805
806 if (context_scim->impl->need_commit_preedit)
807 {
808 if (wstr.length ())
809 {
810 ecore_imf_context_commit_event_add (context_scim->ctx, utf8_wcstombs (wstr).c_str ());
811 ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
812 }
813 _panel_client.prepare (context_scim->id);
814 _panel_client.send ();
815 }
816 }
817}
818
819/**
820 * isf_imf_context_focus_in
821 * @ctx: a #Ecore_IMF_Context
822 *
823 * This function will be called by Ecore IMF.
824 *
825 * Notify the Input Method Context that the widget to which its correspond has gained focus.
826 */
827EAPI void
828isf_imf_context_focus_in (Ecore_IMF_Context *ctx)
829{
830 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
831
832 if (!context_scim)
833 return;
834
835 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__<< "(" << context_scim->id << ")...\n";
836
837 if (_focused_ic)
838 {
839 if (_focused_ic == context_scim)
840 {
841 SCIM_DEBUG_FRONTEND(1) << "It's already focused.\n";
842 //isf_imf_context_cursor_position_set (ctx, 0);
843 return;
844 }
845 SCIM_DEBUG_FRONTEND(1) << "Focus out previous IC first: " << _focused_ic->id << "\n";
846 if (_focused_ic->ctx)
847 isf_imf_context_focus_out (_focused_ic->ctx);
848 }
849
850 bool need_cap = false;
851 bool need_reset = false;
852 bool need_reg = false;
853
854 if (context_scim && context_scim->impl)
855 {
856 _focused_ic = context_scim;
857 _panel_client.prepare (context_scim->id);
858
859 // Handle the "Shared Input Method" mode.
860 if (_shared_input_method)
861 {
862 SCIM_DEBUG_FRONTEND(2) << "shared input method.\n";
863 IMEngineFactoryPointer factory = _backend->get_default_factory (_language, "UTF-8");
864 if (!factory.null ())
865 {
866 if (_default_instance.null () || _default_instance->get_factory_uuid () != factory->get_uuid ())
867 {
868 _default_instance = factory->create_instance ("UTF-8", _default_instance.null () ? _instance_count++ : _default_instance->get_id ());
869 attach_instance (_default_instance);
870 SCIM_DEBUG_FRONTEND(2) << "create new default instance: " << _default_instance->get_id () << " " << _default_instance->get_factory_uuid () << "\n";
871 }
872
873 context_scim->impl->shared_si = true;
874 context_scim->impl->si = _default_instance;
875
876 context_scim->impl->is_on = _config->read (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), context_scim->impl->is_on);
877 context_scim->impl->preedit_string.clear ();
878 context_scim->impl->preedit_attrlist.clear ();
879 context_scim->impl->preedit_caret = 0;
880 context_scim->impl->preedit_started = false;
881 need_cap = true;
882 need_reset = true;
883 need_reg = true;
884 }
885 }
886 else if (context_scim->impl->shared_si)
887 {
888 SCIM_DEBUG_FRONTEND(2) << "exit shared input method.\n";
889 IMEngineFactoryPointer factory = _backend->get_default_factory (_language, "UTF-8");
890 if (!factory.null ())
891 {
892 context_scim->impl->si = factory->create_instance ("UTF-8", _instance_count++);
893 context_scim->impl->preedit_string.clear ();
894 context_scim->impl->preedit_attrlist.clear ();
895 context_scim->impl->preedit_caret = 0;
896 context_scim->impl->preedit_started = false;
897 attach_instance (context_scim->impl->si);
898 need_cap = true;
899 need_reg = true;
900 context_scim->impl->shared_si = false;
901 SCIM_DEBUG_FRONTEND(2) << "create new instance: " << context_scim->impl->si->get_id () << " " << context_scim->impl->si->get_factory_uuid () << "\n";
902 }
903 }
904
905 context_scim->impl->si->set_frontend_data (static_cast <void*> (context_scim));
906
907 if (need_reg) _panel_client.register_input_context (context_scim->id, context_scim->impl->si->get_factory_uuid ());
908 if (need_cap) set_ic_capabilities (context_scim);
909 if (need_reset) context_scim->impl->si->reset ();
910
911 panel_req_focus_in (context_scim);
912 panel_req_update_spot_location (context_scim);
913 panel_req_update_factory_info (context_scim);
914
915 if (context_scim->impl->is_on)
916 {
917 _panel_client.turn_on (context_scim->id);
918 _panel_client.hide_preedit_string (context_scim->id);
919 _panel_client.hide_aux_string (context_scim->id);
920 _panel_client.hide_lookup_table (context_scim->id);
921 context_scim->impl->si->focus_in ();
922 }
923 else
924 {
925 _panel_client.turn_off (context_scim->id);
926 }
927
928 _panel_client.send ();
929 }
930}
931
932/**
933 * isf_imf_context_focus_out
934 * @ctx: a #Ecore_IMF_Context
935 *
936 * This function will be called by Ecore IMF.
937 *
938 * Notify the Input Method Context that the widget to which its correspond has lost focus.
939 */
940EAPI void
941isf_imf_context_focus_out (Ecore_IMF_Context *ctx)
942{
943 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
944
945 if (!context_scim) return;
946
947 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "(" << context_scim->id << ")...\n";
948
949 if (context_scim && context_scim->impl && context_scim == _focused_ic)
950 {
951 WideString wstr = context_scim->impl->preedit_string;
952
953 if (context_scim->impl->need_commit_preedit)
954 {
955 if (wstr.length ())
956 {
957 ecore_imf_context_commit_event_add (context_scim->ctx, utf8_wcstombs (wstr).c_str ());
958 ecore_imf_context_event_callback_call(context_scim->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
959 }
960 _panel_client.prepare (context_scim->id);
961 _panel_client.send ();
962 }
963
964 _panel_client.prepare (context_scim->id);
965 context_scim->impl->si->focus_out ();
966 context_scim->impl->si->reset ();
967 _panel_client.turn_off (context_scim->id);
968 _panel_client.focus_out (context_scim->id);
969 _panel_client.send ();
970 _focused_ic = 0;
971 }
972}
973
974/**
975 * isf_imf_context_cursor_location_set
976 * @ctx: a #Ecore_IMF_Context
977 * @x: x position of New cursor.
978 * @y: y position of New cursor.
979 * @w: the width of New cursor.
980 * @h: the height of New cursor.
981 *
982 * This function will be called by Ecore IMF.
983 *
984 * Notify the Input Method Context that a change in the cursor location has been made.
985 */
986EAPI void
987isf_imf_context_cursor_location_set (Ecore_IMF_Context *ctx, int cx, int cy, int cw, int ch)
988{
989 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
990
991 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
992 Ecore_Evas *ee;
993 int canvas_x, canvas_y;
994
995 if (cw == 0 && ch == 0)
996 return;
997
998 if (context_scim && context_scim->impl && context_scim == _focused_ic)
999 {
1000 // Don't update spot location while updating preedit string.
1001 if (context_scim->impl->preedit_updating)
1002 return;
1003
1004 if (!context_scim->impl->client_canvas)
1005 return;
1006
1007 ee = ecore_evas_ecore_evas_get(context_scim->impl->client_canvas);
1008 if (!ee) return;
1009
1010 ecore_evas_geometry_get (ee, &canvas_x, &canvas_y, NULL, NULL);
1011
1012 if (context_scim->impl->cursor_x != canvas_x + cx || context_scim->impl->cursor_y != canvas_y + cy + ch)
1013 {
1014 context_scim->impl->cursor_x = canvas_x + cx;
1015 context_scim->impl->cursor_y = canvas_y + cy + ch;
1016 _panel_client.prepare (context_scim->id);
1017 panel_req_update_spot_location (context_scim);
1018 _panel_client.send ();
1019 SCIM_DEBUG_FRONTEND(2) << "new cursor location = " << context_scim->impl->cursor_x << "," << context_scim->impl->cursor_y << "\n";
1020 }
1021 }
1022}
1023
1024/**
1025 * isf_imf_context_use_preedit_set
1026 * @ctx: a #Ecore_IMF_Context
1027 * @use_preedit: Whether the IM context should use the preedit string.
1028 *
1029 * This function will be called by Ecore IMF.
1030 *
1031 * Set whether the IM context should use the preedit string to display feedback.
1032 * If is 0 (default is 1), then the IM context may use some other method to
1033 * display feedback, such as displaying it in a child of the root window.
1034 */
1035EAPI void
1036isf_imf_context_use_preedit_set (Ecore_IMF_Context* ctx, Eina_Bool use_preedit)
1037{
1038 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (use_preedit ? "true" : "false") << "...\n";
1039
1040 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get (ctx);
1041
1042 if (!_on_the_spot) return;
1043
1044 if (context_scim && context_scim->impl)
1045 {
1046 bool old = context_scim->impl->use_preedit;
1047 context_scim->impl->use_preedit = use_preedit;
1048 if (context_scim == _focused_ic)
1049 {
1050 _panel_client.prepare (context_scim->id);
1051
1052 if (old != use_preedit)
1053 set_ic_capabilities (context_scim);
1054
1055 if (context_scim->impl->preedit_string.length ())
1056 slot_show_preedit_string (context_scim->impl->si);
1057
1058 _panel_client.send ();
1059 }
1060 }
1061}
1062
1063EAPI void
1064isf_imf_context_preedit_string_with_attributes_get (Ecore_IMF_Context *ctx, char** str, Eina_List **attrs, int *cursor_pos)
1065{
1066 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1067
1068 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get (ctx);
1069
1070 if (context_scim && context_scim->impl && context_scim->impl->is_on)
1071 {
1072 String mbs = utf8_wcstombs (context_scim->impl->preedit_string);
1073
1074 if (str)
1075 {
1076 if (mbs.length ())
1077 *str = strdup (mbs.c_str ());
1078 else
1079 *str = strdup ("");
1080 }
1081
1082 if (cursor_pos)
1083 {
1084 *cursor_pos = context_scim->impl->preedit_caret;
1085 }
1086
1087 if (attrs)
1088 {
1089 if (mbs.length ())
1090 {
1091 int start_index, end_index;
1092 int wlen = context_scim->impl->preedit_string.length ();
1093
1094 Ecore_IMF_Preedit_Attr *attr = NULL;
1095 AttributeList::const_iterator i;
1096 bool *attrs_flag = new bool [mbs.length ()];
1097 memset (attrs_flag, 0, mbs.length () *sizeof (bool));
1098
1099 for (i = context_scim->impl->preedit_attrlist.begin ();
1100 i != context_scim->impl->preedit_attrlist.end (); ++i)
1101 {
1102 start_index = i->get_start ();
1103 end_index = i->get_end ();
1104
1105 if (end_index <= wlen && start_index < end_index && i->get_type () != SCIM_ATTR_DECORATE_NONE)
1106 {
1107 start_index = utf8_offset_to_index (mbs.c_str (), i->get_start ());
1108 end_index = utf8_offset_to_index (mbs.c_str (), i->get_end ());
1109
1110 if (i->get_type () == SCIM_ATTR_DECORATE)
1111 {
1112 attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
1113 if (attr == NULL)
1114 continue;
1115 attr->start_index = start_index;
1116 attr->end_index = end_index;
1117
1118 if (i->get_value () == SCIM_ATTR_DECORATE_UNDERLINE)
1119 {
1120 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
1121 *attrs = eina_list_append(*attrs, (void *)attr);
1122 }
1123 else if (i->get_value () == SCIM_ATTR_DECORATE_REVERSE)
1124 {
1125 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1126 *attrs = eina_list_append(*attrs, (void *)attr);
1127 }
1128 else if (i->get_value () == SCIM_ATTR_DECORATE_HIGHLIGHT)
1129 {
1130 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
1131 *attrs = eina_list_append(*attrs, (void *)attr);
1132 }
1133 else
1134 {
1135 free (attr);
1136 }
1137
1138 switch(i->get_value())
1139 {
1140 case SCIM_ATTR_DECORATE_UNDERLINE:
1141 case SCIM_ATTR_DECORATE_REVERSE:
1142 case SCIM_ATTR_DECORATE_HIGHLIGHT:
1143 // Record which character has attribute.
1144 for (int pos = start_index; pos < end_index; ++pos)
1145 attrs_flag [pos] = 1;
1146 break;
1147 default:
1148 break;
1149 }
1150 }
1151 else if (i->get_type () == SCIM_ATTR_FOREGROUND)
1152 {
1153 SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_FOREGROUND\n";
1154 }
1155 else if (i->get_type () == SCIM_ATTR_BACKGROUND)
1156 {
1157 SCIM_DEBUG_FRONTEND(4) << "SCIM_ATTR_BACKGROUND\n";
1158 }
1159 }
1160 }
1161
1162 // Add underline for all characters which don't have attribute.
1163 for (unsigned int pos = 0; pos < mbs.length (); ++pos)
1164 {
1165 if (!attrs_flag [pos])
1166 {
1167 int begin_pos = pos;
1168
1169 while (pos < mbs.length () && !attrs_flag [pos])
1170 ++pos;
1171
1172 // use REVERSE style as default
1173 attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
1174 if (attr == NULL)
1175 continue;
1176 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
1177 attr->start_index = begin_pos;
1178 attr->end_index = pos;
1179 *attrs = eina_list_append(*attrs, (void *)attr);
1180 }
1181 }
1182
1183 delete [] attrs_flag;
1184 }
1185 }
1186 }
1187 else
1188 {
1189 if (str)
1190 *str = strdup ("");
1191
1192 if (cursor_pos)
1193 *cursor_pos = 0;
1194
1195 if (attrs)
1196 *attrs = NULL;
1197 }
1198}
1199
1200/**
1201 * isf_imf_context_preedit_string_get
1202 * @ctx: a #Ecore_IMF_Context
1203 * @str: the preedit string
1204 * @cursor_pos: the cursor position
1205 *
1206 * This function will be called by Ecore IMF.
1207 *
1208 * To get the preedit string of the input method.
1209 */
1210EAPI void
1211isf_imf_context_preedit_string_get (Ecore_IMF_Context *ctx, char** str, int *cursor_pos)
1212{
1213 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1214
1215 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get (ctx);
1216
1217 if (context_scim && context_scim->impl && context_scim->impl->is_on)
1218 {
1219 String mbs = utf8_wcstombs (context_scim->impl->preedit_string);
1220
1221 if (str)
1222 {
1223 if (mbs.length ())
1224 *str = strdup (mbs.c_str ());
1225 else
1226 *str = strdup ("");
1227 }
1228
1229 if (cursor_pos)
1230 *cursor_pos = context_scim->impl->preedit_caret;
1231 }
1232 else
1233 {
1234 if (str)
1235 *str = strdup ("");
1236
1237 if (cursor_pos)
1238 *cursor_pos = 0;
1239 }
1240}
1241
1242/**
1243 * isf_imf_context_cursor_position_set
1244 * @ctx: a #Ecore_IMF_Context
1245 * @cursor_pos: New cursor position in characters.
1246 *
1247 * This function will be called by Ecore IMF.
1248 *
1249 * Notify the Input Method Context that a change in the cursor position has been made.
1250 */
1251EAPI void
1252isf_imf_context_cursor_position_set (Ecore_IMF_Context *ctx, int cursor_pos)
1253{
1254 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1255
1256 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
1257
1258 if (context_scim && context_scim->impl && context_scim == _focused_ic)
1259 {
1260 // Don't update spot location while updating preedit string.
1261 if (context_scim->impl->preedit_updating)
1262 return;
1263
1264 if (context_scim->impl->cursor_pos != cursor_pos)
1265 {
1266 context_scim->impl->cursor_pos = cursor_pos;
1267 caps_mode_check(ctx, EINA_FALSE);
1268 }
1269 }
1270}
1271
1272/**
1273 * isf_imf_context_input_mode_set
1274 * @ctx: a #Ecore_IMF_Context
1275 * @input_mode: the input mode
1276 *
1277 * This function will be called by Ecore IMF.
1278 *
1279 * To set the input mode of input method. The definition of Ecore_IMF_Input_Mode
1280 * is in Ecore_IMF.h.
1281 */
1282EAPI void
1283isf_imf_context_input_mode_set (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode)
1284{
1285 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1286
1287 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF*)ecore_imf_context_data_get (ctx);
1288 if (context_scim && context_scim->impl)
1289 context_scim->impl->input_mode = input_mode;
1290}
1291
1292/**
1293 * isf_imf_context_prediction_allow_set
1294 * @ctx: a #Ecore_IMF_Context
1295 * @use_prediction: Whether the IM context should use the prediction.
1296 *
1297 * This function will be called by Ecore IMF.
1298 *
1299 * Set whether the IM context should use the prediction.
1300 */
1301EAPI void
1302isf_imf_context_prediction_allow_set (Ecore_IMF_Context* ctx, Eina_Bool prediction)
1303{
1304 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << (prediction ? "true" : "false") << "...\n";
1305
1306 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
1307
1308 if (context_scim && context_scim->impl && context_scim->impl->prediction_allow != prediction)
1309 context_scim->impl->prediction_allow = prediction;
1310}
1311
1312EAPI void
1313isf_imf_context_autocapital_type_set (Ecore_IMF_Context* ctx, Ecore_IMF_Autocapital_Type autocapital_type)
1314{
1315 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " = " << autocapital_type << "...\n";
1316
1317 EcoreIMFContextISF *context_scim = (EcoreIMFContextISF *)ecore_imf_context_data_get (ctx);
1318
1319 if (context_scim && context_scim->impl && context_scim->impl->autocapital_type != autocapital_type)
1320 context_scim->impl->autocapital_type = autocapital_type;
1321}
1322
1323/**
1324 * isf_imf_context_filter_event
1325 * @ctx: a #Ecore_IMF_Context
1326 * @type: The type of event defined by Ecore_IMF_Event_Type.
1327 * @event: The event itself.
1328 * Return value: %TRUE if the input method handled the key event.
1329 *
1330 * This function will be called by Ecore IMF.
1331 *
1332 * Allow an Ecore Input Context to internally handle an event. If this function
1333 * returns 1, then no further processing should be done for this event. Input
1334 * methods must be able to accept all types of events (simply returning 0 if
1335 * the event was not handled), but there is no obligation of any events to be
1336 * submitted to this function.
1337 */
1338
1339EAPI Eina_Bool
1340isf_imf_context_filter_event (Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
1341{
1342 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1343
1344 EcoreIMFContextISF *ic = (EcoreIMFContextISF*)ecore_imf_context_data_get (ctx);
1345 Eina_Bool ret = EINA_FALSE;
1346
1347 if (ic == NULL || ic->impl == NULL)
1348 return ret;
1349
1350 KeyEvent key;
1351
1352 if (type == ECORE_IMF_EVENT_KEY_DOWN)
1353 {
1354 Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
1355 scim_string_to_key (key, ev->key);
1356 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask;
1357 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask;
1358 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask;
1359 if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
1360 if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
1361 }
1362 else if (type == ECORE_IMF_EVENT_KEY_UP)
1363 {
1364 Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
1365 scim_string_to_key (key, ev->key);
1366 key.mask = SCIM_KEY_ReleaseMask;
1367 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT) key.mask |=SCIM_KEY_ShiftMask;
1368 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_CTRL) key.mask |=SCIM_KEY_ControlMask;
1369 if (ev->modifiers & ECORE_IMF_KEYBOARD_MODIFIER_ALT) key.mask |=SCIM_KEY_AltMask;
1370 if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_CAPS) key.mask |=SCIM_KEY_CapsLockMask;
1371 if (ev->locks & ECORE_IMF_KEYBOARD_LOCK_NUM) key.mask |=SCIM_KEY_NumLockMask;
1372 }
1373 else
1374 {
1375 return ret;
1376 }
1377
1378 key.mask &= _valid_key_mask;
1379
1380 _panel_client.prepare (ic->id);
1381
1382 ret = EINA_TRUE;
1383 if (!filter_hotkeys (ic, key))
1384 {
1385 if (!_focused_ic || !_focused_ic->impl->is_on ||
1386 !_focused_ic->impl->si->process_key_event (key))
1387 ret = EINA_FALSE;
1388 }
1389
1390 _panel_client.send ();
1391
1392 return ret;
1393}
1394
1395/* Panel Slot functions */
1396static void
1397panel_slot_reload_config (int context __UNUSED__)
1398{
1399 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1400 _config->reload ();
1401}
1402
1403static void
1404panel_slot_exit (int /* context */)
1405{
1406 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1407
1408 finalize ();
1409}
1410
1411static void
1412panel_slot_update_lookup_table_page_size (int context, int page_size)
1413{
1414 EcoreIMFContextISF *ic = find_ic (context);
1415 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " page_size=" << page_size << " ic=" << ic << "\n";
1416 if (ic && ic->impl)
1417 {
1418 _panel_client.prepare (ic->id);
1419 ic->impl->si->update_lookup_table_page_size (page_size);
1420 _panel_client.send ();
1421 }
1422}
1423
1424static void
1425panel_slot_lookup_table_page_up (int context)
1426{
1427 EcoreIMFContextISF *ic = find_ic (context);
1428 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1429 if (ic && ic->impl)
1430 {
1431 _panel_client.prepare (ic->id);
1432 ic->impl->si->lookup_table_page_up ();
1433 _panel_client.send ();
1434 }
1435}
1436
1437static void
1438panel_slot_lookup_table_page_down (int context)
1439{
1440 EcoreIMFContextISF *ic = find_ic (context);
1441 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1442 if (ic && ic->impl)
1443 {
1444 _panel_client.prepare (ic->id);
1445 ic->impl->si->lookup_table_page_down ();
1446 _panel_client.send ();
1447 }
1448}
1449
1450static void
1451panel_slot_trigger_property (int context, const String &property)
1452{
1453 EcoreIMFContextISF *ic = find_ic (context);
1454 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " property=" << property << " ic=" << ic << "\n";
1455 if (ic && ic->impl)
1456 {
1457 _panel_client.prepare (ic->id);
1458 ic->impl->si->trigger_property (property);
1459 _panel_client.send ();
1460 }
1461}
1462
1463static void
1464panel_slot_process_helper_event (int context, const String &target_uuid, const String &helper_uuid, const Transaction &trans)
1465{
1466 EcoreIMFContextISF *ic = find_ic (context);
1467 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " target=" << target_uuid
1468 << " helper=" << helper_uuid << " ic=" << ic << " ic->impl=" << (ic ? ic->impl : 0) << " ic-uuid="
1469 << ((ic && ic->impl) ? ic->impl->si->get_factory_uuid () : "" ) << "\n";
1470 if (ic && ic->impl && ic->impl->si->get_factory_uuid () == target_uuid)
1471 {
1472 _panel_client.prepare (ic->id);
1473 SCIM_DEBUG_FRONTEND(2) << "call process_helper_event\n";
1474 ic->impl->si->process_helper_event (helper_uuid, trans);
1475 _panel_client.send ();
1476 }
1477}
1478
1479static void
1480panel_slot_move_preedit_caret (int context, int caret_pos)
1481{
1482 EcoreIMFContextISF *ic = find_ic (context);
1483 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " caret=" << caret_pos << " ic=" << ic << "\n";
1484 if (ic && ic->impl)
1485 {
1486 _panel_client.prepare (ic->id);
1487 ic->impl->si->move_preedit_caret (caret_pos);
1488 _panel_client.send ();
1489 }
1490}
1491
1492static void
1493panel_slot_select_candidate (int context, int cand_index)
1494{
1495 EcoreIMFContextISF *ic = find_ic (context);
1496 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " candidate=" << cand_index << " ic=" << ic << "\n";
1497 if (ic && ic->impl)
1498 {
1499 _panel_client.prepare (ic->id);
1500 ic->impl->si->select_candidate (cand_index);
1501 _panel_client.send ();
1502 }
1503}
1504
1505static void
1506panel_slot_process_key_event (int context, const KeyEvent &key)
1507{
1508 EcoreIMFContextISF *ic = find_ic (context);
1509 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string () << " ic=" << ic << "\n";
1510
1511 if (ic && ic->impl && ic->impl->client_canvas)
1512 feed_key_event(ic->impl->client_canvas, key.get_key_string().c_str(), EINA_FALSE);
1513}
1514
1515static void
1516panel_slot_commit_string (int context, const WideString &wstr)
1517{
1518 EcoreIMFContextISF *ic = find_ic (context);
1519 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " str=" << utf8_wcstombs (wstr) << " ic=" << ic << "\n";
1520
1521 if (ic && ic->impl)
1522 {
1523 if (_focused_ic != ic)
1524 return;
1525
1526 ecore_imf_context_commit_event_add (ic->ctx, utf8_wcstombs (wstr).c_str ());
1527 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(wstr).c_str());
1528 }
1529}
1530
1531static void
1532panel_slot_forward_key_event (int context, const KeyEvent &key)
1533{
1534 EcoreIMFContextISF *ic = find_ic (context);
1535 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " key=" << key.get_key_string () << " ic=" << ic << "\n";
1536
1537 if (ic && ic->impl && ic->impl->client_canvas)
1538 feed_key_event (ic->impl->client_canvas, key.get_key_string ().c_str (), EINA_TRUE);
1539}
1540
1541static void
1542panel_slot_request_help (int context)
1543{
1544 EcoreIMFContextISF *ic = find_ic (context);
1545 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1546
1547 if (ic && ic->impl)
1548 {
1549 _panel_client.prepare (ic->id);
1550 panel_req_show_help (ic);
1551 _panel_client.send ();
1552 }
1553}
1554
1555static void
1556panel_slot_request_factory_menu (int context)
1557{
1558 EcoreIMFContextISF *ic = find_ic (context);
1559 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " ic=" << ic << "\n";
1560
1561 if (ic && ic->impl)
1562 {
1563 _panel_client.prepare (ic->id);
1564 panel_req_show_factory_menu (ic);
1565 _panel_client.send ();
1566 }
1567}
1568
1569static void
1570panel_slot_change_factory (int context, const String &uuid)
1571{
1572 EcoreIMFContextISF *ic = find_ic (context);
1573 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " context=" << context << " factory=" << uuid << " ic=" << ic << "\n";
1574
1575 if (ic && ic->impl)
1576 {
1577 ic->impl->si->reset ();
1578 _panel_client.prepare (ic->id);
1579 open_specific_factory (ic, uuid);
1580 _panel_client.send ();
1581 }
1582}
1583
1584/* Panel Requestion functions. */
1585static void
1586panel_req_show_help (EcoreIMFContextISF *ic)
1587{
1588 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1589
1590 String help;
1591
1592 help = String ("Smart Common Input Method platform ") +
1593 //String (SCIM_VERSION) +
1594 String ("\n(C) 2002-2005 James Su <suzhe@tsinghua.org.cn>\n\n");
1595
1596 if (ic && ic->impl)
1597 {
1598 IMEngineFactoryPointer sf = _backend->get_factory (ic->impl->si->get_factory_uuid ());
1599 if (sf)
1600 {
1601 help += utf8_wcstombs (sf->get_name ());
1602 help += String (":\n\n");
1603
1604 help += utf8_wcstombs (sf->get_help ());
1605 help += String ("\n\n");
1606
1607 help += utf8_wcstombs (sf->get_credits ());
1608 }
1609 _panel_client.show_help (ic->id, help);
1610 }
1611}
1612
1613static void
1614panel_req_show_factory_menu (EcoreIMFContextISF *ic)
1615{
1616 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1617
1618 std::vector<IMEngineFactoryPointer> factories;
1619 std::vector <PanelFactoryInfo> menu;
1620
1621 _backend->get_factories_for_encoding (factories, "UTF-8");
1622
1623 for (size_t i = 0; i < factories.size (); ++ i)
1624 {
1625 menu.push_back (PanelFactoryInfo (
1626 factories [i]->get_uuid (),
1627 utf8_wcstombs (factories [i]->get_name ()),
1628 factories [i]->get_language (),
1629 factories [i]->get_icon_file ()));
1630 }
1631
1632 if (menu.size ())
1633 _panel_client.show_factory_menu (ic->id, menu);
1634}
1635
1636static void
1637panel_req_update_factory_info (EcoreIMFContextISF *ic)
1638{
1639 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1640
1641 if (ic && ic->impl && ic == _focused_ic)
1642 {
1643 PanelFactoryInfo info;
1644 if (ic->impl->is_on)
1645 {
1646 IMEngineFactoryPointer sf = _backend->get_factory (ic->impl->si->get_factory_uuid ());
1647 if (sf)
1648 info = PanelFactoryInfo (sf->get_uuid (), utf8_wcstombs (sf->get_name ()), sf->get_language (), sf->get_icon_file ());
1649 }
1650 else
1651 {
1652 info = PanelFactoryInfo (String (""), String ("English/Keyboard"), String ("C"), "");
1653 }
1654 _panel_client.update_factory_info (ic->id, info);
1655 }
1656}
1657
1658static void
1659panel_req_focus_in (EcoreIMFContextISF *ic)
1660{
1661 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1662
1663 _panel_client.focus_in (ic->id, ic->impl->si->get_factory_uuid ());
1664}
1665
1666static void
1667panel_req_update_spot_location (EcoreIMFContextISF *ic)
1668{
1669 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1670
1671 _panel_client.update_spot_location (ic->id, ic->impl->cursor_x, ic->impl->cursor_y);
1672}
1673
1674static bool
1675filter_hotkeys (EcoreIMFContextISF *ic, const KeyEvent &key)
1676{
1677 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1678
1679 bool ret = false;
1680
1681 _frontend_hotkey_matcher.push_key_event (key);
1682 _imengine_hotkey_matcher.push_key_event (key);
1683
1684 FrontEndHotkeyAction hotkey_action = _frontend_hotkey_matcher.get_match_result ();
1685
1686 if (hotkey_action == SCIM_FRONTEND_HOTKEY_TRIGGER)
1687 {
1688 if (!ic->impl->is_on)
1689 turn_on_ic (ic);
1690 else
1691 turn_off_ic (ic);
1692 ret = true;
1693 }
1694 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_ON)
1695 {
1696 if (!ic->impl->is_on)
1697 turn_on_ic (ic);
1698 ret = true;
1699 }
1700 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_OFF)
1701 {
1702 if (ic->impl->is_on)
1703 turn_off_ic (ic);
1704 ret = true;
1705 }
1706 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_NEXT_FACTORY)
1707 {
1708 open_next_factory (ic);
1709 ret = true;
1710 }
1711 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_PREVIOUS_FACTORY)
1712 {
1713 open_previous_factory (ic);
1714 ret = true;
1715 }
1716 else if (hotkey_action == SCIM_FRONTEND_HOTKEY_SHOW_FACTORY_MENU)
1717 {
1718 panel_req_show_factory_menu (ic);
1719 ret = true;
1720 }
1721 else if (_imengine_hotkey_matcher.is_matched ())
1722 {
1723 String sfid = _imengine_hotkey_matcher.get_match_result ();
1724 open_specific_factory (ic, sfid);
1725 ret = true;
1726 }
1727 return ret;
1728}
1729
1730static bool
1731panel_initialize (void)
1732{
1733 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1734
1735 String display_name;
1736 {
1737 const char *p = getenv ("DISPLAY");
1738 if (p) display_name = String (p);
1739 }
1740
1741 if (_panel_client.open_connection (_config->get_name (), display_name) >= 0)
1742 {
1743 int fd = _panel_client.get_connection_number ();
1744
1745 _panel_iochannel_read_handler = ecore_main_fd_handler_add (fd, ECORE_FD_READ, panel_iochannel_handler, NULL, NULL, NULL);
1746
1747 SCIM_DEBUG_FRONTEND(2) << " Panel FD= " << fd << "\n";
1748
1749 return true;
1750 }
1751 std::cerr << "panel_initialize () failed!!!\n";
1752 return false;
1753}
1754
1755static void
1756panel_finalize (void)
1757{
1758 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1759
1760 _panel_client.close_connection ();
1761
1762 if (_panel_iochannel_read_handler)
1763 {
1764 ecore_main_fd_handler_del (_panel_iochannel_read_handler);
1765 _panel_iochannel_read_handler = 0;
1766 }
1767
1768 if (_panel_iochannel_err_handler)
1769 {
1770 ecore_main_fd_handler_del (_panel_iochannel_err_handler);
1771 _panel_iochannel_err_handler = 0;
1772 }
1773}
1774
1775static Eina_Bool
1776panel_iochannel_handler (void *data __UNUSED__, Ecore_Fd_Handler *fd_handler)
1777{
1778 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1779
1780 if (fd_handler == _panel_iochannel_read_handler)
1781 {
1782 if (!_panel_client.filter_event ())
1783 {
1784 panel_finalize ();
1785 panel_initialize ();
1786 return ECORE_CALLBACK_CANCEL;
1787 }
1788 }
1789 else if (fd_handler == _panel_iochannel_err_handler)
1790 {
1791 panel_finalize ();
1792 panel_initialize ();
1793 return ECORE_CALLBACK_CANCEL;
1794 }
1795 return ECORE_CALLBACK_RENEW;
1796}
1797
1798static void
1799turn_on_ic (EcoreIMFContextISF *ic)
1800{
1801 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1802
1803 if (ic && ic->impl && !ic->impl->is_on)
1804 {
1805 ic->impl->is_on = true;
1806
1807 if (ic == _focused_ic)
1808 {
1809 panel_req_focus_in (ic);
1810 panel_req_update_spot_location (ic);
1811 panel_req_update_factory_info (ic);
1812 _panel_client.turn_on (ic->id);
1813 _panel_client.hide_preedit_string (ic->id);
1814 _panel_client.hide_aux_string (ic->id);
1815 _panel_client.hide_lookup_table (ic->id);
1816 ic->impl->si->focus_in ();
1817 }
1818
1819 //Record the IC on/off status
1820 if (_shared_input_method)
1821 _config->write (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), true);
1822
1823 if (ic->impl->use_preedit && ic->impl->preedit_string.length ())
1824 {
1825 ecore_imf_context_preedit_start_event_add (ic->ctx);
1826 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
1827 ecore_imf_context_preedit_changed_event_add (ic->ctx);
1828 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1829 ic->impl->preedit_started = true;
1830 }
1831 }
1832}
1833
1834static void
1835turn_off_ic (EcoreIMFContextISF *ic)
1836{
1837 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1838
1839 if (ic && ic->impl && ic->impl->is_on)
1840 {
1841 ic->impl->is_on = false;
1842
1843 if (ic == _focused_ic)
1844 {
1845 ic->impl->si->focus_out ();
1846
1847 panel_req_update_factory_info (ic);
1848 _panel_client.turn_off (ic->id);
1849 }
1850
1851 //Record the IC on/off status
1852 if (_shared_input_method)
1853 _config->write (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
1854
1855 if (ic->impl->use_preedit && ic->impl->preedit_string.length ())
1856 {
1857 ecore_imf_context_preedit_changed_event_add (ic->ctx);
1858 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1859 ecore_imf_context_preedit_end_event_add (ic->ctx);
1860 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
1861 ic->impl->preedit_started = false;
1862 }
1863 }
1864}
1865
1866static void
1867set_ic_capabilities (EcoreIMFContextISF *ic)
1868{
1869 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1870
1871 if (ic && ic->impl)
1872 {
1873 unsigned int cap = SCIM_CLIENT_CAP_ALL_CAPABILITIES;
1874
1875 if (!_on_the_spot || !ic->impl->use_preedit)
1876 cap -= SCIM_CLIENT_CAP_ONTHESPOT_PREEDIT;
1877
1878 ic->impl->si->update_client_capabilities (cap);
1879 }
1880}
1881
1882static bool
1883check_socket_frontend (void)
1884{
1885 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
1886
1887 SocketAddress address;
1888 SocketClient client;
1889
1890 uint32 magic;
1891
1892 address.set_address (scim_get_default_socket_frontend_address ());
1893
1894 if (!client.connect (address))
1895 return false;
1896
1897 if (!scim_socket_open_connection (magic,
1898 String ("ConnectionTester"),
1899 String ("SocketFrontEnd"),
1900 client,
1901 1000))
1902 return false;
1903
1904 return true;
1905}
1906
1907void
1908initialize (void)
1909{
1910 std::vector<String> config_list;
1911 std::vector<String> engine_list;
1912 std::vector<String> load_engine_list;
1913
1914 std::vector<String>::iterator it;
1915
1916 bool manual = false;
1917
1918 bool socket = true;
1919
1920 String config_module_name = "simple";
1921
1922 printf("Initializing Ecore SCIM IMModule...\n");
1923
1924 SCIM_DEBUG_FRONTEND(1) << "Initializing Ecore SCIM IMModule...\n";
1925
1926 // Get system language.
1927 _language = scim_get_locale_language (scim_get_current_locale ());
1928
1929 if (socket)
1930 {
1931 // If no Socket FrontEnd is running, then launch one.
1932 // And set manual to false.
1933 bool check_result = check_socket_frontend ();
1934 if (!check_result)
1935 {
1936 std::cerr << "Launching a SCIM daemon with Socket FrontEnd...\n";
1937 //get modules list
1938 scim_get_imengine_module_list (engine_list);
1939
1940 for (it = engine_list.begin (); it != engine_list.end (); it++)
1941 {
1942 if (*it != "socket")
1943 load_engine_list.push_back (*it);
1944 }
1945
1946 const char *new_argv [] = { "--no-stay", 0 };
1947 scim_launch (true,
1948 config_module_name,
1949 (load_engine_list.size () ? scim_combine_string_list (load_engine_list, ',') : "none"),
1950 "socket",
1951 (char **)new_argv);
1952 manual = false;
1953 }
1954
1955 // If there is one Socket FrontEnd running and it's not manual mode,
1956 // then just use this Socket Frontend.
1957 if (!manual)
1958 {
1959 for (int i = 0; i < 200; ++i)
1960 {
1961 if (check_result)
1962 {
1963 config_module_name = "socket";
1964 load_engine_list.clear ();
1965 load_engine_list.push_back ("socket");
1966 break;
1967 }
1968 scim_usleep (50000);
1969 check_result = check_socket_frontend ();
1970 }
1971 }
1972 }
1973
1974 if (config_module_name != "dummy")
1975 {
1976 //load config module
1977 SCIM_DEBUG_FRONTEND(1) << "Loading Config module: " << config_module_name << "...\n";
1978 _config_module = new ConfigModule (config_module_name);
1979
1980 //create config instance
1981 if (_config_module != NULL && _config_module->valid ())
1982 _config = _config_module->create_config ();
1983 }
1984
1985 if (_config.null ())
1986 {
1987 SCIM_DEBUG_FRONTEND(1) << "Config module cannot be loaded, using dummy Config.\n";
1988
1989 if (_config_module) delete _config_module;
1990 _config_module = NULL;
1991
1992 _config = new DummyConfig ();
1993 config_module_name = "dummy";
1994 }
1995
1996 reload_config_callback (_config);
1997 _config->signal_connect_reload (slot (reload_config_callback));
1998
1999 // create backend
2000 _backend = new CommonBackEnd (_config, load_engine_list.size () ? load_engine_list : engine_list);
2001
2002 if (_backend.null ())
2003 std::cerr << "Cannot create BackEnd Object!\n";
2004 else
2005 _fallback_factory = _backend->get_factory (SCIM_COMPOSE_KEY_FACTORY_UUID);
2006
2007 if (_fallback_factory.null ())
2008 _fallback_factory = new DummyIMEngineFactory ();
2009
2010 _fallback_instance = _fallback_factory->create_instance (String ("UTF-8"), 0);
2011 _fallback_instance->signal_connect_commit_string (slot (fallback_commit_string_cb));
2012
2013 // Attach Panel Client signal.
2014 _panel_client.signal_connect_reload_config (slot (panel_slot_reload_config));
2015 _panel_client.signal_connect_exit (slot (panel_slot_exit));
2016 _panel_client.signal_connect_update_lookup_table_page_size (slot (panel_slot_update_lookup_table_page_size));
2017 _panel_client.signal_connect_lookup_table_page_up (slot (panel_slot_lookup_table_page_up));
2018 _panel_client.signal_connect_lookup_table_page_down (slot (panel_slot_lookup_table_page_down));
2019 _panel_client.signal_connect_trigger_property (slot (panel_slot_trigger_property));
2020 _panel_client.signal_connect_process_helper_event (slot (panel_slot_process_helper_event));
2021 _panel_client.signal_connect_move_preedit_caret (slot (panel_slot_move_preedit_caret));
2022 _panel_client.signal_connect_select_candidate (slot (panel_slot_select_candidate));
2023 _panel_client.signal_connect_process_key_event (slot (panel_slot_process_key_event));
2024 _panel_client.signal_connect_commit_string (slot (panel_slot_commit_string));
2025 _panel_client.signal_connect_forward_key_event (slot (panel_slot_forward_key_event));
2026 _panel_client.signal_connect_request_help (slot (panel_slot_request_help));
2027 _panel_client.signal_connect_request_factory_menu (slot (panel_slot_request_factory_menu));
2028 _panel_client.signal_connect_change_factory (slot (panel_slot_change_factory));
2029
2030 if (!panel_initialize ())
2031 std::cerr << "Ecore IM Module: Cannot connect to Panel!\n";
2032}
2033
2034static void
2035finalize (void)
2036{
2037 SCIM_DEBUG_FRONTEND(1) << "Finalizing Ecore ISF IMModule...\n";
2038
2039 // Reset this first so that the shared instance could be released correctly afterwards.
2040 _default_instance.reset ();
2041
2042 SCIM_DEBUG_FRONTEND(2) << "Finalize all IC partially.\n";
2043 while (_used_ic_impl_list)
2044 {
2045 // In case in "shared input method" mode,
2046 // all contexts share only one instance,
2047 // so we need point the reference pointer correctly before finalizing.
2048 _used_ic_impl_list->si->set_frontend_data (static_cast <void*> (_used_ic_impl_list->parent));
2049 isf_imf_context_del (_used_ic_impl_list->parent->ctx);
2050 }
2051
2052 delete_all_ic_impl ();
2053
2054 _fallback_instance.reset ();
2055 _fallback_factory.reset ();
2056
2057 SCIM_DEBUG_FRONTEND(2) << " Releasing BackEnd...\n";
2058 _backend.reset ();
2059
2060 SCIM_DEBUG_FRONTEND(2) << " Releasing Config...\n";
2061 _config.reset ();
2062
2063 if (_config_module)
2064 {
2065 SCIM_DEBUG_FRONTEND(2) << " Deleting _config_module...\n";
2066 delete _config_module;
2067 _config_module = 0;
2068 }
2069
2070 _focused_ic = NULL;
2071 _ic_list = NULL;
2072
2073 _scim_initialized = false;
2074
2075 panel_finalize ();
2076}
2077
2078static void
2079open_next_factory (EcoreIMFContextISF *ic)
2080{
2081 SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2082 IMEngineFactoryPointer sf = _backend->get_next_factory ("", "UTF-8", ic->impl->si->get_factory_uuid ());
2083
2084 if (!sf.null ())
2085 {
2086 turn_off_ic (ic);
2087 ic->impl->si = sf->create_instance ("UTF-8", ic->impl->si->get_id ());
2088 ic->impl->si->set_frontend_data (static_cast <void*> (ic));
2089 ic->impl->preedit_string = WideString ();
2090 ic->impl->preedit_caret = 0;
2091 attach_instance (ic->impl->si);
2092 _backend->set_default_factory (_language, sf->get_uuid ());
2093 _panel_client.register_input_context (ic->id, sf->get_uuid ());
2094 set_ic_capabilities (ic);
2095 turn_on_ic (ic);
2096
2097 if (_shared_input_method)
2098 {
2099 _default_instance = ic->impl->si;
2100 ic->impl->shared_si = true;
2101 }
2102 }
2103}
2104
2105static void
2106open_previous_factory (EcoreIMFContextISF *ic)
2107{
2108 if (ic == NULL)
2109 return;
2110
2111 SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2112 IMEngineFactoryPointer sf = _backend->get_previous_factory ("", "UTF-8", ic->impl->si->get_factory_uuid ());
2113
2114 if (!sf.null ())
2115 {
2116 turn_off_ic (ic);
2117 ic->impl->si = sf->create_instance ("UTF-8", ic->impl->si->get_id ());
2118 ic->impl->si->set_frontend_data (static_cast <void*> (ic));
2119 ic->impl->preedit_string = WideString ();
2120 ic->impl->preedit_caret = 0;
2121 attach_instance (ic->impl->si);
2122 _backend->set_default_factory (_language, sf->get_uuid ());
2123 _panel_client.register_input_context (ic->id, sf->get_uuid ());
2124 set_ic_capabilities (ic);
2125 turn_on_ic (ic);
2126
2127 if (_shared_input_method)
2128 {
2129 _default_instance = ic->impl->si;
2130 ic->impl->shared_si = true;
2131 }
2132 }
2133}
2134
2135static void
2136open_specific_factory (EcoreIMFContextISF *ic,
2137 const String &uuid)
2138{
2139 if (ic == NULL)
2140 return;
2141
2142 SCIM_DEBUG_FRONTEND(2) << __FUNCTION__ << " context=" << ic->id << "\n";
2143
2144 // The same input method is selected, just turn on the IC.
2145 if (ic->impl->si->get_factory_uuid () == uuid)
2146 {
2147 turn_on_ic (ic);
2148 return;
2149 }
2150
2151 IMEngineFactoryPointer sf = _backend->get_factory (uuid);
2152
2153 if (uuid.length () && !sf.null ())
2154 {
2155 turn_off_ic (ic);
2156 ic->impl->si = sf->create_instance ("UTF-8", ic->impl->si->get_id ());
2157 ic->impl->si->set_frontend_data (static_cast <void*> (ic));
2158 ic->impl->preedit_string = WideString ();
2159 ic->impl->preedit_caret = 0;
2160 attach_instance (ic->impl->si);
2161 _backend->set_default_factory (_language, sf->get_uuid ());
2162 _panel_client.register_input_context (ic->id, sf->get_uuid ());
2163 set_ic_capabilities (ic);
2164 turn_on_ic (ic);
2165
2166 if (_shared_input_method)
2167 {
2168 _default_instance = ic->impl->si;
2169 ic->impl->shared_si = true;
2170 }
2171 }
2172 else
2173 {
2174 // turn_off_ic comment out panel_req_update_factory_info ()
2175 turn_off_ic (ic);
2176 if (ic && ic->impl->is_on)
2177 {
2178 ic->impl->is_on = false;
2179
2180 if (ic == _focused_ic)
2181 {
2182 ic->impl->si->focus_out ();
2183
2184 panel_req_update_factory_info (ic);
2185 _panel_client.turn_off (ic->id);
2186 }
2187
2188 //Record the IC on/off status
2189 if (_shared_input_method)
2190 _config->write (String (SCIM_CONFIG_FRONTEND_IM_OPENED_BY_DEFAULT), false);
2191
2192 if (ic->impl->use_preedit && ic->impl->preedit_string.length ())
2193 {
2194 ecore_imf_context_preedit_changed_event_add (ic->ctx);
2195 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2196 ecore_imf_context_preedit_end_event_add (ic->ctx);
2197 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2198 ic->impl->preedit_started = false;
2199 }
2200 }
2201 }
2202}
2203
2204static void initialize_modifier_bits (Display *display)
2205{
2206 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2207
2208 if (__current_display == display)
2209 return;
2210
2211 __current_display = display;
2212
2213 if (display == 0)
2214 {
2215 __current_alt_mask = Mod1Mask;
2216 __current_meta_mask = ShiftMask | Mod1Mask;
2217 __current_super_mask = 0;
2218 __current_hyper_mask = 0;
2219 __current_numlock_mask = Mod2Mask;
2220 return;
2221 }
2222
2223 XModifierKeymap *mods = NULL;
2224
2225 ::KeyCode ctrl_l = XKeysymToKeycode (display, XK_Control_L);
2226 ::KeyCode ctrl_r = XKeysymToKeycode (display, XK_Control_R);
2227 ::KeyCode meta_l = XKeysymToKeycode (display, XK_Meta_L);
2228 ::KeyCode meta_r = XKeysymToKeycode (display, XK_Meta_R);
2229 ::KeyCode alt_l = XKeysymToKeycode (display, XK_Alt_L);
2230 ::KeyCode alt_r = XKeysymToKeycode (display, XK_Alt_R);
2231 ::KeyCode super_l = XKeysymToKeycode (display, XK_Super_L);
2232 ::KeyCode super_r = XKeysymToKeycode (display, XK_Super_R);
2233 ::KeyCode hyper_l = XKeysymToKeycode (display, XK_Hyper_L);
2234 ::KeyCode hyper_r = XKeysymToKeycode (display, XK_Hyper_R);
2235 ::KeyCode numlock = XKeysymToKeycode (display, XK_Num_Lock);
2236
2237 int i, j;
2238
2239 mods = XGetModifierMapping (display);
2240 if (mods == NULL)
2241 return;
2242
2243 __current_alt_mask = 0;
2244 __current_meta_mask = 0;
2245 __current_super_mask = 0;
2246 __current_hyper_mask = 0;
2247 __current_numlock_mask = 0;
2248
2249 /* We skip the first three sets for Shift, Lock, and Control. The
2250 remaining sets are for Mod1, Mod2, Mod3, Mod4, and Mod5. */
2251 for (i = 3; i < 8; i++)
2252 {
2253 for (j = 0; j < mods->max_keypermod; j++)
2254 {
2255 ::KeyCode code = mods->modifiermap [i * mods->max_keypermod + j];
2256 if (! code) continue;
2257 if (code == alt_l || code == alt_r)
2258 __current_alt_mask |= (1 << i);
2259 else if (code == meta_l || code == meta_r)
2260 __current_meta_mask |= (1 << i);
2261 else if (code == super_l || code == super_r)
2262 __current_super_mask |= (1 << i);
2263 else if (code == hyper_l || code == hyper_r)
2264 __current_hyper_mask |= (1 << i);
2265 else if (code == numlock)
2266 __current_numlock_mask |= (1 << i);
2267 }
2268 }
2269
2270 /* Check whether there is a combine keys mapped to Meta */
2271 if (__current_meta_mask == 0)
2272 {
2273 char buf [32];
2274 XKeyEvent xkey;
2275 KeySym keysym_l, keysym_r;
2276
2277 xkey.type = KeyPress;
2278 xkey.display = display;
2279 xkey.serial = 0L;
2280 xkey.send_event = False;
2281 xkey.x = xkey.y = xkey.x_root = xkey.y_root = 0;
2282 xkey.time = 0;
2283 xkey.same_screen = False;
2284 xkey.subwindow = None;
2285 xkey.window = None;
2286 xkey.root = DefaultRootWindow (display);
2287 xkey.state = ShiftMask;
2288
2289 xkey.keycode = meta_l;
2290 XLookupString (&xkey, buf, 32, &keysym_l, 0);
2291 xkey.keycode = meta_r;
2292 XLookupString (&xkey, buf, 32, &keysym_r, 0);
2293
2294 if ((meta_l == alt_l && keysym_l == XK_Meta_L) || (meta_r == alt_r && keysym_r == XK_Meta_R))
2295 __current_meta_mask = ShiftMask + __current_alt_mask;
2296 else if ((meta_l == ctrl_l && keysym_l == XK_Meta_L) || (meta_r == ctrl_r && keysym_r == XK_Meta_R))
2297 __current_meta_mask = ShiftMask + ControlMask;
2298 }
2299
2300 XFreeModifiermap (mods);
2301}
2302
2303static unsigned int scim_x11_keymask_scim_to_x11 (Display *display, uint16 scimkeymask)
2304{
2305 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2306
2307 unsigned int state = 0;
2308
2309 initialize_modifier_bits (display);
2310
2311 if (scimkeymask & SCIM_KEY_ShiftMask) state |= ShiftMask;
2312 if (scimkeymask & SCIM_KEY_CapsLockMask) state |= LockMask;
2313 if (scimkeymask & SCIM_KEY_ControlMask) state |= ControlMask;
2314 if (scimkeymask & SCIM_KEY_AltMask) state |= __current_alt_mask;
2315 if (scimkeymask & SCIM_KEY_MetaMask) state |= __current_meta_mask;
2316 if (scimkeymask & SCIM_KEY_SuperMask) state |= __current_super_mask;
2317 if (scimkeymask & SCIM_KEY_HyperMask) state |= __current_hyper_mask;
2318 if (scimkeymask & SCIM_KEY_NumLockMask) state |= __current_numlock_mask;
2319
2320 return state;
2321}
2322
2323static XKeyEvent createKeyEvent (Display *display, Window &win,
2324 Window &winRoot, bool press,
2325 int keycode, int modifiers)
2326{
2327 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2328
2329 XKeyEvent event;
2330
2331 event.display = display;
2332 event.window = win;
2333 event.root = winRoot;
2334 event.subwindow = None;
2335 event.time = CurrentTime;
2336 event.x = 1;
2337 event.y = 1;
2338 event.x_root = 1;
2339 event.y_root = 1;
2340 event.same_screen = EINA_TRUE;
2341 event.state = modifiers;
2342 event.keycode = XKeysymToKeycode (display, keycode);
2343 if (press)
2344 event.type = KeyPress;
2345 else
2346 event.type = KeyRelease;
2347 event.send_event = EINA_FALSE;
2348 event.serial = 0;
2349
2350 return event;
2351}
2352
2353static void _x_send_key_event (const KeyEvent &key)
2354{
2355 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2356
2357 // Obtain the X11 display.
2358 Display *display = XOpenDisplay (NULL);
2359 if (display == NULL)
2360 {
2361 std::cerr << "XOpenDisplay failed\n";
2362 return;
2363 }
2364
2365 // Get the root window for the current display.
2366 Window winRoot = 0;// = XRootWindow (display, 1);
2367
2368 // Find the window which has the current keyboard focus.
2369 Window winFocus = 0;
2370 int revert = RevertToParent;
2371
2372 XGetInputFocus (display, &winFocus, &revert);
2373
2374 // Send a fake key press event to the window.
2375 XSelectInput (display, winFocus, FocusChangeMask|KeyPressMask|KeyReleaseMask);
2376 XMapWindow (display, winFocus);
2377
2378 unsigned int modifier = scim_x11_keymask_scim_to_x11 (display, key.mask);
2379 XKeyEvent event;
2380 if (key.is_key_press ())
2381 {
2382 event = createKeyEvent (display, winFocus, winRoot, true, key.code, modifier);
2383 XSendEvent (event.display, event.window, True, KeyPressMask, (XEvent *)&event);
2384 }
2385 else
2386 {
2387 event = createKeyEvent (display, winFocus, winRoot, false, key.code, modifier);
2388 XSendEvent (event.display, event.window, True, KeyReleaseMask, (XEvent *)&event);
2389 }
2390
2391 XCloseDisplay (display);
2392}
2393
2394static void
2395attach_instance (const IMEngineInstancePointer &si)
2396{
2397 si->signal_connect_show_preedit_string (
2398 slot (slot_show_preedit_string));
2399 si->signal_connect_show_aux_string (
2400 slot (slot_show_aux_string));
2401 si->signal_connect_show_lookup_table (
2402 slot (slot_show_lookup_table));
2403
2404 si->signal_connect_hide_preedit_string (
2405 slot (slot_hide_preedit_string));
2406 si->signal_connect_hide_aux_string (
2407 slot (slot_hide_aux_string));
2408 si->signal_connect_hide_lookup_table (
2409 slot (slot_hide_lookup_table));
2410
2411 si->signal_connect_update_preedit_caret (
2412 slot (slot_update_preedit_caret));
2413 si->signal_connect_update_preedit_string (
2414 slot (slot_update_preedit_string));
2415 si->signal_connect_update_aux_string (
2416 slot (slot_update_aux_string));
2417 si->signal_connect_update_lookup_table (
2418 slot (slot_update_lookup_table));
2419
2420 si->signal_connect_commit_string (
2421 slot (slot_commit_string));
2422
2423 si->signal_connect_forward_key_event (
2424 slot (slot_forward_key_event));
2425
2426 si->signal_connect_register_properties (
2427 slot (slot_register_properties));
2428
2429 si->signal_connect_update_property (
2430 slot (slot_update_property));
2431
2432 si->signal_connect_beep (
2433 slot (slot_beep));
2434
2435 si->signal_connect_start_helper (
2436 slot (slot_start_helper));
2437
2438 si->signal_connect_stop_helper (
2439 slot (slot_stop_helper));
2440
2441 si->signal_connect_send_helper_event (
2442 slot (slot_send_helper_event));
2443
2444 si->signal_connect_get_surrounding_text (
2445 slot (slot_get_surrounding_text));
2446
2447 si->signal_connect_delete_surrounding_text (
2448 slot (slot_delete_surrounding_text));
2449}
2450
2451// Implementation of slot functions
2452static void
2453slot_show_preedit_string (IMEngineInstanceBase *si)
2454{
2455 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2456
2457 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2458
2459 if (ic && ic->impl && _focused_ic == ic)
2460 {
2461 if (ic->impl->use_preedit)
2462 {
2463 if (!ic->impl->preedit_started)
2464 {
2465 ecore_imf_context_preedit_start_event_add (_focused_ic->ctx);
2466 ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2467 ic->impl->preedit_started = true;
2468 }
2469 }
2470 else
2471 _panel_client.show_preedit_string (ic->id);
2472 }
2473}
2474
2475static void
2476slot_show_aux_string (IMEngineInstanceBase *si)
2477{
2478 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2479
2480 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2481
2482 if (ic && ic->impl && _focused_ic == ic)
2483 _panel_client.show_aux_string (ic->id);
2484}
2485
2486static void
2487slot_show_lookup_table (IMEngineInstanceBase *si)
2488{
2489 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2490
2491 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2492
2493 if (ic && ic->impl && _focused_ic == ic)
2494 _panel_client.show_lookup_table (ic->id);
2495}
2496
2497static void
2498slot_hide_preedit_string (IMEngineInstanceBase *si)
2499{
2500 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2501
2502 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2503
2504 if (ic && ic->impl && _focused_ic == ic)
2505 {
2506 bool emit = false;
2507 if (ic->impl->preedit_string.length ())
2508 {
2509 ic->impl->preedit_string = WideString ();
2510 ic->impl->preedit_caret = 0;
2511 ic->impl->preedit_attrlist.clear ();
2512 emit = true;
2513 }
2514 if (ic->impl->use_preedit)
2515 {
2516 if (emit)
2517 {
2518 ecore_imf_context_preedit_changed_event_add (ic->ctx);
2519 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2520 }
2521 if (ic->impl->preedit_started)
2522 {
2523 ecore_imf_context_preedit_end_event_add (ic->ctx);
2524 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
2525 ic->impl->preedit_started = false;
2526 }
2527 }
2528 else
2529 _panel_client.hide_preedit_string (ic->id);
2530 }
2531}
2532
2533static void
2534slot_hide_aux_string (IMEngineInstanceBase *si)
2535{
2536 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2537
2538 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2539
2540 if (ic && ic->impl && _focused_ic == ic)
2541 _panel_client.hide_aux_string (ic->id);
2542}
2543
2544static void
2545slot_hide_lookup_table (IMEngineInstanceBase *si)
2546{
2547 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2548
2549 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2550
2551 if (ic && ic->impl && _focused_ic == ic)
2552 _panel_client.hide_lookup_table (ic->id);
2553}
2554
2555static void
2556slot_update_preedit_caret (IMEngineInstanceBase *si, int caret)
2557{
2558 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2559
2560 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2561
2562 if (ic && ic->impl && _focused_ic == ic && ic->impl->preedit_caret != caret)
2563 {
2564 ic->impl->preedit_caret = caret;
2565 if (ic->impl->use_preedit)
2566 {
2567 if (!ic->impl->preedit_started)
2568 {
2569 ecore_imf_context_preedit_start_event_add (ic->ctx);
2570 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2571 ic->impl->preedit_started = true;
2572 }
2573 ecore_imf_context_preedit_changed_event_add (ic->ctx);
2574 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2575 }
2576 else
2577 _panel_client.update_preedit_caret (ic->id, caret);
2578 }
2579}
2580
2581static void
2582slot_update_preedit_string (IMEngineInstanceBase *si,
2583 const WideString & str,
2584 const AttributeList & attrs)
2585{
2586 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2587
2588 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2589
2590 if (ic && ic->impl && _focused_ic == ic && (ic->impl->preedit_string != str || str.length ()))
2591 {
2592 ic->impl->preedit_string = str;
2593 ic->impl->preedit_attrlist = attrs;
2594 if (ic->impl->use_preedit)
2595 {
2596 if (!ic->impl->preedit_started)
2597 {
2598 ecore_imf_context_preedit_start_event_add (_focused_ic->ctx);
2599 ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
2600 ic->impl->preedit_started = true;
2601 }
2602 ic->impl->preedit_caret = str.length ();
2603 ic->impl->preedit_updating = true;
2604 ecore_imf_context_preedit_changed_event_add (ic->ctx);
2605 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
2606 ic->impl->preedit_updating = false;
2607 }
2608 else
2609 {
2610 _panel_client.update_preedit_string (ic->id, str, attrs);
2611 }
2612 }
2613}
2614
2615static void
2616slot_update_aux_string (IMEngineInstanceBase *si,
2617 const WideString & str,
2618 const AttributeList & attrs)
2619{
2620 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2621
2622 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2623
2624 if (ic && ic->impl && _focused_ic == ic)
2625 _panel_client.update_aux_string (ic->id, str, attrs);
2626}
2627
2628static void
2629slot_commit_string (IMEngineInstanceBase *si,
2630 const WideString & str)
2631{
2632 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2633
2634 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2635
2636 if (ic && ic->ctx)
2637 {
2638 ecore_imf_context_commit_event_add (ic->ctx, utf8_wcstombs (str).c_str ());
2639 ecore_imf_context_event_callback_call(ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
2640 }
2641}
2642
2643static void
2644slot_forward_key_event (IMEngineInstanceBase *si,
2645 const KeyEvent & key)
2646{
2647 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2648
2649 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2650
2651 if (ic && _focused_ic == ic)
2652 {
2653 if (!_fallback_instance->process_key_event (key))
2654 _x_send_key_event(key);
2655 }
2656}
2657
2658static void
2659slot_update_lookup_table (IMEngineInstanceBase *si,
2660 const LookupTable & table)
2661{
2662 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2663
2664 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2665
2666 if (ic && ic->impl && _focused_ic == ic)
2667 _panel_client.update_lookup_table (ic->id, table);
2668}
2669
2670static void
2671slot_register_properties (IMEngineInstanceBase *si,
2672 const PropertyList & properties)
2673{
2674 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2675
2676 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2677
2678 if (ic && ic->impl && _focused_ic == ic)
2679 _panel_client.register_properties (ic->id, properties);
2680}
2681
2682static void
2683slot_update_property (IMEngineInstanceBase *si,
2684 const Property & property)
2685{
2686 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2687
2688 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2689
2690 if (ic && ic->impl && _focused_ic == ic)
2691 _panel_client.update_property (ic->id, property);
2692}
2693
2694static void
2695slot_beep (IMEngineInstanceBase *si __UNUSED__)
2696{
2697 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2698}
2699
2700static void
2701slot_start_helper (IMEngineInstanceBase *si,
2702 const String &helper_uuid)
2703{
2704 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2705
2706 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
2707 << (ic ? ic->id : -1) << " ic=" << ic
2708 << " ic-uuid=" << ((ic ) ? ic->impl->si->get_factory_uuid () : "") << "...\n";
2709
2710 if (ic && ic->impl)
2711 _panel_client.start_helper (ic->id, helper_uuid);
2712}
2713
2714static void
2715slot_stop_helper (IMEngineInstanceBase *si,
2716 const String &helper_uuid)
2717{
2718 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2719
2720 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context=" << (ic ? ic->id : -1) << " ic=" << ic << "...\n";
2721
2722 if (ic && ic->impl)
2723 _panel_client.stop_helper (ic->id, helper_uuid);
2724}
2725
2726static void
2727slot_send_helper_event (IMEngineInstanceBase *si,
2728 const String &helper_uuid,
2729 const Transaction &trans)
2730{
2731 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2732
2733 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << " helper= " << helper_uuid << " context="
2734 << (ic ? ic->id : -1) << " ic=" << ic
2735 << " ic-uuid=" << ((ic) ? ic->impl->si->get_factory_uuid () : "") << "...\n";
2736
2737 if (ic && ic->impl)
2738 _panel_client.send_helper_event (ic->id, helper_uuid, trans);
2739}
2740
2741static bool
2742slot_get_surrounding_text (IMEngineInstanceBase *si,
2743 WideString &text,
2744 int &cursor,
2745 int maxlen_before,
2746 int maxlen_after)
2747{
2748 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2749
2750 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2751
2752 if (ic && ic->impl && _focused_ic == ic)
2753 {
2754 char *surrounding = NULL;
2755 int cursor_index;
2756 if (ecore_imf_context_surrounding_get (_focused_ic->ctx, &surrounding, &cursor_index))
2757 {
2758 SCIM_DEBUG_FRONTEND(2) << "Surrounding text: " << surrounding <<"\n";
2759 SCIM_DEBUG_FRONTEND(2) << "Cursor Index : " << cursor_index <<"\n";
2760 WideString before (utf8_mbstowcs (String (surrounding, surrounding + cursor_index)));
2761 WideString after (utf8_mbstowcs (String (surrounding + cursor_index)));
2762 if (maxlen_before > 0 && ((unsigned int)maxlen_before) < before.length ())
2763 before = WideString (before.begin () + (before.length () - maxlen_before), before.end ());
2764 else if (maxlen_before == 0) before = WideString ();
2765 if (maxlen_after > 0 && ((unsigned int)maxlen_after) < after.length ())
2766 after = WideString (after.begin (), after.begin () + maxlen_after);
2767 else if (maxlen_after == 0) after = WideString ();
2768 text = before + after;
2769 cursor = before.length ();
2770 return true;
2771 }
2772 }
2773 return false;
2774}
2775
2776static bool
2777slot_delete_surrounding_text (IMEngineInstanceBase *si,
2778 int offset,
2779 int len)
2780{
2781 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2782
2783 EcoreIMFContextISF *ic = static_cast<EcoreIMFContextISF *> (si->get_frontend_data ());
2784
2785 if (ic && ic->impl && _focused_ic == ic)
2786 {
2787 Ecore_IMF_Event_Delete_Surrounding ev;
2788 ev.ctx = _focused_ic->ctx;
2789 ev.n_chars = len;
2790 ev.offset = offset;
2791 ecore_imf_context_delete_surrounding_event_add (_focused_ic->ctx, offset, len);
2792 ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
2793 return true;
2794 }
2795 return false;
2796}
2797
2798static void
2799reload_config_callback (const ConfigPointer &config)
2800{
2801 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2802
2803 _frontend_hotkey_matcher.load_hotkeys (config);
2804 _imengine_hotkey_matcher.load_hotkeys (config);
2805
2806 KeyEvent key;
2807
2808 scim_string_to_key (key,
2809 config->read (String (SCIM_CONFIG_HOTKEYS_FRONTEND_VALID_KEY_MASK),
2810 String ("Shift+Control+Alt+Lock")));
2811
2812 _valid_key_mask = (key.mask > 0)?(key.mask):0xFFFF;
2813 _valid_key_mask |= SCIM_KEY_ReleaseMask;
2814 // Special treatment for two backslash keys on jp106 keyboard.
2815 _valid_key_mask |= SCIM_KEY_QuirkKanaRoMask;
2816
2817 _on_the_spot = config->read (String (SCIM_CONFIG_FRONTEND_ON_THE_SPOT), _on_the_spot);
2818 _shared_input_method = config->read (String (SCIM_CONFIG_FRONTEND_SHARED_INPUT_METHOD), _shared_input_method);
2819
2820 // Get keyboard layout setting
2821 // Flush the global config first, in order to load the new configs from disk.
2822 scim_global_config_flush ();
2823
2824 _keyboard_layout = scim_get_default_keyboard_layout ();
2825}
2826
2827static void
2828fallback_commit_string_cb (IMEngineInstanceBase *si __UNUSED__,
2829 const WideString &str)
2830{
2831 SCIM_DEBUG_FRONTEND(1) << __FUNCTION__ << "...\n";
2832
2833 if (_focused_ic && _focused_ic->impl)
2834 {
2835 ecore_imf_context_commit_event_add (_focused_ic->ctx, utf8_wcstombs (str).c_str ());
2836 ecore_imf_context_event_callback_call(_focused_ic->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)utf8_wcstombs(str).c_str());
2837 }
2838}
2839