7 #include <Ecore_Input.h>
11 #include <X11/Xlocale.h>
12 #include <X11/Xutil.h>
13 #include <X11/keysym.h>
20 #define CLAMP(x, low, high) (x > high) ? high : (x < low) ? low : x
24 static Eina_List *open_ims = NULL;
27 #define FEEDBACK_MASK (XIMReverse | XIMUnderline | XIMHighlight)
29 typedef struct _XIM_Im_Info XIM_Im_Info;
36 Eina_Bool reconnecting;
37 XIMStyles *xim_styles;
38 Eina_Bool supports_string_conversion : 1;
39 Eina_Bool supports_cursor : 1;
42 typedef struct _Ecore_IMF_Context_Data Ecore_IMF_Context_Data;
43 struct _Ecore_IMF_Context_Data
47 XIC ic; /* Input context for composed characters */
52 Eina_Unicode *preedit_chars;
53 Eina_Bool use_preedit;
56 Eina_Bool in_toplevel;
57 XIMFeedback *feedbacks;
59 XIMCallback preedit_start_cb;
60 XIMCallback preedit_done_cb;
61 XIMCallback preedit_draw_cb;
62 XIMCallback preedit_caret_cb;
66 Ecore_IMF_Context_Data *imf_context_data_new();
67 void imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data);
70 static void add_feedback_attr(Eina_List **attrs,
76 static void reinitialize_ic(Ecore_IMF_Context *ctx);
77 static void reinitialize_all_ics(XIM_Im_Info *info);
78 static void set_ic_client_window(Ecore_IMF_Context *ctx,
79 Ecore_X_Window window);
80 static int preedit_start_callback(XIC xic,
83 static void preedit_done_callback(XIC xic,
86 static int xim_text_to_utf8(Ecore_IMF_Context *ctx,
89 static void preedit_draw_callback(XIC xic,
91 XIMPreeditDrawCallbackStruct *call_data);
92 static void preedit_caret_callback(XIC xic,
94 XIMPreeditCaretCallbackStruct *call_data);
95 static XVaNestedList preedit_callback_set(Ecore_IMF_Context *ctx);
96 static XIC get_ic(Ecore_IMF_Context *ctx);
97 static XIM_Im_Info *get_im(Ecore_X_Window window,
99 static void xim_info_try_im(XIM_Im_Info *info);
100 static void xim_info_display_closed(Ecore_X_Display *display,
103 static void xim_instantiate_callback(Display *display,
104 XPointer client_data,
106 static void setup_im(XIM_Im_Info *info);
107 static void xim_destroy_callback(XIM xim,
108 XPointer client_data,
114 utf8_offset_to_index(const char *str, int offset)
118 for (i = 0; i < offset; i++)
120 eina_unicode_utf8_get_next(str, &idx);
129 _ecore_imf_context_xim_add(Ecore_IMF_Context *ctx)
133 Ecore_IMF_Context_Data *imf_context_data = NULL;
135 imf_context_data = imf_context_data_new();
136 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
138 imf_context_data->use_preedit = EINA_TRUE;
139 imf_context_data->finalizing = EINA_FALSE;
140 imf_context_data->has_focus = EINA_FALSE;
141 imf_context_data->in_toplevel = EINA_FALSE;
143 ecore_imf_context_data_set(ctx, imf_context_data);
150 _ecore_imf_context_xim_del(Ecore_IMF_Context *ctx)
154 Ecore_IMF_Context_Data *imf_context_data;
155 imf_context_data = ecore_imf_context_data_get(ctx);
156 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
158 imf_context_data->finalizing = EINA_TRUE;
159 if (imf_context_data->im_info && !imf_context_data->im_info->ics->next)
161 if (imf_context_data->im_info->reconnecting == EINA_TRUE)
163 Ecore_X_Display *dsp;
164 dsp = ecore_x_display_get();
165 XUnregisterIMInstantiateCallback(dsp,
167 xim_instantiate_callback,
168 (XPointer)imf_context_data->im_info);
170 else if (imf_context_data->im_info->im)
172 XIMCallback im_destroy_callback;
173 im_destroy_callback.client_data = NULL;
174 im_destroy_callback.callback = NULL;
175 XSetIMValues(imf_context_data->im_info->im,
176 XNDestroyCallback, &im_destroy_callback,
181 set_ic_client_window(ctx, 0);
183 imf_context_data_destroy(imf_context_data);
190 _ecore_imf_context_xim_client_window_set(Ecore_IMF_Context *ctx,
195 set_ic_client_window(ctx, (Ecore_X_Window)((Ecore_Window)window));
203 _ecore_imf_context_xim_preedit_string_get(Ecore_IMF_Context *ctx,
209 Ecore_IMF_Context_Data *imf_context_data;
212 imf_context_data = ecore_imf_context_data_get(ctx);
213 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
215 if (imf_context_data->preedit_chars)
217 utf8 = eina_unicode_unicode_to_utf8(imf_context_data->preedit_chars,
233 *cursor_pos = imf_context_data->preedit_cursor;
244 _ecore_imf_context_xim_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
252 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
254 _ecore_imf_context_xim_preedit_string_get(ctx, str, cursor_pos);
257 if (!imf_context_data || !imf_context_data->feedbacks) return;
260 XIMFeedback last_feedback = 0;
263 for (i = 0; i < imf_context_data->preedit_length; i++)
265 XIMFeedback new_feedback = imf_context_data->feedbacks[i] & FEEDBACK_MASK;
267 if (new_feedback != last_feedback)
270 add_feedback_attr(attrs, *str, last_feedback, start, i);
272 last_feedback = new_feedback;
278 add_feedback_attr(attrs, *str, last_feedback, start, i);
291 _ecore_imf_context_xim_focus_in(Ecore_IMF_Context *ctx)
296 Ecore_IMF_Context_Data *imf_context_data;
297 imf_context_data = ecore_imf_context_data_get(ctx);
298 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
300 ic = imf_context_data->ic;
301 imf_context_data->has_focus = EINA_TRUE;
303 if (ecore_imf_context_input_panel_enabled_get(ctx))
304 ecore_imf_context_input_panel_show(ctx);
310 #ifdef X_HAVE_UTF8_STRING
311 if ((str = Xutf8ResetIC(ic)))
313 if ((str = XmbResetIC(ic)))
325 _ecore_imf_context_xim_focus_out(Ecore_IMF_Context *ctx)
327 EINA_LOG_DBG("%s in", __FUNCTION__);
330 Ecore_IMF_Context_Data *imf_context_data;
331 imf_context_data = ecore_imf_context_data_get(ctx);
332 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
334 if (imf_context_data->has_focus == EINA_TRUE)
336 imf_context_data->has_focus = EINA_FALSE;
337 ic = imf_context_data->ic;
341 if (ecore_imf_context_input_panel_enabled_get(ctx))
342 ecore_imf_context_input_panel_hide(ctx);
350 _ecore_imf_context_xim_reset(Ecore_IMF_Context *ctx)
352 EINA_LOG_DBG("%s in", __FUNCTION__);
355 Ecore_IMF_Context_Data *imf_context_data;
358 /* restore conversion state after resetting ic later */
359 XIMPreeditState preedit_state = XIMPreeditUnKnown;
360 XVaNestedList preedit_attr;
361 Eina_Bool have_preedit_state = EINA_FALSE;
363 imf_context_data = ecore_imf_context_data_get(ctx);
364 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
366 ic = imf_context_data->ic;
370 if (imf_context_data->preedit_length == 0)
373 preedit_attr = XVaCreateNestedList(0,
374 XNPreeditState, &preedit_state,
376 if (!XGetICValues(ic,
377 XNPreeditAttributes, preedit_attr,
379 have_preedit_state = EINA_TRUE;
383 result = XmbResetIC(ic);
385 preedit_attr = XVaCreateNestedList(0,
386 XNPreeditState, preedit_state,
388 if (have_preedit_state)
390 XNPreeditAttributes, preedit_attr,
395 if (imf_context_data->feedbacks)
397 free(imf_context_data->feedbacks);
398 imf_context_data->feedbacks = NULL;
401 if (imf_context_data->preedit_length)
403 imf_context_data->preedit_length = 0;
404 free(imf_context_data->preedit_chars);
405 imf_context_data->preedit_chars = NULL;
407 ecore_imf_context_preedit_changed_event_add(ctx);
408 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
413 char *result_utf8 = strdup(result);
416 ecore_imf_context_commit_event_add(ctx, result_utf8);
417 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, result_utf8);
429 _ecore_imf_context_xim_use_preedit_set(Ecore_IMF_Context *ctx,
430 Eina_Bool use_preedit)
434 Ecore_IMF_Context_Data *imf_context_data;
435 imf_context_data = ecore_imf_context_data_get(ctx);
436 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
438 use_preedit = use_preedit != EINA_FALSE;
440 if (imf_context_data->use_preedit != use_preedit)
442 imf_context_data->use_preedit = use_preedit;
443 reinitialize_ic(ctx);
453 add_feedback_attr(Eina_List **attrs,
455 XIMFeedback feedback,
459 Ecore_IMF_Preedit_Attr *attr = NULL;
461 unsigned int start_index = utf8_offset_to_index(str, start_pos);
462 unsigned int end_index = utf8_offset_to_index(str, end_pos);
464 if (feedback & FEEDBACK_MASK)
466 attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
467 attr->start_index = start_index;
468 attr->end_index = end_index;
469 *attrs = eina_list_append(*attrs, (void *)attr);
472 if (feedback & XIMUnderline)
473 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
475 if (feedback & XIMReverse)
476 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
478 if (feedback & XIMHighlight)
479 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
485 _ecore_imf_context_xim_cursor_location_set(Ecore_IMF_Context *ctx,
486 int x, int y, int w, int h)
488 EINA_LOG_DBG("%s in", __FUNCTION__);
491 Ecore_IMF_Context_Data *imf_context_data;
493 XVaNestedList preedit_attr;
496 imf_context_data = ecore_imf_context_data_get(ctx);
497 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
498 ic = imf_context_data->ic;
505 preedit_attr = XVaCreateNestedList(0,
506 XNSpotLocation, &spot,
509 XNPreeditAttributes, preedit_attr,
519 (void)(w); // yes w is unused, but only a bi-product of the algorithm
523 _ecore_imf_context_xim_input_panel_show(Ecore_IMF_Context *ctx)
525 EINA_LOG_DBG("%s in", __FUNCTION__);
528 Ecore_IMF_Context_Data *imf_context_data;
529 imf_context_data = ecore_imf_context_data_get(ctx);
530 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
532 ecore_x_e_virtual_keyboard_state_set
533 (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
540 _ecore_imf_context_xim_input_panel_hide(Ecore_IMF_Context *ctx)
542 EINA_LOG_DBG("%s in", __FUNCTION__);
545 Ecore_IMF_Context_Data *imf_context_data;
546 imf_context_data = ecore_imf_context_data_get(ctx);
547 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
549 ecore_x_e_virtual_keyboard_state_set
550 (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
558 _ecore_x_event_reverse_modifiers(unsigned int state)
560 unsigned int modifiers = 0;
562 /**< "Control" is pressed */
563 if (state & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
564 modifiers |= ControlMask;
566 /**< "Alt" is pressed */
567 if (state & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
568 modifiers |= Mod1Mask;
570 /**< "Shift" is pressed */
571 if (state & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
572 modifiers |= ShiftMask;
574 /**< "Win" (between "Ctrl" and "A */
575 if (state & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
576 modifiers |= Mod5Mask;
582 _ecore_x_event_reverse_locks(unsigned int state)
584 unsigned int locks = 0;
586 /**< "Num" lock is active */
587 if (state & ECORE_IMF_KEYBOARD_LOCK_NUM)
590 if (state & ECORE_IMF_KEYBOARD_LOCK_CAPS)
593 #if 0 /* FIXME: add mask. */
594 if (state & ECORE_IMF_KEYBOARD_LOCK_SCROLL)
602 _keycode_get(Ecore_X_Display *dsp,
607 // EINA_LOG_DBG("keyname:%s keysym:%lu", keyname, XStringToKeysym(keyname));
608 if (strcmp(keyname, "Keycode-0") == 0)
611 keycode = XKeysymToKeycode(dsp, XStringToKeysym(keyname));
619 _ecore_imf_context_xim_filter_event(Ecore_IMF_Context *ctx,
620 Ecore_IMF_Event_Type type,
621 Ecore_IMF_Event *event)
623 EINA_LOG_DBG("%s in", __FUNCTION__);
625 Ecore_IMF_Context_Data *imf_context_data;
628 Ecore_X_Display *dsp;
632 char compose_buffer[256];
634 char *compose = NULL;
636 Eina_Bool result = EINA_FALSE;
638 imf_context_data = ecore_imf_context_data_get(ctx);
639 if (!imf_context_data) return EINA_FALSE;
640 ic = imf_context_data->ic;
644 if (type == ECORE_IMF_EVENT_KEY_DOWN)
646 XKeyPressedEvent xev;
647 Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
648 EINA_LOG_DBG("ECORE_IMF_EVENT_KEY_DOWN");
650 dsp = ecore_x_display_get();
651 win = imf_context_data->win;
654 xev.serial = 0; /* hope it doesn't matter */
658 xev.root = ecore_x_window_root_get(win);
660 xev.time = ev->timestamp;
661 xev.x = xev.x_root = 0;
662 xev.y = xev.y_root = 0;
664 xev.state |= _ecore_x_event_reverse_modifiers(ev->modifiers);
665 xev.state |= _ecore_x_event_reverse_locks(ev->locks);
666 xev.keycode = _keycode_get(dsp, ev->keyname);
667 xev.same_screen = True;
672 #ifdef X_HAVE_UTF8_STRING
673 val = Xutf8LookupString(ic,
676 sizeof(compose_buffer) - 1,
679 #else /* ifdef X_HAVE_UTF8_STRING */
680 val = XmbLookupString(ic,
683 sizeof(compose_buffer) - 1,
686 #endif /* ifdef X_HAVE_UTF8_STRING */
687 if (mbstatus == XBufferOverflow)
689 tmp = malloc(sizeof (char) * (val + 1));
695 #ifdef X_HAVE_UTF8_STRING
696 val = Xutf8LookupString(ic,
702 #else /* ifdef X_HAVE_UTF8_STRING */
703 val = XmbLookupString(ic,
709 #endif /* ifdef X_HAVE_UTF8_STRING */
713 #ifndef X_HAVE_UTF8_STRING
714 compose = eina_str_convert(nl_langinfo(CODESET),
718 #endif /* ifndef X_HAVE_UTF8_STRING */
725 compose_buffer[val] = '\0';
726 #ifdef X_HAVE_UTF8_STRING
727 compose = strdup(compose_buffer);
728 #else /* ifdef X_HAVE_UTF8_STRING */
729 compose = eina_str_convert(nl_langinfo(CODESET), "UTF-8",
731 #endif /* ifdef X_HAVE_UTF8_STRING */
736 XComposeStatus status;
737 val = XLookupString(&xev,
739 sizeof(compose_buffer),
744 compose_buffer[val] = '\0';
745 compose = eina_str_convert(nl_langinfo(CODESET),
746 "UTF-8", compose_buffer);
752 Eina_Unicode *unicode;
754 unicode = eina_unicode_utf8_to_unicode(compose, &len);
755 if (!unicode) abort();
756 if (unicode[0] >= 0x20 && unicode[0] != 0x7f)
758 ecore_imf_context_commit_event_add(ctx, compose);
759 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, compose);
776 static const Ecore_IMF_Context_Info xim_info = {
778 .description = _("X input method"),
779 .default_locales = "ko:ja:th:zh",
780 .canvas_type = "evas",
781 .canvas_required = 1,
784 static Ecore_IMF_Context_Class xim_class = {
785 .add = _ecore_imf_context_xim_add,
786 .del = _ecore_imf_context_xim_del,
787 .client_window_set = _ecore_imf_context_xim_client_window_set,
788 .client_canvas_set = NULL,
789 .show = _ecore_imf_context_xim_input_panel_show,
790 .hide = _ecore_imf_context_xim_input_panel_hide,
791 .preedit_string_get = _ecore_imf_context_xim_preedit_string_get,
792 .focus_in = _ecore_imf_context_xim_focus_in,
793 .focus_out = _ecore_imf_context_xim_focus_out,
794 .reset = _ecore_imf_context_xim_reset,
795 .cursor_position_set = NULL,
796 .use_preedit_set = _ecore_imf_context_xim_use_preedit_set,
797 .input_mode_set = NULL,
798 .filter_event = _ecore_imf_context_xim_filter_event,
799 .preedit_string_with_attributes_get = _ecore_imf_context_xim_preedit_string_with_attributes_get,
800 .prediction_allow_set = NULL,
801 .autocapital_type_set = NULL,
802 .control_panel_show = NULL,
803 .control_panel_hide = NULL,
804 .input_panel_layout_set = NULL,
805 .input_panel_layout_get = NULL,
806 .input_panel_language_set = NULL,
807 .input_panel_language_get = NULL,
808 .cursor_location_set = _ecore_imf_context_xim_cursor_location_set,
809 .input_panel_imdata_set = NULL,
810 .input_panel_imdata_get = NULL,
811 .input_panel_return_key_type_set = NULL,
812 .input_panel_return_key_disabled_set = NULL,
813 .input_panel_caps_lock_mode_set = NULL
816 static Ecore_IMF_Context *
817 xim_imf_module_create(void)
819 EINA_LOG_DBG("%s in", __FUNCTION__);
820 Ecore_IMF_Context *ctx = NULL;
822 ctx = ecore_imf_context_new(&xim_class);
833 static Ecore_IMF_Context *
834 xim_imf_module_exit(void)
840 ecore_imf_xim_init(void)
842 EINA_LOG_DBG("%s in", __FUNCTION__);
845 ecore_imf_module_register(&xim_info,
846 xim_imf_module_create,
847 xim_imf_module_exit);
853 ecore_imf_xim_shutdown(void)
858 XIM_Im_Info *info = open_ims->data;
859 Ecore_X_Display *display = ecore_x_display_get();
861 xim_info_display_closed(display, EINA_FALSE, info);
869 EINA_MODULE_INIT(ecore_imf_xim_init);
870 EINA_MODULE_SHUTDOWN(ecore_imf_xim_shutdown);
876 Ecore_IMF_Context_Data *
877 imf_context_data_new()
879 Ecore_IMF_Context_Data *imf_context_data = NULL;
882 locale = setlocale(LC_CTYPE, "");
883 if (!locale) return NULL;
885 if (!XSupportsLocale()) return NULL;
887 imf_context_data = calloc(1, sizeof(Ecore_IMF_Context_Data));
888 EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
890 imf_context_data->locale = strdup(locale);
891 if (!imf_context_data->locale) goto error;
893 return imf_context_data;
895 imf_context_data_destroy(imf_context_data);
900 imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data)
902 if (!imf_context_data)
905 if (imf_context_data->ic)
906 XDestroyIC(imf_context_data->ic);
908 free(imf_context_data->preedit_chars);
910 if (imf_context_data->feedbacks)
912 free(imf_context_data->feedbacks);
913 imf_context_data->feedbacks = NULL;
916 free(imf_context_data->locale);
917 free(imf_context_data);
921 preedit_start_callback(XIC xic __UNUSED__,
922 XPointer client_data,
923 XPointer call_data __UNUSED__)
926 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
927 Ecore_IMF_Context_Data *imf_context_data;
928 imf_context_data = ecore_imf_context_data_get(ctx);
929 if (!imf_context_data) return -1;
931 if (imf_context_data->finalizing == EINA_FALSE)
933 ecore_imf_context_preedit_start_event_add(ctx);
934 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
940 preedit_done_callback(XIC xic __UNUSED__,
941 XPointer client_data,
942 XPointer call_data __UNUSED__)
945 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
946 Ecore_IMF_Context_Data *imf_context_data;
947 imf_context_data = ecore_imf_context_data_get(ctx);
948 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
950 if (imf_context_data->preedit_length)
952 imf_context_data->preedit_length = 0;
953 free(imf_context_data->preedit_chars);
954 imf_context_data->preedit_chars = NULL;
955 ecore_imf_context_preedit_changed_event_add(ctx);
956 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
959 if (imf_context_data->finalizing == EINA_FALSE)
961 ecore_imf_context_preedit_end_event_add(ctx);
962 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
968 xim_text_to_utf8(Ecore_IMF_Context *ctx __UNUSED__,
975 if (xim_text && xim_text->string.multi_byte)
977 if (xim_text->encoding_is_wchar)
979 EINA_LOG_WARN("Wide character return from Xlib not currently supported");
984 /* XXX Convert to UTF-8 */
985 result = strdup(xim_text->string.multi_byte);
988 text_length = eina_unicode_utf8_get_len(result);
989 if (text_length != xim_text->length)
991 EINA_LOG_WARN("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length);
996 EINA_LOG_WARN("Error converting text from IM to UCS-4");
1012 preedit_draw_callback(XIC xic __UNUSED__,
1013 XPointer client_data,
1014 XIMPreeditDrawCallbackStruct *call_data)
1017 Eina_Bool ret = EINA_FALSE;
1018 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
1019 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1020 XIMText *t = call_data->text;
1022 Eina_Unicode *new_text = NULL;
1023 Eina_UStrbuf *preedit_bufs = NULL;
1024 int new_text_length;
1027 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1029 preedit_bufs = eina_ustrbuf_new();
1030 if (imf_context_data->preedit_chars)
1032 ret = eina_ustrbuf_append(preedit_bufs, imf_context_data->preedit_chars);
1033 if (ret == EINA_FALSE) goto done;
1036 new_text_length = xim_text_to_utf8(ctx, t, &tmp);
1040 new_text = eina_unicode_utf8_to_unicode((const char *)tmp, &tmp_len);
1047 ret = eina_ustrbuf_remove(preedit_bufs,
1048 call_data->chg_first, call_data->chg_length);
1050 else if (call_data->chg_length == 0)
1053 ret = eina_ustrbuf_insert(preedit_bufs, new_text, call_data->chg_first);
1055 else if (call_data->chg_length > 0)
1057 /* replace string */
1058 ret = eina_ustrbuf_remove(preedit_bufs,
1059 call_data->chg_first, call_data->chg_length);
1060 if (ret == EINA_FALSE) goto done;
1062 ret = eina_ustrbuf_insert_n(preedit_bufs, new_text,
1063 new_text_length, call_data->chg_first);
1064 if (ret == EINA_FALSE) goto done;
1072 if (ret == EINA_TRUE)
1074 free(imf_context_data->preedit_chars);
1075 imf_context_data->preedit_chars =
1076 eina_ustrbuf_string_steal(preedit_bufs);
1077 imf_context_data->preedit_length =
1078 eina_unicode_strlen(imf_context_data->preedit_chars);
1080 if (imf_context_data->feedbacks)
1082 free(imf_context_data->feedbacks);
1083 imf_context_data->feedbacks = NULL;
1086 if (imf_context_data->preedit_length > 0)
1088 imf_context_data->feedbacks = calloc(imf_context_data->preedit_length, sizeof(XIMFeedback));
1090 for (i = 0; i < imf_context_data->preedit_length; i++)
1091 imf_context_data->feedbacks[i] = t->feedback[i];
1094 ecore_imf_context_preedit_changed_event_add(ctx);
1095 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1099 eina_ustrbuf_free(preedit_bufs);
1103 preedit_caret_callback(XIC xic __UNUSED__,
1104 XPointer client_data,
1105 XIMPreeditCaretCallbackStruct *call_data)
1108 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
1109 Ecore_IMF_Context_Data *imf_context_data;
1110 imf_context_data = ecore_imf_context_data_get(ctx);
1111 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1113 if (call_data->direction == XIMAbsolutePosition)
1115 // printf("call_data->position:%d\n", call_data->position);
1116 imf_context_data->preedit_cursor = call_data->position;
1117 if (imf_context_data->finalizing == EINA_FALSE)
1119 ecore_imf_context_preedit_changed_event_add(ctx);
1120 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1125 static XVaNestedList
1126 preedit_callback_set(Ecore_IMF_Context *ctx)
1128 Ecore_IMF_Context_Data *imf_context_data;
1129 imf_context_data = ecore_imf_context_data_get(ctx);
1131 imf_context_data->preedit_start_cb.client_data = (XPointer)ctx;
1132 imf_context_data->preedit_start_cb.callback = (XIMProc)preedit_start_callback;
1134 imf_context_data->preedit_done_cb.client_data = (XPointer)ctx;
1135 imf_context_data->preedit_done_cb.callback = (XIMProc)preedit_done_callback;
1137 imf_context_data->preedit_draw_cb.client_data = (XPointer)ctx;
1138 imf_context_data->preedit_draw_cb.callback = (XIMProc)preedit_draw_callback;
1140 imf_context_data->preedit_caret_cb.client_data = (XPointer)ctx;
1141 imf_context_data->preedit_caret_cb.callback = (XIMProc)preedit_caret_callback;
1143 return XVaCreateNestedList(0,
1144 XNPreeditStartCallback,
1145 &imf_context_data->preedit_start_cb,
1146 XNPreeditDoneCallback,
1147 &imf_context_data->preedit_done_cb,
1148 XNPreeditDrawCallback,
1149 &imf_context_data->preedit_draw_cb,
1150 XNPreeditCaretCallback,
1151 &imf_context_data->preedit_caret_cb,
1156 get_ic(Ecore_IMF_Context *ctx)
1158 Ecore_IMF_Context_Data *imf_context_data;
1160 imf_context_data = ecore_imf_context_data_get(ctx);
1161 EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
1163 ic = imf_context_data->ic;
1166 XIM_Im_Info *im_info = imf_context_data->im_info;
1167 XVaNestedList preedit_attr = NULL;
1168 XIMStyle im_style = 0;
1169 XPoint spot = { 0, 0 };
1174 EINA_LOG_WARN("Doesn't open XIM.");
1181 if (im_info->xim_styles)
1183 for (i = 0; i < im_info->xim_styles->count_styles; i++)
1186 if (im_info->xim_styles->supported_styles[i] & XIMPreeditCallbacks)
1187 printf("XIMPreeditCallbacks | ");
1188 if (im_info->xim_styles->supported_styles[i] & XIMPreeditPosition)
1189 printf("XIMPreeditPosition | ");
1190 if (im_info->xim_styles->supported_styles[i] & XIMPreeditArea)
1191 printf("XIMPreeditArea | ");
1192 if (im_info->xim_styles->supported_styles[i] & XIMPreeditNothing)
1193 printf("XIMPreeditNothing | ");
1194 if (im_info->xim_styles->supported_styles[i] & XIMPreeditNone)
1195 printf("XIMPreeditNone | ");
1196 if (im_info->xim_styles->supported_styles[i] & XIMStatusArea)
1197 printf("XIMStatusArea | ");
1198 if (im_info->xim_styles->supported_styles[i] & XIMStatusCallbacks)
1199 printf("XIMStatusCallbacks | ");
1200 if (im_info->xim_styles->supported_styles[i] & XIMStatusNothing)
1201 printf("XIMStatusNothing | ");
1202 if (im_info->xim_styles->supported_styles[i] & XIMStatusNone)
1203 printf("XIMStatusNone | ");
1208 // "OverTheSpot" = XIMPreeditPosition | XIMStatusNothing
1209 // "OffTheSpot" = XIMPreeditArea | XIMStatusArea
1210 // "Root" = XIMPreeditNothing | XIMStatusNothing
1212 if (imf_context_data->use_preedit == EINA_TRUE)
1214 if (im_info->supports_cursor)
1216 // kinput2 DOES do this...
1218 char **missing_charset_list;
1219 int missing_charset_count;
1222 im_style |= XIMPreeditPosition;
1223 im_style |= XIMStatusNothing;
1224 fs = XCreateFontSet(ecore_x_display_get(),
1226 &missing_charset_list,
1227 &missing_charset_count,
1229 preedit_attr = XVaCreateNestedList(0,
1230 XNSpotLocation, &spot,
1236 im_style |= XIMPreeditCallbacks;
1237 im_style |= XIMStatusNothing;
1238 preedit_attr = preedit_callback_set(ctx);
1240 name = XNPreeditAttributes;
1244 im_style |= XIMPreeditNothing;
1245 im_style |= XIMStatusNothing;
1248 if (!im_info->xim_styles)
1250 EINA_LOG_WARN("No XIM styles supported! Wanted %#llx",
1251 (unsigned long long)im_style);
1256 XIMStyle fallback = 0;
1259 for (i = 0; i < im_info->xim_styles->count_styles; i++)
1261 XIMStyle cur = im_info->xim_styles->supported_styles[i];
1262 if (cur == im_style)
1264 else if (cur == (XIMPreeditNothing | XIMStatusNothing))
1265 /* TODO: fallback is just that or the anyone? */
1269 if (i == im_info->xim_styles->count_styles)
1273 EINA_LOG_WARN("Wanted XIM style %#llx not found, "
1274 "using fallback %#llx instead.",
1275 (unsigned long long)im_style,
1276 (unsigned long long)fallback);
1277 im_style = fallback;
1281 EINA_LOG_WARN("Wanted XIM style %#llx not found, "
1282 "no fallback supported.",
1283 (unsigned long long)im_style);
1289 if ((im_info->im) && (im_style))
1291 ic = XCreateIC(im_info->im,
1292 XNInputStyle, im_style,
1293 XNClientWindow, imf_context_data->win,
1294 name, preedit_attr, NULL);
1296 XFree(preedit_attr);
1299 unsigned long mask = 0xaaaaaaaa;
1301 XNFilterEvents, &mask,
1303 imf_context_data->mask = mask;
1304 ecore_x_event_mask_set(imf_context_data->win, mask);
1307 imf_context_data->ic = ic;
1308 if (ic && imf_context_data->has_focus == EINA_TRUE)
1316 reinitialize_ic(Ecore_IMF_Context *ctx)
1318 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1319 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1321 XIC ic = imf_context_data->ic;
1325 imf_context_data->ic = NULL;
1326 if (imf_context_data->preedit_length)
1328 imf_context_data->preedit_length = 0;
1329 free(imf_context_data->preedit_chars);
1330 imf_context_data->preedit_chars = NULL;
1331 ecore_imf_context_preedit_changed_event_add(ctx);
1332 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1338 reinitialize_all_ics(XIM_Im_Info *info)
1340 Eina_List *tmp_list;
1341 Ecore_IMF_Context *ctx;
1343 EINA_LIST_FOREACH (info->ics, tmp_list, ctx)
1344 reinitialize_ic(ctx);
1348 set_ic_client_window(Ecore_IMF_Context *ctx,
1349 Ecore_X_Window window)
1352 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1353 Ecore_X_Window old_win;
1355 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1357 /* reinitialize IC */
1358 reinitialize_ic(ctx);
1360 old_win = imf_context_data->win;
1361 EINA_LOG_DBG("old_win:%d window:%d ", old_win, window);
1362 if (old_win != 0 && old_win != window) /* XXX how do check window... */
1365 info = imf_context_data->im_info;
1366 info->ics = eina_list_remove(info->ics, imf_context_data);
1367 imf_context_data->im_info = NULL;
1370 imf_context_data->win = window;
1372 if (window) /* XXX */
1374 XIM_Im_Info *info = NULL;
1375 info = get_im(window, imf_context_data->locale);
1376 imf_context_data->im_info = info;
1377 imf_context_data->im_info->ics =
1378 eina_list_prepend(imf_context_data->im_info->ics,
1383 static XIM_Im_Info *
1384 get_im(Ecore_X_Window window,
1390 XIM_Im_Info *im_info = NULL;
1391 XIM_Im_Info *info = NULL;
1392 EINA_LIST_FOREACH (open_ims, l, im_info)
1394 if (strcmp(im_info->locale, locale) == 0)
1410 info = calloc(1, sizeof(XIM_Im_Info));
1411 if (!info) return NULL;
1412 open_ims = eina_list_prepend(open_ims, info);
1414 info->locale = strdup(locale);
1415 info->reconnecting = EINA_FALSE;
1418 xim_info_try_im(info);
1422 /* initialize info->im */
1424 xim_info_try_im(XIM_Im_Info *info)
1426 Ecore_X_Display *dsp;
1428 assert(info->im == NULL);
1429 if (info->reconnecting == EINA_TRUE)
1432 if (XSupportsLocale())
1434 if (!XSetLocaleModifiers(""))
1435 EINA_LOG_WARN("Unable to set locale modifiers with XSetLocaleModifiers()");
1436 dsp = ecore_x_display_get();
1437 info->im = XOpenIM(dsp, NULL, NULL, NULL);
1440 XRegisterIMInstantiateCallback(dsp,
1442 xim_instantiate_callback,
1444 info->reconnecting = EINA_TRUE;
1452 xim_info_display_closed(Ecore_X_Display *display __UNUSED__,
1453 int is_error __UNUSED__,
1456 Eina_List *ics, *tmp_list;
1457 Ecore_IMF_Context *ctx;
1459 open_ims = eina_list_remove(open_ims, info);
1464 EINA_LIST_FOREACH (ics, tmp_list, ctx)
1465 set_ic_client_window(ctx, 0);
1467 EINA_LIST_FREE (ics, ctx)
1469 Ecore_IMF_Context_Data *imf_context_data;
1470 imf_context_data = ecore_imf_context_data_get(ctx);
1471 imf_context_data_destroy(imf_context_data);
1483 xim_instantiate_callback(Display *display,
1484 XPointer client_data,
1485 XPointer call_data __UNUSED__)
1487 XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1490 im = XOpenIM(display, NULL, NULL, NULL);
1494 fprintf(stderr, "Failed to connect to IM\n");
1501 XUnregisterIMInstantiateCallback(display, NULL, NULL, NULL,
1502 xim_instantiate_callback,
1504 info->reconnecting = EINA_FALSE;
1508 setup_im(XIM_Im_Info *info)
1510 XIMValuesList *ic_values = NULL;
1511 XIMCallback im_destroy_callback;
1516 im_destroy_callback.client_data = (XPointer)info;
1517 im_destroy_callback.callback = (XIMProc)xim_destroy_callback;
1518 XSetIMValues(info->im,
1519 XNDestroyCallback, &im_destroy_callback,
1522 XGetIMValues(info->im,
1523 XNQueryInputStyle, &info->xim_styles,
1524 XNQueryICValuesList, &ic_values,
1531 for (i = 0; i < ic_values->count_values; i++)
1533 if (!strcmp(ic_values->supported_values[i],
1534 XNStringConversionCallback))
1535 info->supports_string_conversion = EINA_TRUE;
1536 if (!strcmp(ic_values->supported_values[i],
1538 info->supports_cursor = EINA_TRUE;
1541 printf("values........\n");
1542 for (i = 0; i < ic_values->count_values; i++)
1543 printf("%s\n", ic_values->supported_values[i]);
1544 printf("styles........\n");
1545 for (i = 0; i < info->xim_styles->count_styles; i++)
1546 printf("%lx\n", info->xim_styles->supported_styles[i]);
1553 xim_destroy_callback(XIM xim __UNUSED__,
1554 XPointer client_data,
1555 XPointer call_data __UNUSED__)
1557 XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1560 reinitialize_all_ics(info);
1561 xim_info_try_im(info);
1566 #endif /* ENABLE_XIM */