7 #include <Ecore_Input.h>
11 #include <X11/Xlocale.h>
12 #include <X11/Xutil.h>
19 #define CLAMP(x, low, high) (x > high) ? high : (x < low) ? low : x
23 static Eina_List *open_ims = NULL;
26 #define FEEDBACK_MASK (XIMReverse | XIMUnderline | XIMHighlight)
28 typedef struct _XIM_Im_Info XIM_Im_Info;
30 typedef struct _Ecore_IMF_Context_Data Ecore_IMF_Context_Data;
35 Ecore_IMF_Context_Data *user;
39 Eina_Bool reconnecting;
40 XIMStyles *xim_styles;
41 Eina_Bool supports_string_conversion : 1;
42 Eina_Bool supports_cursor : 1;
45 struct _Ecore_IMF_Context_Data
49 XIC ic; /* Input context for composed characters */
54 Eina_Unicode *preedit_chars;
55 Eina_Bool use_preedit;
58 Eina_Bool in_toplevel;
59 XIMFeedback *feedbacks;
61 XIMCallback destroy_cb;
63 XIMCallback preedit_start_cb;
64 XIMCallback preedit_done_cb;
65 XIMCallback preedit_draw_cb;
66 XIMCallback preedit_caret_cb;
70 Ecore_IMF_Context_Data *imf_context_data_new();
71 void imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data);
74 static void add_feedback_attr(Eina_List **attrs,
80 static void reinitialize_ic(Ecore_IMF_Context *ctx);
81 static void set_ic_client_window(Ecore_IMF_Context *ctx,
82 Ecore_X_Window window);
83 static int preedit_start_callback(XIC xic,
86 static void preedit_done_callback(XIC xic,
89 static int xim_text_to_utf8(Ecore_IMF_Context *ctx,
92 static void preedit_draw_callback(XIC xic,
94 XIMPreeditDrawCallbackStruct *call_data);
95 static void preedit_caret_callback(XIC xic,
97 XIMPreeditCaretCallbackStruct *call_data);
98 static XVaNestedList preedit_callback_set(Ecore_IMF_Context *ctx);
99 static XIC get_ic(Ecore_IMF_Context *ctx);
100 static XIM_Im_Info *get_im(Ecore_X_Window window,
102 static void xim_info_try_im(XIM_Im_Info *info);
103 static void xim_info_display_closed(Ecore_X_Display *display,
106 static void xim_instantiate_callback(Display *display,
107 XPointer client_data,
109 static void setup_im(XIM_Im_Info *info);
110 static void xim_destroy_callback(XIM xim,
111 XPointer client_data,
117 utf8_offset_to_index(const char *str, int offset)
121 for (i = 0; i < offset; i++)
123 eina_unicode_utf8_get_next(str, &idx);
132 _ecore_imf_context_xim_add(Ecore_IMF_Context *ctx)
136 Ecore_IMF_Context_Data *imf_context_data = NULL;
138 imf_context_data = imf_context_data_new();
139 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
141 imf_context_data->use_preedit = EINA_TRUE;
142 imf_context_data->finalizing = EINA_FALSE;
143 imf_context_data->has_focus = EINA_FALSE;
144 imf_context_data->in_toplevel = EINA_FALSE;
146 ecore_imf_context_data_set(ctx, imf_context_data);
153 _ecore_imf_context_xim_del(Ecore_IMF_Context *ctx)
157 Ecore_IMF_Context_Data *imf_context_data;
158 imf_context_data = ecore_imf_context_data_get(ctx);
159 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
161 imf_context_data->finalizing = EINA_TRUE;
162 if (imf_context_data->im_info && !imf_context_data->im_info->ics->next)
164 if (imf_context_data->im_info->reconnecting == EINA_TRUE)
166 Ecore_X_Display *dsp;
167 dsp = ecore_x_display_get();
168 XUnregisterIMInstantiateCallback(dsp,
170 xim_instantiate_callback,
171 (XPointer)imf_context_data->im_info);
173 else if (imf_context_data->im_info->im)
175 XIMCallback im_destroy_callback;
176 im_destroy_callback.client_data = NULL;
177 im_destroy_callback.callback = NULL;
178 XSetIMValues(imf_context_data->im_info->im,
179 XNDestroyCallback, &im_destroy_callback,
184 set_ic_client_window(ctx, 0);
186 imf_context_data_destroy(imf_context_data);
193 _ecore_imf_context_xim_client_window_set(Ecore_IMF_Context *ctx,
198 set_ic_client_window(ctx, (Ecore_X_Window)((Ecore_Window)window));
206 _ecore_imf_context_xim_preedit_string_get(Ecore_IMF_Context *ctx,
212 Ecore_IMF_Context_Data *imf_context_data;
215 imf_context_data = ecore_imf_context_data_get(ctx);
216 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
218 if (imf_context_data->preedit_chars)
220 utf8 = eina_unicode_unicode_to_utf8(imf_context_data->preedit_chars,
236 *cursor_pos = imf_context_data->preedit_cursor;
247 _ecore_imf_context_xim_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
255 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
257 _ecore_imf_context_xim_preedit_string_get(ctx, str, cursor_pos);
260 if (!imf_context_data || !imf_context_data->feedbacks) return;
263 XIMFeedback last_feedback = 0;
266 for (i = 0; i < imf_context_data->preedit_length; i++)
268 XIMFeedback new_feedback = imf_context_data->feedbacks[i] & FEEDBACK_MASK;
270 if (new_feedback != last_feedback)
273 add_feedback_attr(attrs, *str, last_feedback, start, i);
275 last_feedback = new_feedback;
281 add_feedback_attr(attrs, *str, last_feedback, start, i);
294 _ecore_imf_context_xim_focus_in(Ecore_IMF_Context *ctx)
299 Ecore_IMF_Context_Data *imf_context_data;
300 imf_context_data = ecore_imf_context_data_get(ctx);
301 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
303 ic = imf_context_data->ic;
304 imf_context_data->has_focus = EINA_TRUE;
306 if (ecore_imf_context_input_panel_enabled_get(ctx))
307 ecore_imf_context_input_panel_show(ctx);
313 #ifdef X_HAVE_UTF8_STRING
314 if ((str = Xutf8ResetIC(ic)))
316 if ((str = XmbResetIC(ic)))
328 _ecore_imf_context_xim_focus_out(Ecore_IMF_Context *ctx)
330 EINA_LOG_DBG("%s in", __FUNCTION__);
333 Ecore_IMF_Context_Data *imf_context_data;
334 imf_context_data = ecore_imf_context_data_get(ctx);
335 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
337 if (imf_context_data->has_focus == EINA_TRUE)
339 imf_context_data->has_focus = EINA_FALSE;
340 ic = imf_context_data->ic;
344 if (ecore_imf_context_input_panel_enabled_get(ctx))
345 ecore_imf_context_input_panel_hide(ctx);
353 _ecore_imf_context_xim_reset(Ecore_IMF_Context *ctx)
355 EINA_LOG_DBG("%s in", __FUNCTION__);
358 Ecore_IMF_Context_Data *imf_context_data;
361 /* restore conversion state after resetting ic later */
362 XIMPreeditState preedit_state = XIMPreeditUnKnown;
363 XVaNestedList preedit_attr;
364 Eina_Bool have_preedit_state = EINA_FALSE;
366 imf_context_data = ecore_imf_context_data_get(ctx);
367 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
369 ic = imf_context_data->ic;
373 if (imf_context_data->preedit_length == 0)
376 preedit_attr = XVaCreateNestedList(0,
377 XNPreeditState, &preedit_state,
379 if (!XGetICValues(ic,
380 XNPreeditAttributes, preedit_attr,
382 have_preedit_state = EINA_TRUE;
386 result = XmbResetIC(ic);
388 preedit_attr = XVaCreateNestedList(0,
389 XNPreeditState, preedit_state,
391 if (have_preedit_state)
393 XNPreeditAttributes, preedit_attr,
398 if (imf_context_data->feedbacks)
400 free(imf_context_data->feedbacks);
401 imf_context_data->feedbacks = NULL;
404 if (imf_context_data->preedit_length)
406 imf_context_data->preedit_length = 0;
407 free(imf_context_data->preedit_chars);
408 imf_context_data->preedit_chars = NULL;
410 ecore_imf_context_preedit_changed_event_add(ctx);
411 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
416 char *result_utf8 = strdup(result);
419 ecore_imf_context_commit_event_add(ctx, result_utf8);
420 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, result_utf8);
432 _ecore_imf_context_xim_use_preedit_set(Ecore_IMF_Context *ctx,
433 Eina_Bool use_preedit)
437 Ecore_IMF_Context_Data *imf_context_data;
438 imf_context_data = ecore_imf_context_data_get(ctx);
439 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
441 use_preedit = use_preedit != EINA_FALSE;
443 if (imf_context_data->use_preedit != use_preedit)
445 imf_context_data->use_preedit = use_preedit;
446 reinitialize_ic(ctx);
456 add_feedback_attr(Eina_List **attrs,
458 XIMFeedback feedback,
462 Ecore_IMF_Preedit_Attr *attr = NULL;
464 unsigned int start_index = utf8_offset_to_index(str, start_pos);
465 unsigned int end_index = utf8_offset_to_index(str, end_pos);
467 if (feedback & FEEDBACK_MASK)
469 attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
470 attr->start_index = start_index;
471 attr->end_index = end_index;
472 *attrs = eina_list_append(*attrs, (void *)attr);
475 if (feedback & XIMUnderline)
476 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
478 if (feedback & XIMReverse)
479 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
481 if (feedback & XIMHighlight)
482 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
488 _ecore_imf_context_xim_cursor_location_set(Ecore_IMF_Context *ctx,
489 int x, int y, int w, int h)
491 EINA_LOG_DBG("%s in", __FUNCTION__);
494 Ecore_IMF_Context_Data *imf_context_data;
496 XVaNestedList preedit_attr;
499 imf_context_data = ecore_imf_context_data_get(ctx);
500 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
501 ic = imf_context_data->ic;
508 preedit_attr = XVaCreateNestedList(0,
509 XNSpotLocation, &spot,
512 XNPreeditAttributes, preedit_attr,
522 (void)(w); // yes w is unused, but only a bi-product of the algorithm
526 _ecore_imf_context_xim_input_panel_show(Ecore_IMF_Context *ctx)
528 EINA_LOG_DBG("%s in", __FUNCTION__);
531 Ecore_IMF_Context_Data *imf_context_data;
532 imf_context_data = ecore_imf_context_data_get(ctx);
533 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
535 ecore_x_e_virtual_keyboard_state_set
536 (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
543 _ecore_imf_context_xim_input_panel_hide(Ecore_IMF_Context *ctx)
545 EINA_LOG_DBG("%s in", __FUNCTION__);
548 Ecore_IMF_Context_Data *imf_context_data;
549 imf_context_data = ecore_imf_context_data_get(ctx);
550 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
552 ecore_x_e_virtual_keyboard_state_set
553 (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
561 _ecore_x_event_reverse_modifiers(unsigned int state)
563 unsigned int modifiers = 0;
565 /**< "Control" is pressed */
566 if (state & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
567 modifiers |= ECORE_X_MODIFIER_CTRL;
569 /**< "Alt" is pressed */
570 if (state & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
571 modifiers |= ECORE_X_MODIFIER_ALT;
573 /**< "Shift" is pressed */
574 if (state & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
575 modifiers |= ECORE_X_MODIFIER_SHIFT;
577 /**< "Win" (between "Ctrl" and "Alt") is pressed */
578 if (state & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
579 modifiers |= ECORE_X_MODIFIER_WIN;
581 /**< "AltGr" is pressed */
582 if (state & ECORE_IMF_KEYBOARD_MODIFIER_ALTGR)
583 modifiers |= ECORE_X_MODIFIER_ALTGR;
589 _ecore_x_event_reverse_locks(unsigned int state)
591 unsigned int locks = 0;
593 /**< "Num" lock is active */
594 if (state & ECORE_IMF_KEYBOARD_LOCK_NUM)
595 locks |= ECORE_X_LOCK_NUM;
597 if (state & ECORE_IMF_KEYBOARD_LOCK_CAPS)
598 locks |= ECORE_X_LOCK_CAPS;
600 if (state & ECORE_IMF_KEYBOARD_LOCK_SCROLL)
601 locks |= ECORE_X_LOCK_SCROLL;
607 _keycode_get(Ecore_X_Display *dsp,
612 // EINA_LOG_DBG("keyname:%s keysym:%lu", keyname, XStringToKeysym(keyname));
613 if (strcmp(keyname, "Keycode-0") == 0)
616 keycode = XKeysymToKeycode(dsp, XStringToKeysym(keyname));
624 _ecore_imf_context_xim_filter_event(Ecore_IMF_Context *ctx,
625 Ecore_IMF_Event_Type type,
626 Ecore_IMF_Event *event)
628 EINA_LOG_DBG("%s in", __FUNCTION__);
630 Ecore_IMF_Context_Data *imf_context_data;
633 Ecore_X_Display *dsp;
637 char compose_buffer[256];
639 char *compose = NULL;
641 Eina_Bool result = EINA_FALSE;
643 imf_context_data = ecore_imf_context_data_get(ctx);
644 if (!imf_context_data) return EINA_FALSE;
645 ic = imf_context_data->ic;
649 if (type == ECORE_IMF_EVENT_KEY_DOWN)
651 XKeyPressedEvent xev;
652 Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
653 EINA_LOG_DBG("ECORE_IMF_EVENT_KEY_DOWN");
655 dsp = ecore_x_display_get();
656 win = imf_context_data->win;
659 xev.serial = 0; /* hope it doesn't matter */
663 xev.root = ecore_x_window_root_get(win);
665 xev.time = ev->timestamp;
666 xev.x = xev.x_root = 0;
667 xev.y = xev.y_root = 0;
669 xev.state |= _ecore_x_event_reverse_modifiers(ev->modifiers);
670 xev.state |= _ecore_x_event_reverse_locks(ev->locks);
671 xev.keycode = _keycode_get(dsp, ev->keyname);
672 xev.same_screen = True;
677 #ifdef X_HAVE_UTF8_STRING
678 val = Xutf8LookupString(ic,
681 sizeof(compose_buffer) - 1,
684 #else /* ifdef X_HAVE_UTF8_STRING */
685 val = XmbLookupString(ic,
688 sizeof(compose_buffer) - 1,
691 #endif /* ifdef X_HAVE_UTF8_STRING */
692 if (mbstatus == XBufferOverflow)
694 tmp = malloc(sizeof (char) * (val + 1));
700 #ifdef X_HAVE_UTF8_STRING
701 val = Xutf8LookupString(ic,
707 #else /* ifdef X_HAVE_UTF8_STRING */
708 val = XmbLookupString(ic,
714 #endif /* ifdef X_HAVE_UTF8_STRING */
718 #ifndef X_HAVE_UTF8_STRING
719 compose = eina_str_convert(nl_langinfo(CODESET),
723 #endif /* ifndef X_HAVE_UTF8_STRING */
730 compose_buffer[val] = '\0';
731 #ifdef X_HAVE_UTF8_STRING
732 compose = strdup(compose_buffer);
733 #else /* ifdef X_HAVE_UTF8_STRING */
734 compose = eina_str_convert(nl_langinfo(CODESET), "UTF-8",
736 #endif /* ifdef X_HAVE_UTF8_STRING */
741 compose = strdup(ev->compose);
746 Eina_Unicode *unicode;
748 unicode = eina_unicode_utf8_to_unicode(compose, &len);
749 if (!unicode) abort();
750 if (unicode[0] >= 0x20 && unicode[0] != 0x7f)
752 ecore_imf_context_commit_event_add(ctx, compose);
753 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, compose);
770 static const Ecore_IMF_Context_Info xim_info = {
772 .description = _("X input method"),
773 .default_locales = "ko:ja:th:zh",
774 .canvas_type = "evas",
775 .canvas_required = 1,
778 static Ecore_IMF_Context_Class xim_class = {
779 .add = _ecore_imf_context_xim_add,
780 .del = _ecore_imf_context_xim_del,
781 .client_window_set = _ecore_imf_context_xim_client_window_set,
782 .client_canvas_set = NULL,
783 .show = _ecore_imf_context_xim_input_panel_show,
784 .hide = _ecore_imf_context_xim_input_panel_hide,
785 .preedit_string_get = _ecore_imf_context_xim_preedit_string_get,
786 .focus_in = _ecore_imf_context_xim_focus_in,
787 .focus_out = _ecore_imf_context_xim_focus_out,
788 .reset = _ecore_imf_context_xim_reset,
789 .cursor_position_set = NULL,
790 .use_preedit_set = _ecore_imf_context_xim_use_preedit_set,
791 .input_mode_set = NULL,
792 .filter_event = _ecore_imf_context_xim_filter_event,
793 .preedit_string_with_attributes_get = _ecore_imf_context_xim_preedit_string_with_attributes_get,
794 .prediction_allow_set = NULL,
795 .autocapital_type_set = NULL,
796 .control_panel_show = NULL,
797 .control_panel_hide = NULL,
798 .input_panel_layout_set = NULL,
799 .input_panel_layout_get = NULL,
800 .input_panel_language_set = NULL,
801 .input_panel_language_get = NULL,
802 .cursor_location_set = _ecore_imf_context_xim_cursor_location_set,
803 .input_panel_imdata_set = NULL,
804 .input_panel_imdata_get = NULL,
805 .input_panel_return_key_type_set = NULL,
806 .input_panel_return_key_disabled_set = NULL,
807 .input_panel_caps_lock_mode_set = NULL
810 static Ecore_IMF_Context *
811 xim_imf_module_create(void)
813 EINA_LOG_DBG("%s in", __FUNCTION__);
814 Ecore_IMF_Context *ctx = NULL;
816 ctx = ecore_imf_context_new(&xim_class);
827 static Ecore_IMF_Context *
828 xim_imf_module_exit(void)
834 ecore_imf_xim_init(void)
836 EINA_LOG_DBG("%s in", __FUNCTION__);
839 ecore_imf_module_register(&xim_info,
840 xim_imf_module_create,
841 xim_imf_module_exit);
847 ecore_imf_xim_shutdown(void)
852 XIM_Im_Info *info = open_ims->data;
853 Ecore_X_Display *display = ecore_x_display_get();
855 xim_info_display_closed(display, EINA_FALSE, info);
863 EINA_MODULE_INIT(ecore_imf_xim_init);
864 EINA_MODULE_SHUTDOWN(ecore_imf_xim_shutdown);
870 Ecore_IMF_Context_Data *
871 imf_context_data_new()
873 Ecore_IMF_Context_Data *imf_context_data = NULL;
876 locale = setlocale(LC_CTYPE, "");
877 if (!locale) return NULL;
879 if (!XSupportsLocale()) return NULL;
881 imf_context_data = calloc(1, sizeof(Ecore_IMF_Context_Data));
882 EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
884 imf_context_data->locale = strdup(locale);
885 if (!imf_context_data->locale) goto error;
887 return imf_context_data;
889 imf_context_data_destroy(imf_context_data);
894 imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data)
896 if (!imf_context_data)
899 if (imf_context_data->ic)
900 XDestroyIC(imf_context_data->ic);
902 free(imf_context_data->preedit_chars);
904 if (imf_context_data->feedbacks)
906 free(imf_context_data->feedbacks);
907 imf_context_data->feedbacks = NULL;
910 free(imf_context_data->locale);
911 free(imf_context_data);
915 preedit_start_callback(XIC xic __UNUSED__,
916 XPointer client_data,
917 XPointer call_data __UNUSED__)
920 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
921 Ecore_IMF_Context_Data *imf_context_data;
922 imf_context_data = ecore_imf_context_data_get(ctx);
923 if (!imf_context_data) return -1;
925 if (imf_context_data->finalizing == EINA_FALSE)
927 ecore_imf_context_preedit_start_event_add(ctx);
928 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
934 preedit_done_callback(XIC xic __UNUSED__,
935 XPointer client_data,
936 XPointer call_data __UNUSED__)
939 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
940 Ecore_IMF_Context_Data *imf_context_data;
941 imf_context_data = ecore_imf_context_data_get(ctx);
942 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
944 if (imf_context_data->preedit_length)
946 imf_context_data->preedit_length = 0;
947 free(imf_context_data->preedit_chars);
948 imf_context_data->preedit_chars = NULL;
949 ecore_imf_context_preedit_changed_event_add(ctx);
950 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
953 if (imf_context_data->finalizing == EINA_FALSE)
955 ecore_imf_context_preedit_end_event_add(ctx);
956 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
962 xim_text_to_utf8(Ecore_IMF_Context *ctx __UNUSED__,
969 if (xim_text && xim_text->string.multi_byte)
971 if (xim_text->encoding_is_wchar)
973 EINA_LOG_WARN("Wide character return from Xlib not currently supported");
978 /* XXX Convert to UTF-8 */
979 result = strdup(xim_text->string.multi_byte);
982 text_length = eina_unicode_utf8_get_len(result);
983 if (text_length != xim_text->length)
985 EINA_LOG_WARN("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length);
990 EINA_LOG_WARN("Error converting text from IM to UCS-4");
1006 preedit_draw_callback(XIC xic __UNUSED__,
1007 XPointer client_data,
1008 XIMPreeditDrawCallbackStruct *call_data)
1011 Eina_Bool ret = EINA_FALSE;
1012 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
1013 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1014 XIMText *t = call_data->text;
1016 Eina_Unicode *new_text = NULL;
1017 Eina_UStrbuf *preedit_bufs = NULL;
1018 int new_text_length;
1021 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1023 preedit_bufs = eina_ustrbuf_new();
1024 if (imf_context_data->preedit_chars)
1026 ret = eina_ustrbuf_append(preedit_bufs, imf_context_data->preedit_chars);
1027 if (ret == EINA_FALSE) goto done;
1030 new_text_length = xim_text_to_utf8(ctx, t, &tmp);
1034 new_text = eina_unicode_utf8_to_unicode((const char *)tmp, &tmp_len);
1041 ret = eina_ustrbuf_remove(preedit_bufs,
1042 call_data->chg_first, call_data->chg_length);
1044 else if (call_data->chg_length == 0)
1047 ret = eina_ustrbuf_insert(preedit_bufs, new_text, call_data->chg_first);
1049 else if (call_data->chg_length > 0)
1051 /* replace string */
1052 ret = eina_ustrbuf_remove(preedit_bufs,
1053 call_data->chg_first, call_data->chg_length);
1054 if (ret == EINA_FALSE) goto done;
1056 ret = eina_ustrbuf_insert_n(preedit_bufs, new_text,
1057 new_text_length, call_data->chg_first);
1058 if (ret == EINA_FALSE) goto done;
1066 if (ret == EINA_TRUE)
1068 free(imf_context_data->preedit_chars);
1069 imf_context_data->preedit_chars =
1070 eina_ustrbuf_string_steal(preedit_bufs);
1071 imf_context_data->preedit_length =
1072 eina_unicode_strlen(imf_context_data->preedit_chars);
1074 if (imf_context_data->feedbacks)
1076 free(imf_context_data->feedbacks);
1077 imf_context_data->feedbacks = NULL;
1080 if (imf_context_data->preedit_length > 0)
1082 imf_context_data->feedbacks = calloc(imf_context_data->preedit_length, sizeof(XIMFeedback));
1084 for (i = 0; i < imf_context_data->preedit_length; i++)
1085 imf_context_data->feedbacks[i] = t->feedback[i];
1088 ecore_imf_context_preedit_changed_event_add(ctx);
1089 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1093 eina_ustrbuf_free(preedit_bufs);
1097 preedit_caret_callback(XIC xic __UNUSED__,
1098 XPointer client_data,
1099 XIMPreeditCaretCallbackStruct *call_data)
1102 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
1103 Ecore_IMF_Context_Data *imf_context_data;
1104 imf_context_data = ecore_imf_context_data_get(ctx);
1105 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1107 if (call_data->direction == XIMAbsolutePosition)
1109 // printf("call_data->position:%d\n", call_data->position);
1110 imf_context_data->preedit_cursor = call_data->position;
1111 if (imf_context_data->finalizing == EINA_FALSE)
1113 ecore_imf_context_preedit_changed_event_add(ctx);
1114 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1119 static XVaNestedList
1120 preedit_callback_set(Ecore_IMF_Context *ctx)
1122 Ecore_IMF_Context_Data *imf_context_data;
1123 imf_context_data = ecore_imf_context_data_get(ctx);
1125 imf_context_data->preedit_start_cb.client_data = (XPointer)ctx;
1126 imf_context_data->preedit_start_cb.callback = (XIMProc)preedit_start_callback;
1128 imf_context_data->preedit_done_cb.client_data = (XPointer)ctx;
1129 imf_context_data->preedit_done_cb.callback = (XIMProc)preedit_done_callback;
1131 imf_context_data->preedit_draw_cb.client_data = (XPointer)ctx;
1132 imf_context_data->preedit_draw_cb.callback = (XIMProc)preedit_draw_callback;
1134 imf_context_data->preedit_caret_cb.client_data = (XPointer)ctx;
1135 imf_context_data->preedit_caret_cb.callback = (XIMProc)preedit_caret_callback;
1137 return XVaCreateNestedList(0,
1138 XNPreeditStartCallback,
1139 &imf_context_data->preedit_start_cb,
1140 XNPreeditDoneCallback,
1141 &imf_context_data->preedit_done_cb,
1142 XNPreeditDrawCallback,
1143 &imf_context_data->preedit_draw_cb,
1144 XNPreeditCaretCallback,
1145 &imf_context_data->preedit_caret_cb,
1150 get_ic(Ecore_IMF_Context *ctx)
1152 Ecore_IMF_Context_Data *imf_context_data;
1154 imf_context_data = ecore_imf_context_data_get(ctx);
1155 EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
1157 ic = imf_context_data->ic;
1160 XIM_Im_Info *im_info = imf_context_data->im_info;
1161 XVaNestedList preedit_attr = NULL;
1162 XIMStyle im_style = 0;
1163 XPoint spot = { 0, 0 };
1168 EINA_LOG_WARN("Doesn't open XIM.");
1175 if (im_info->xim_styles)
1177 for (i = 0; i < im_info->xim_styles->count_styles; i++)
1180 if (im_info->xim_styles->supported_styles[i] & XIMPreeditCallbacks)
1181 printf("XIMPreeditCallbacks | ");
1182 if (im_info->xim_styles->supported_styles[i] & XIMPreeditPosition)
1183 printf("XIMPreeditPosition | ");
1184 if (im_info->xim_styles->supported_styles[i] & XIMPreeditArea)
1185 printf("XIMPreeditArea | ");
1186 if (im_info->xim_styles->supported_styles[i] & XIMPreeditNothing)
1187 printf("XIMPreeditNothing | ");
1188 if (im_info->xim_styles->supported_styles[i] & XIMPreeditNone)
1189 printf("XIMPreeditNone | ");
1190 if (im_info->xim_styles->supported_styles[i] & XIMStatusArea)
1191 printf("XIMStatusArea | ");
1192 if (im_info->xim_styles->supported_styles[i] & XIMStatusCallbacks)
1193 printf("XIMStatusCallbacks | ");
1194 if (im_info->xim_styles->supported_styles[i] & XIMStatusNothing)
1195 printf("XIMStatusNothing | ");
1196 if (im_info->xim_styles->supported_styles[i] & XIMStatusNone)
1197 printf("XIMStatusNone | ");
1202 // "OverTheSpot" = XIMPreeditPosition | XIMStatusNothing
1203 // "OffTheSpot" = XIMPreeditArea | XIMStatusArea
1204 // "Root" = XIMPreeditNothing | XIMStatusNothing
1206 if (imf_context_data->use_preedit == EINA_TRUE)
1208 if (im_info->supports_cursor)
1210 // kinput2 DOES do this...
1212 char **missing_charset_list;
1213 int missing_charset_count;
1216 im_style |= XIMPreeditPosition;
1217 im_style |= XIMStatusNothing;
1218 fs = XCreateFontSet(ecore_x_display_get(),
1220 &missing_charset_list,
1221 &missing_charset_count,
1223 preedit_attr = XVaCreateNestedList(0,
1224 XNSpotLocation, &spot,
1230 im_style |= XIMPreeditCallbacks;
1231 im_style |= XIMStatusNothing;
1232 preedit_attr = preedit_callback_set(ctx);
1234 name = XNPreeditAttributes;
1238 im_style |= XIMPreeditNothing;
1239 im_style |= XIMStatusNothing;
1242 if (!im_info->xim_styles)
1244 EINA_LOG_WARN("No XIM styles supported! Wanted %#llx",
1245 (unsigned long long)im_style);
1250 XIMStyle fallback = 0;
1253 for (i = 0; i < im_info->xim_styles->count_styles; i++)
1255 XIMStyle cur = im_info->xim_styles->supported_styles[i];
1256 if (cur == im_style)
1258 else if (cur == (XIMPreeditNothing | XIMStatusNothing))
1259 /* TODO: fallback is just that or the anyone? */
1263 if (i == im_info->xim_styles->count_styles)
1267 EINA_LOG_WARN("Wanted XIM style %#llx not found, "
1268 "using fallback %#llx instead.",
1269 (unsigned long long)im_style,
1270 (unsigned long long)fallback);
1271 im_style = fallback;
1275 EINA_LOG_WARN("Wanted XIM style %#llx not found, "
1276 "no fallback supported.",
1277 (unsigned long long)im_style);
1283 if ((im_info->im) && (im_style))
1285 ic = XCreateIC(im_info->im,
1286 XNInputStyle, im_style,
1287 XNClientWindow, imf_context_data->win,
1288 name, preedit_attr, NULL);
1290 XFree(preedit_attr);
1293 unsigned long mask = 0xaaaaaaaa;
1295 XNFilterEvents, &mask,
1297 imf_context_data->mask = mask;
1298 ecore_x_event_mask_set(imf_context_data->win, mask);
1301 imf_context_data->ic = ic;
1302 if (ic && imf_context_data->has_focus == EINA_TRUE)
1310 reinitialize_ic(Ecore_IMF_Context *ctx)
1312 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1313 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1315 XIC ic = imf_context_data->ic;
1319 imf_context_data->ic = NULL;
1320 if (imf_context_data->preedit_length)
1322 imf_context_data->preedit_length = 0;
1323 free(imf_context_data->preedit_chars);
1324 imf_context_data->preedit_chars = NULL;
1325 ecore_imf_context_preedit_changed_event_add(ctx);
1326 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1332 set_ic_client_window(Ecore_IMF_Context *ctx,
1333 Ecore_X_Window window)
1336 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1337 Ecore_X_Window old_win;
1339 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1341 /* reinitialize IC */
1342 reinitialize_ic(ctx);
1344 old_win = imf_context_data->win;
1345 EINA_LOG_DBG("old_win:%d window:%d ", old_win, window);
1346 if (old_win != 0 && old_win != window) /* XXX how do check window... */
1349 info = imf_context_data->im_info;
1350 info->ics = eina_list_remove(info->ics, imf_context_data);
1351 if (imf_context_data->im_info)
1352 imf_context_data->im_info->user = NULL;
1353 imf_context_data->im_info = NULL;
1356 imf_context_data->win = window;
1358 if (window) /* XXX */
1360 XIM_Im_Info *info = NULL;
1361 info = get_im(window, imf_context_data->locale);
1362 imf_context_data->im_info = info;
1363 imf_context_data->im_info->ics =
1364 eina_list_prepend(imf_context_data->im_info->ics,
1366 if (imf_context_data->im_info)
1367 imf_context_data->im_info->user = imf_context_data;
1371 static XIM_Im_Info *
1372 get_im(Ecore_X_Window window,
1378 XIM_Im_Info *im_info = NULL;
1379 XIM_Im_Info *info = NULL;
1380 EINA_LIST_FOREACH (open_ims, l, im_info)
1382 if (strcmp(im_info->locale, locale) == 0)
1398 info = calloc(1, sizeof(XIM_Im_Info));
1399 if (!info) return NULL;
1400 open_ims = eina_list_prepend(open_ims, info);
1402 info->locale = strdup(locale);
1403 info->reconnecting = EINA_FALSE;
1406 xim_info_try_im(info);
1410 /* initialize info->im */
1412 xim_info_try_im(XIM_Im_Info *info)
1414 Ecore_X_Display *dsp;
1416 assert(info->im == NULL);
1417 if (info->reconnecting == EINA_TRUE)
1420 if (XSupportsLocale())
1422 if (!XSetLocaleModifiers(""))
1423 EINA_LOG_WARN("Unable to set locale modifiers with XSetLocaleModifiers()");
1424 dsp = ecore_x_display_get();
1425 info->im = XOpenIM(dsp, NULL, NULL, NULL);
1428 XRegisterIMInstantiateCallback(dsp,
1430 xim_instantiate_callback,
1432 info->reconnecting = EINA_TRUE;
1440 xim_info_display_closed(Ecore_X_Display *display __UNUSED__,
1441 int is_error __UNUSED__,
1444 Eina_List *ics, *tmp_list;
1445 Ecore_IMF_Context *ctx;
1447 open_ims = eina_list_remove(open_ims, info);
1452 EINA_LIST_FOREACH (ics, tmp_list, ctx)
1453 set_ic_client_window(ctx, 0);
1455 EINA_LIST_FREE (ics, ctx)
1457 Ecore_IMF_Context_Data *imf_context_data;
1458 imf_context_data = ecore_imf_context_data_get(ctx);
1459 imf_context_data_destroy(imf_context_data);
1471 xim_instantiate_callback(Display *display,
1472 XPointer client_data,
1473 XPointer call_data __UNUSED__)
1475 XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1478 im = XOpenIM(display, NULL, NULL, NULL);
1482 fprintf(stderr, "Failed to connect to IM\n");
1489 XUnregisterIMInstantiateCallback(display, NULL, NULL, NULL,
1490 xim_instantiate_callback,
1492 info->reconnecting = EINA_FALSE;
1496 setup_im(XIM_Im_Info *info)
1498 XIMValuesList *ic_values = NULL;
1499 XIMCallback im_destroy_callback;
1504 im_destroy_callback.client_data = (XPointer)info;
1505 im_destroy_callback.callback = (XIMProc)xim_destroy_callback;
1506 XSetIMValues(info->im,
1507 XNDestroyCallback, &im_destroy_callback,
1510 XGetIMValues(info->im,
1511 XNQueryInputStyle, &info->xim_styles,
1512 XNQueryICValuesList, &ic_values,
1519 for (i = 0; i < ic_values->count_values; i++)
1521 if (!strcmp(ic_values->supported_values[i],
1522 XNStringConversionCallback))
1523 info->supports_string_conversion = EINA_TRUE;
1524 if (!strcmp(ic_values->supported_values[i],
1526 info->supports_cursor = EINA_TRUE;
1529 printf("values........\n");
1530 for (i = 0; i < ic_values->count_values; i++)
1531 printf("%s\n", ic_values->supported_values[i]);
1532 printf("styles........\n");
1533 for (i = 0; i < info->xim_styles->count_styles; i++)
1534 printf("%lx\n", info->xim_styles->supported_styles[i]);
1541 xim_destroy_callback(XIM xim __UNUSED__,
1542 XPointer client_data,
1543 XPointer call_data __UNUSED__)
1545 XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1547 if (info->user) info->user->ic = NULL;
1549 // reinitialize_ic(ctx);
1550 xim_info_try_im(info);
1555 #endif /* ENABLE_XIM */