6 #include <sys/socket.h>
15 #include <Ecore_Evas.h>
18 #include "ibus_imcontext.h"
20 struct _IBusIMContext {
21 /* instance members */
22 Ecore_IMF_Context *ctx;
26 IBusInputContext *ibuscontext;
30 Eina_List *preedit_attrs;
31 int preedit_cursor_pos;
32 Eina_Bool preedit_visible;
41 Ecore_X_Window client_window;
47 static Ecore_IMF_Context *_focus_im_context = NULL;
48 static IBusBus *_bus = NULL;
50 /* functions prototype */
52 static void _create_input_context (IBusIMContext *context);
53 static void _set_cursor_location_internal
54 (Ecore_IMF_Context *ctx);
55 static void _bus_connected_cb (IBusBus *bus,
56 IBusIMContext *context);
60 _window_to_screen_geometry_get(Ecore_X_Window client_win, int *x, int *y)
62 Ecore_X_Window root_window, win;
64 int sum_x = 0, sum_y = 0;
66 root_window = ecore_x_window_root_get(client_win);
69 while (root_window != win)
71 ecore_x_window_geometry_get(win, &win_x, &win_y, NULL, NULL);
74 win = ecore_x_window_parent_get(win);
84 _ecore_imf_modifier_to_ibus_modifier(unsigned int modifier)
86 unsigned int state = 0;
88 /**< "Control" is pressed */
89 if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
90 state |= IBUS_CONTROL_MASK;
92 /**< "Alt" is pressed */
93 if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
94 state |= IBUS_MOD1_MASK;
96 /**< "Shift" is pressed */
97 if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
98 state |= IBUS_SHIFT_MASK;
100 /**< "Win" (between "Ctrl" and "A */
101 if (modifier & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
102 state |= IBUS_SUPER_MASK;
108 ibus_im_context_new(void)
110 EINA_LOG_DBG("%s", __FUNCTION__);
112 IBusIMContext *context = calloc(1, sizeof(IBusIMContext));
114 /* init bus object */
117 char *display_name = NULL;
119 if ((display_name = getenv ("DISPLAY")))
120 ibus_set_display (display_name);
122 ibus_set_display (":0.0");
124 _bus = ibus_bus_new();
131 ibus_im_context_add(Ecore_IMF_Context *ctx)
133 EINA_LOG_DBG("%s", __FUNCTION__);
135 IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
136 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
138 ibusimcontext->client_window = 0;
141 ibusimcontext->enable = EINA_FALSE;
143 // Init preedit status
144 ibusimcontext->preedit_string = NULL;
145 ibusimcontext->preedit_attrs = NULL;
146 ibusimcontext->preedit_cursor_pos = 0;
147 ibusimcontext->preedit_visible = EINA_FALSE;
150 ibusimcontext->cursor_x = -1;
151 ibusimcontext->cursor_y = -1;
152 ibusimcontext->cursor_w = 0;
153 ibusimcontext->cursor_h = 0;
155 ibusimcontext->ibuscontext = NULL;
156 ibusimcontext->has_focus = EINA_FALSE;
157 ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT;
158 ibusimcontext->ctx = ctx;
160 if (ibus_bus_is_connected(_bus))
161 _create_input_context (ibusimcontext);
163 g_signal_connect(_bus, "connected", G_CALLBACK (_bus_connected_cb), ctx);
167 ibus_im_context_del(Ecore_IMF_Context *ctx)
169 EINA_LOG_DBG("%s", __FUNCTION__);
171 IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
172 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
174 g_signal_handlers_disconnect_by_func(_bus, G_CALLBACK(_bus_connected_cb), ctx);
176 if (ibusimcontext->ibuscontext)
177 ibus_proxy_destroy((IBusProxy *)ibusimcontext->ibuscontext);
180 if (ibusimcontext->preedit_string)
181 free(ibusimcontext->preedit_string);
185 ibus_im_context_filter_event(Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event)
187 IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
188 EINA_SAFETY_ON_NULL_RETURN_VAL(ibusimcontext, EINA_FALSE);
190 if (type != ECORE_IMF_EVENT_KEY_UP && type != ECORE_IMF_EVENT_KEY_DOWN)
193 EINA_LOG_DBG("%s", __FUNCTION__);
195 if (G_LIKELY(ibusimcontext->ibuscontext && ibusimcontext->has_focus))
197 /* If context does not have focus, ibus will process key event in sync mode.
198 * It is a workaround for increase search in treeview.
200 Eina_Bool retval = EINA_FALSE;
203 unsigned int state = 0;
205 if (type == ECORE_IMF_EVENT_KEY_UP)
207 Ecore_IMF_Event_Key_Up *ev = (Ecore_IMF_Event_Key_Up *)event;
208 if (ev->timestamp == 0)
211 keycode = ecore_x_keysym_keycode_get(ev->key);
212 keysym = XStringToKeysym(ev->key);
213 state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers) | IBUS_RELEASE_MASK;
214 retval = ibus_input_context_process_key_event (ibusimcontext->ibuscontext,
219 else if (type == ECORE_IMF_EVENT_KEY_DOWN)
221 Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
222 if (ev->timestamp == 0)
225 keycode = ecore_x_keysym_keycode_get(ev->key);
226 keysym = XStringToKeysym(ev->key);
227 state = _ecore_imf_modifier_to_ibus_modifier(ev->modifiers);
228 retval = ibus_input_context_process_key_event (ibusimcontext->ibuscontext,
246 ibus_im_context_focus_in(Ecore_IMF_Context *ctx)
248 EINA_LOG_DBG("ctx : %p", ctx);
250 IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
251 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
253 if (ibusimcontext->has_focus)
256 if (_focus_im_context != NULL)
257 ecore_imf_context_focus_out(_focus_im_context);
259 ibusimcontext->has_focus = EINA_TRUE;
260 if (ibusimcontext->ibuscontext)
261 ibus_input_context_focus_in(ibusimcontext->ibuscontext);
263 if (_focus_im_context != ctx)
264 _focus_im_context = ctx;
268 ibus_im_context_focus_out(Ecore_IMF_Context *ctx)
270 EINA_LOG_DBG("ctx : %p", ctx);
272 IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
273 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
275 if (ibusimcontext->has_focus == EINA_FALSE)
278 if (_focus_im_context == ctx)
279 _focus_im_context = NULL;
281 ibusimcontext->has_focus = EINA_FALSE;
282 if (ibusimcontext->ibuscontext)
283 ibus_input_context_focus_out(ibusimcontext->ibuscontext);
287 ibus_im_context_reset(Ecore_IMF_Context *ctx)
289 IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
290 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
292 if (ibusimcontext->ibuscontext)
293 ibus_input_context_reset(ibusimcontext->ibuscontext);
297 ibus_im_context_preedit_string_get(Ecore_IMF_Context *ctx,
301 IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
302 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
304 if (ibusimcontext->enable && ibusimcontext->preedit_visible)
307 *str = strdup (ibusimcontext->preedit_string ? ibusimcontext->preedit_string: "");
310 *cursor_pos = ibusimcontext->preedit_cursor_pos;
320 EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos);
324 ibus_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
326 Eina_List **attr __UNUSED__,
329 IBusIMContext *ibusimcontext = (IBusIMContext*)ecore_imf_context_data_get(ctx);
330 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
332 if (ibusimcontext->enable && ibusimcontext->preedit_visible)
335 *str = strdup(ibusimcontext->preedit_string ? ibusimcontext->preedit_string: "");
338 *cursor_pos = ibusimcontext->preedit_cursor_pos;
348 EINA_LOG_DBG("str : %s, cursor_pos : %d", *str, *cursor_pos);
352 ibus_im_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
354 EINA_LOG_DBG("canvas : %p", window);
355 IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
356 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
359 ibusimcontext->client_window = (Ecore_X_Window)(Ecore_Window)window;
363 ibus_im_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
365 EINA_LOG_DBG("canvas : %p", canvas);
366 IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
367 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
370 ibusimcontext->client_canvas = canvas;
374 _set_cursor_location_internal(Ecore_IMF_Context *ctx)
376 IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
378 int canvas_x, canvas_y;
380 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
382 if (ibusimcontext->ibuscontext == NULL)
385 if (ibusimcontext->client_canvas)
387 ee = ecore_evas_ecore_evas_get(ibusimcontext->client_canvas);
390 ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
394 if (ibusimcontext->client_window)
395 _window_to_screen_geometry_get(ibusimcontext->client_window, &canvas_x, &canvas_y);
400 ibus_input_context_set_cursor_location(ibusimcontext->ibuscontext,
401 ibusimcontext->cursor_x + canvas_x,
402 ibusimcontext->cursor_y + canvas_y,
403 ibusimcontext->cursor_w,
404 ibusimcontext->cursor_h);
408 ibus_im_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int w, int h)
410 EINA_LOG_DBG("x : %d, y : %d, w, %d, h :%d", x, y, w, h);
411 IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
412 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
414 if (ibusimcontext->cursor_x != x ||
415 ibusimcontext->cursor_y != y ||
416 ibusimcontext->cursor_w != w ||
417 ibusimcontext->cursor_h != h)
419 ibusimcontext->cursor_x = x;
420 ibusimcontext->cursor_y = y;
421 ibusimcontext->cursor_w = w;
422 ibusimcontext->cursor_h = h;
424 _set_cursor_location_internal(ctx);
429 ibus_im_context_use_preedit_set(Ecore_IMF_Context *ctx, Eina_Bool use_preedit)
431 EINA_LOG_DBG("preedit : %d", use_preedit);
432 IBusIMContext *ibusimcontext = (IBusIMContext *)ecore_imf_context_data_get(ctx);
433 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
435 if (ibusimcontext->ibuscontext)
438 ibusimcontext->caps |= IBUS_CAP_PREEDIT_TEXT;
440 ibusimcontext->caps &= ~IBUS_CAP_PREEDIT_TEXT;
442 ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps);
447 _bus_connected_cb(IBusBus *bus __UNUSED__,
448 IBusIMContext *ibusimcontext)
450 EINA_LOG_DBG("ibus is connected");
453 _create_input_context(ibusimcontext);
457 _ibus_context_commit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
459 IBusIMContext *ibusimcontext)
461 if (!ibusimcontext || !text) return;
462 char *commit_str = text->text ? text->text : "";
464 EINA_LOG_DBG("commit string : %s", commit_str);
466 if (ibusimcontext->ctx)
468 ecore_imf_context_commit_event_add(ibusimcontext->ctx, text->text);
469 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)commit_str);
473 static XKeyEvent createXKeyEvent(Window win, Eina_Bool press, int keysym, int modifiers)
476 Display *display = ecore_x_display_get();
478 event.display = display;
480 event.root = ecore_x_window_root_get(win);
481 event.subwindow = None;
487 event.same_screen = EINA_TRUE;
488 event.state = modifiers;
489 event.keycode = XKeysymToKeycode(display, keysym);
491 event.type = KeyPress;
493 event.type = KeyRelease;
494 event.send_event = EINA_FALSE;
501 _ibus_context_forward_key_event_cb(IBusInputContext *ibuscontext __UNUSED__,
504 IBusIMContext *ibusimcontext __UNUSED__)
506 EINA_LOG_DBG("keyval : %d, state : %d", keyval, state);
508 // Find the window which has the current keyboard focus.
510 int revert = RevertToParent;
512 XGetInputFocus(ecore_x_display_get(), &winFocus, &revert);
515 if (state & IBUS_RELEASE_MASK)
517 event = createXKeyEvent(winFocus, EINA_FALSE, keyval, state);
518 XSendEvent(event.display, event.window, True, KeyReleaseMask, (XEvent *)&event);
522 event = createXKeyEvent(winFocus, EINA_TRUE, keyval, state);
523 XSendEvent(event.display, event.window, True, KeyPressMask, (XEvent *)&event);
528 _ibus_context_update_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
532 IBusIMContext *ibusimcontext)
534 if (!ibusimcontext || !text) return;
539 if (ibusimcontext->preedit_string)
540 free (ibusimcontext->preedit_string);
545 ibusimcontext->preedit_string = strdup(str);
547 ibusimcontext->preedit_string = strdup("");
549 ibusimcontext->preedit_cursor_pos = cursor_pos;
551 EINA_LOG_DBG("string : %s, cursor : %d",ibusimcontext->preedit_string, ibusimcontext->preedit_cursor_pos);
553 flag = ibusimcontext->preedit_visible != visible;
554 ibusimcontext->preedit_visible = visible;
556 if (ibusimcontext->preedit_visible)
560 ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx);
561 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
564 ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
565 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
571 ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
572 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
575 ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
576 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
581 _ibus_context_show_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
582 IBusIMContext *ibusimcontext)
584 EINA_LOG_DBG("preedit visible : %d", ibusimcontext->preedit_visible);
585 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
587 if (ibusimcontext->preedit_visible == EINA_TRUE)
590 ibusimcontext->preedit_visible = EINA_TRUE;
592 // call preedit start
593 ecore_imf_context_preedit_start_event_add(ibusimcontext->ctx);
594 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
596 // call preedit changed
597 ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
598 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
602 _ibus_context_hide_preedit_text_cb(IBusInputContext *ibuscontext __UNUSED__,
603 IBusIMContext *ibusimcontext)
605 EINA_LOG_DBG("%s", __FUNCTION__);
606 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
608 if (ibusimcontext->preedit_visible == EINA_FALSE)
611 ibusimcontext->preedit_visible = EINA_FALSE;
613 // call preedit changed
614 ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
615 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
618 ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
619 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
623 _ibus_context_enabled_cb(IBusInputContext *ibuscontext __UNUSED__,
624 IBusIMContext *ibusimcontext)
626 EINA_LOG_DBG("%s", __FUNCTION__);
627 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
629 ibusimcontext->enable = EINA_TRUE;
633 _ibus_context_disabled_cb(IBusInputContext *ibuscontext __UNUSED__,
634 IBusIMContext *ibusimcontext)
636 EINA_LOG_DBG("%s", __FUNCTION__);
637 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
639 ibusimcontext->enable = EINA_FALSE;
642 ibusimcontext->preedit_visible = EINA_FALSE;
643 ibusimcontext->preedit_cursor_pos = 0;
644 free (ibusimcontext->preedit_string);
645 ibusimcontext->preedit_string = NULL;
647 // call preedit changed
648 ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
649 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
652 ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
653 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
657 _ibus_context_destroy_cb(IBusInputContext *ibuscontext __UNUSED__,
658 IBusIMContext *ibusimcontext)
660 EINA_LOG_DBG("%s", __FUNCTION__);
661 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
663 ibusimcontext->ibuscontext = NULL;
664 ibusimcontext->enable = EINA_FALSE;
667 ibusimcontext->preedit_visible = EINA_FALSE;
668 ibusimcontext->preedit_cursor_pos = 0;
669 free (ibusimcontext->preedit_string);
670 ibusimcontext->preedit_string = NULL;
672 // call preedit changed
673 ecore_imf_context_preedit_changed_event_add(ibusimcontext->ctx);
674 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
677 ecore_imf_context_preedit_end_event_add(ibusimcontext->ctx);
678 ecore_imf_context_event_callback_call(ibusimcontext->ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
682 _create_input_context(IBusIMContext *ibusimcontext)
684 EINA_LOG_DBG("%s", __FUNCTION__);
685 EINA_SAFETY_ON_NULL_RETURN(ibusimcontext);
687 ibusimcontext->ibuscontext = ibus_bus_create_input_context(_bus, "ecore");
689 g_return_if_fail(ibusimcontext->ibuscontext != NULL);
691 g_signal_connect(ibusimcontext->ibuscontext,
693 G_CALLBACK (_ibus_context_commit_text_cb),
695 g_signal_connect(ibusimcontext->ibuscontext,
697 G_CALLBACK (_ibus_context_forward_key_event_cb),
699 g_signal_connect(ibusimcontext->ibuscontext,
700 "update-preedit-text",
701 G_CALLBACK (_ibus_context_update_preedit_text_cb),
703 g_signal_connect(ibusimcontext->ibuscontext,
705 G_CALLBACK (_ibus_context_show_preedit_text_cb),
707 g_signal_connect(ibusimcontext->ibuscontext,
709 G_CALLBACK (_ibus_context_hide_preedit_text_cb),
711 g_signal_connect(ibusimcontext->ibuscontext,
713 G_CALLBACK (_ibus_context_enabled_cb),
715 g_signal_connect(ibusimcontext->ibuscontext,
717 G_CALLBACK (_ibus_context_disabled_cb),
719 g_signal_connect(ibusimcontext->ibuscontext, "destroy",
720 G_CALLBACK (_ibus_context_destroy_cb),
723 ibus_input_context_set_capabilities(ibusimcontext->ibuscontext, ibusimcontext->caps);
725 if (ibusimcontext->has_focus)
726 ibus_input_context_focus_in(ibusimcontext->ibuscontext);