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