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 XComposeStatus status;
742 val = XLookupString(&xev,
744 sizeof(compose_buffer),
749 compose_buffer[val] = '\0';
750 compose = eina_str_convert(nl_langinfo(CODESET),
751 "UTF-8", compose_buffer);
757 Eina_Unicode *unicode;
759 unicode = eina_unicode_utf8_to_unicode(compose, &len);
760 if (!unicode) abort();
761 if (unicode[0] >= 0x20 && unicode[0] != 0x7f)
763 ecore_imf_context_commit_event_add(ctx, compose);
764 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, compose);
781 static const Ecore_IMF_Context_Info xim_info = {
783 .description = _("X input method"),
784 .default_locales = "ko:ja:th:zh",
785 .canvas_type = "evas",
786 .canvas_required = 1,
789 static Ecore_IMF_Context_Class xim_class = {
790 .add = _ecore_imf_context_xim_add,
791 .del = _ecore_imf_context_xim_del,
792 .client_window_set = _ecore_imf_context_xim_client_window_set,
793 .client_canvas_set = NULL,
794 .show = _ecore_imf_context_xim_input_panel_show,
795 .hide = _ecore_imf_context_xim_input_panel_hide,
796 .preedit_string_get = _ecore_imf_context_xim_preedit_string_get,
797 .focus_in = _ecore_imf_context_xim_focus_in,
798 .focus_out = _ecore_imf_context_xim_focus_out,
799 .reset = _ecore_imf_context_xim_reset,
800 .cursor_position_set = NULL,
801 .use_preedit_set = _ecore_imf_context_xim_use_preedit_set,
802 .input_mode_set = NULL,
803 .filter_event = _ecore_imf_context_xim_filter_event,
804 .preedit_string_with_attributes_get = _ecore_imf_context_xim_preedit_string_with_attributes_get,
805 .prediction_allow_set = NULL,
806 .autocapital_type_set = NULL,
807 .control_panel_show = NULL,
808 .control_panel_hide = NULL,
809 .input_panel_layout_set = NULL,
810 .input_panel_layout_get = NULL,
811 .input_panel_language_set = NULL,
812 .input_panel_language_get = NULL,
813 .cursor_location_set = _ecore_imf_context_xim_cursor_location_set,
814 .input_panel_imdata_set = NULL,
815 .input_panel_imdata_get = NULL,
816 .input_panel_return_key_type_set = NULL,
817 .input_panel_return_key_disabled_set = NULL,
818 .input_panel_caps_lock_mode_set = NULL
821 static Ecore_IMF_Context *
822 xim_imf_module_create(void)
824 EINA_LOG_DBG("%s in", __FUNCTION__);
825 Ecore_IMF_Context *ctx = NULL;
827 ctx = ecore_imf_context_new(&xim_class);
838 static Ecore_IMF_Context *
839 xim_imf_module_exit(void)
845 ecore_imf_xim_init(void)
847 EINA_LOG_DBG("%s in", __FUNCTION__);
850 ecore_imf_module_register(&xim_info,
851 xim_imf_module_create,
852 xim_imf_module_exit);
858 ecore_imf_xim_shutdown(void)
863 XIM_Im_Info *info = open_ims->data;
864 Ecore_X_Display *display = ecore_x_display_get();
866 xim_info_display_closed(display, EINA_FALSE, info);
874 EINA_MODULE_INIT(ecore_imf_xim_init);
875 EINA_MODULE_SHUTDOWN(ecore_imf_xim_shutdown);
881 Ecore_IMF_Context_Data *
882 imf_context_data_new()
884 Ecore_IMF_Context_Data *imf_context_data = NULL;
887 locale = setlocale(LC_CTYPE, "");
888 if (!locale) return NULL;
890 if (!XSupportsLocale()) return NULL;
892 imf_context_data = calloc(1, sizeof(Ecore_IMF_Context_Data));
893 EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
895 imf_context_data->locale = strdup(locale);
896 if (!imf_context_data->locale) goto error;
898 return imf_context_data;
900 imf_context_data_destroy(imf_context_data);
905 imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data)
907 if (!imf_context_data)
910 if (imf_context_data->ic)
911 XDestroyIC(imf_context_data->ic);
913 free(imf_context_data->preedit_chars);
915 if (imf_context_data->feedbacks)
917 free(imf_context_data->feedbacks);
918 imf_context_data->feedbacks = NULL;
921 free(imf_context_data->locale);
922 free(imf_context_data);
926 preedit_start_callback(XIC xic __UNUSED__,
927 XPointer client_data,
928 XPointer call_data __UNUSED__)
931 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
932 Ecore_IMF_Context_Data *imf_context_data;
933 imf_context_data = ecore_imf_context_data_get(ctx);
934 if (!imf_context_data) return -1;
936 if (imf_context_data->finalizing == EINA_FALSE)
938 ecore_imf_context_preedit_start_event_add(ctx);
939 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
945 preedit_done_callback(XIC xic __UNUSED__,
946 XPointer client_data,
947 XPointer call_data __UNUSED__)
950 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
951 Ecore_IMF_Context_Data *imf_context_data;
952 imf_context_data = ecore_imf_context_data_get(ctx);
953 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
955 if (imf_context_data->preedit_length)
957 imf_context_data->preedit_length = 0;
958 free(imf_context_data->preedit_chars);
959 imf_context_data->preedit_chars = NULL;
960 ecore_imf_context_preedit_changed_event_add(ctx);
961 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
964 if (imf_context_data->finalizing == EINA_FALSE)
966 ecore_imf_context_preedit_end_event_add(ctx);
967 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
973 xim_text_to_utf8(Ecore_IMF_Context *ctx __UNUSED__,
980 if (xim_text && xim_text->string.multi_byte)
982 if (xim_text->encoding_is_wchar)
984 EINA_LOG_WARN("Wide character return from Xlib not currently supported");
989 /* XXX Convert to UTF-8 */
990 result = strdup(xim_text->string.multi_byte);
993 text_length = eina_unicode_utf8_get_len(result);
994 if (text_length != xim_text->length)
996 EINA_LOG_WARN("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length);
1001 EINA_LOG_WARN("Error converting text from IM to UCS-4");
1017 preedit_draw_callback(XIC xic __UNUSED__,
1018 XPointer client_data,
1019 XIMPreeditDrawCallbackStruct *call_data)
1022 Eina_Bool ret = EINA_FALSE;
1023 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
1024 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1025 XIMText *t = call_data->text;
1027 Eina_Unicode *new_text = NULL;
1028 Eina_UStrbuf *preedit_bufs = NULL;
1029 int new_text_length;
1032 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1034 preedit_bufs = eina_ustrbuf_new();
1035 if (imf_context_data->preedit_chars)
1037 ret = eina_ustrbuf_append(preedit_bufs, imf_context_data->preedit_chars);
1038 if (ret == EINA_FALSE) goto done;
1041 new_text_length = xim_text_to_utf8(ctx, t, &tmp);
1045 new_text = eina_unicode_utf8_to_unicode((const char *)tmp, &tmp_len);
1052 ret = eina_ustrbuf_remove(preedit_bufs,
1053 call_data->chg_first, call_data->chg_length);
1055 else if (call_data->chg_length == 0)
1058 ret = eina_ustrbuf_insert(preedit_bufs, new_text, call_data->chg_first);
1060 else if (call_data->chg_length > 0)
1062 /* replace string */
1063 ret = eina_ustrbuf_remove(preedit_bufs,
1064 call_data->chg_first, call_data->chg_length);
1065 if (ret == EINA_FALSE) goto done;
1067 ret = eina_ustrbuf_insert_n(preedit_bufs, new_text,
1068 new_text_length, call_data->chg_first);
1069 if (ret == EINA_FALSE) goto done;
1077 if (ret == EINA_TRUE)
1079 free(imf_context_data->preedit_chars);
1080 imf_context_data->preedit_chars =
1081 eina_ustrbuf_string_steal(preedit_bufs);
1082 imf_context_data->preedit_length =
1083 eina_unicode_strlen(imf_context_data->preedit_chars);
1085 if (imf_context_data->feedbacks)
1087 free(imf_context_data->feedbacks);
1088 imf_context_data->feedbacks = NULL;
1091 if (imf_context_data->preedit_length > 0)
1093 imf_context_data->feedbacks = calloc(imf_context_data->preedit_length, sizeof(XIMFeedback));
1095 for (i = 0; i < imf_context_data->preedit_length; i++)
1096 imf_context_data->feedbacks[i] = t->feedback[i];
1099 ecore_imf_context_preedit_changed_event_add(ctx);
1100 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1104 eina_ustrbuf_free(preedit_bufs);
1108 preedit_caret_callback(XIC xic __UNUSED__,
1109 XPointer client_data,
1110 XIMPreeditCaretCallbackStruct *call_data)
1113 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
1114 Ecore_IMF_Context_Data *imf_context_data;
1115 imf_context_data = ecore_imf_context_data_get(ctx);
1116 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1118 if (call_data->direction == XIMAbsolutePosition)
1120 // printf("call_data->position:%d\n", call_data->position);
1121 imf_context_data->preedit_cursor = call_data->position;
1122 if (imf_context_data->finalizing == EINA_FALSE)
1124 ecore_imf_context_preedit_changed_event_add(ctx);
1125 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1130 static XVaNestedList
1131 preedit_callback_set(Ecore_IMF_Context *ctx)
1133 Ecore_IMF_Context_Data *imf_context_data;
1134 imf_context_data = ecore_imf_context_data_get(ctx);
1136 imf_context_data->preedit_start_cb.client_data = (XPointer)ctx;
1137 imf_context_data->preedit_start_cb.callback = (XIMProc)preedit_start_callback;
1139 imf_context_data->preedit_done_cb.client_data = (XPointer)ctx;
1140 imf_context_data->preedit_done_cb.callback = (XIMProc)preedit_done_callback;
1142 imf_context_data->preedit_draw_cb.client_data = (XPointer)ctx;
1143 imf_context_data->preedit_draw_cb.callback = (XIMProc)preedit_draw_callback;
1145 imf_context_data->preedit_caret_cb.client_data = (XPointer)ctx;
1146 imf_context_data->preedit_caret_cb.callback = (XIMProc)preedit_caret_callback;
1148 return XVaCreateNestedList(0,
1149 XNPreeditStartCallback,
1150 &imf_context_data->preedit_start_cb,
1151 XNPreeditDoneCallback,
1152 &imf_context_data->preedit_done_cb,
1153 XNPreeditDrawCallback,
1154 &imf_context_data->preedit_draw_cb,
1155 XNPreeditCaretCallback,
1156 &imf_context_data->preedit_caret_cb,
1161 get_ic(Ecore_IMF_Context *ctx)
1163 Ecore_IMF_Context_Data *imf_context_data;
1165 imf_context_data = ecore_imf_context_data_get(ctx);
1166 EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
1168 ic = imf_context_data->ic;
1171 XIM_Im_Info *im_info = imf_context_data->im_info;
1172 XVaNestedList preedit_attr = NULL;
1173 XIMStyle im_style = 0;
1174 XPoint spot = { 0, 0 };
1179 EINA_LOG_WARN("Doesn't open XIM.");
1186 if (im_info->xim_styles)
1188 for (i = 0; i < im_info->xim_styles->count_styles; i++)
1191 if (im_info->xim_styles->supported_styles[i] & XIMPreeditCallbacks)
1192 printf("XIMPreeditCallbacks | ");
1193 if (im_info->xim_styles->supported_styles[i] & XIMPreeditPosition)
1194 printf("XIMPreeditPosition | ");
1195 if (im_info->xim_styles->supported_styles[i] & XIMPreeditArea)
1196 printf("XIMPreeditArea | ");
1197 if (im_info->xim_styles->supported_styles[i] & XIMPreeditNothing)
1198 printf("XIMPreeditNothing | ");
1199 if (im_info->xim_styles->supported_styles[i] & XIMPreeditNone)
1200 printf("XIMPreeditNone | ");
1201 if (im_info->xim_styles->supported_styles[i] & XIMStatusArea)
1202 printf("XIMStatusArea | ");
1203 if (im_info->xim_styles->supported_styles[i] & XIMStatusCallbacks)
1204 printf("XIMStatusCallbacks | ");
1205 if (im_info->xim_styles->supported_styles[i] & XIMStatusNothing)
1206 printf("XIMStatusNothing | ");
1207 if (im_info->xim_styles->supported_styles[i] & XIMStatusNone)
1208 printf("XIMStatusNone | ");
1213 // "OverTheSpot" = XIMPreeditPosition | XIMStatusNothing
1214 // "OffTheSpot" = XIMPreeditArea | XIMStatusArea
1215 // "Root" = XIMPreeditNothing | XIMStatusNothing
1217 if (imf_context_data->use_preedit == EINA_TRUE)
1219 if (im_info->supports_cursor)
1221 // kinput2 DOES do this...
1223 char **missing_charset_list;
1224 int missing_charset_count;
1227 im_style |= XIMPreeditPosition;
1228 im_style |= XIMStatusNothing;
1229 fs = XCreateFontSet(ecore_x_display_get(),
1231 &missing_charset_list,
1232 &missing_charset_count,
1234 preedit_attr = XVaCreateNestedList(0,
1235 XNSpotLocation, &spot,
1241 im_style |= XIMPreeditCallbacks;
1242 im_style |= XIMStatusNothing;
1243 preedit_attr = preedit_callback_set(ctx);
1245 name = XNPreeditAttributes;
1249 im_style |= XIMPreeditNothing;
1250 im_style |= XIMStatusNothing;
1253 if (!im_info->xim_styles)
1255 EINA_LOG_WARN("No XIM styles supported! Wanted %#llx",
1256 (unsigned long long)im_style);
1261 XIMStyle fallback = 0;
1264 for (i = 0; i < im_info->xim_styles->count_styles; i++)
1266 XIMStyle cur = im_info->xim_styles->supported_styles[i];
1267 if (cur == im_style)
1269 else if (cur == (XIMPreeditNothing | XIMStatusNothing))
1270 /* TODO: fallback is just that or the anyone? */
1274 if (i == im_info->xim_styles->count_styles)
1278 EINA_LOG_WARN("Wanted XIM style %#llx not found, "
1279 "using fallback %#llx instead.",
1280 (unsigned long long)im_style,
1281 (unsigned long long)fallback);
1282 im_style = fallback;
1286 EINA_LOG_WARN("Wanted XIM style %#llx not found, "
1287 "no fallback supported.",
1288 (unsigned long long)im_style);
1294 if ((im_info->im) && (im_style))
1296 ic = XCreateIC(im_info->im,
1297 XNInputStyle, im_style,
1298 XNClientWindow, imf_context_data->win,
1299 name, preedit_attr, NULL);
1301 XFree(preedit_attr);
1304 unsigned long mask = 0xaaaaaaaa;
1306 XNFilterEvents, &mask,
1308 imf_context_data->mask = mask;
1309 ecore_x_event_mask_set(imf_context_data->win, mask);
1312 imf_context_data->ic = ic;
1313 if (ic && imf_context_data->has_focus == EINA_TRUE)
1321 reinitialize_ic(Ecore_IMF_Context *ctx)
1323 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1324 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1326 XIC ic = imf_context_data->ic;
1330 imf_context_data->ic = NULL;
1331 if (imf_context_data->preedit_length)
1333 imf_context_data->preedit_length = 0;
1334 free(imf_context_data->preedit_chars);
1335 imf_context_data->preedit_chars = NULL;
1336 ecore_imf_context_preedit_changed_event_add(ctx);
1337 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1343 set_ic_client_window(Ecore_IMF_Context *ctx,
1344 Ecore_X_Window window)
1347 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1348 Ecore_X_Window old_win;
1350 EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1352 /* reinitialize IC */
1353 reinitialize_ic(ctx);
1355 old_win = imf_context_data->win;
1356 EINA_LOG_DBG("old_win:%d window:%d ", old_win, window);
1357 if (old_win != 0 && old_win != window) /* XXX how do check window... */
1360 info = imf_context_data->im_info;
1361 info->ics = eina_list_remove(info->ics, imf_context_data);
1362 if (imf_context_data->im_info)
1363 imf_context_data->im_info->user = NULL;
1364 imf_context_data->im_info = NULL;
1367 imf_context_data->win = window;
1369 if (window) /* XXX */
1371 XIM_Im_Info *info = NULL;
1372 info = get_im(window, imf_context_data->locale);
1373 imf_context_data->im_info = info;
1374 imf_context_data->im_info->ics =
1375 eina_list_prepend(imf_context_data->im_info->ics,
1377 if (imf_context_data->im_info)
1378 imf_context_data->im_info->user = imf_context_data;
1382 static XIM_Im_Info *
1383 get_im(Ecore_X_Window window,
1389 XIM_Im_Info *im_info = NULL;
1390 XIM_Im_Info *info = NULL;
1391 EINA_LIST_FOREACH (open_ims, l, im_info)
1393 if (strcmp(im_info->locale, locale) == 0)
1409 info = calloc(1, sizeof(XIM_Im_Info));
1410 if (!info) return NULL;
1411 open_ims = eina_list_prepend(open_ims, info);
1413 info->locale = strdup(locale);
1414 info->reconnecting = EINA_FALSE;
1417 xim_info_try_im(info);
1421 /* initialize info->im */
1423 xim_info_try_im(XIM_Im_Info *info)
1425 Ecore_X_Display *dsp;
1427 assert(info->im == NULL);
1428 if (info->reconnecting == EINA_TRUE)
1431 if (XSupportsLocale())
1433 if (!XSetLocaleModifiers(""))
1434 EINA_LOG_WARN("Unable to set locale modifiers with XSetLocaleModifiers()");
1435 dsp = ecore_x_display_get();
1436 info->im = XOpenIM(dsp, NULL, NULL, NULL);
1439 XRegisterIMInstantiateCallback(dsp,
1441 xim_instantiate_callback,
1443 info->reconnecting = EINA_TRUE;
1451 xim_info_display_closed(Ecore_X_Display *display __UNUSED__,
1452 int is_error __UNUSED__,
1455 Eina_List *ics, *tmp_list;
1456 Ecore_IMF_Context *ctx;
1458 open_ims = eina_list_remove(open_ims, info);
1463 EINA_LIST_FOREACH (ics, tmp_list, ctx)
1464 set_ic_client_window(ctx, 0);
1466 EINA_LIST_FREE (ics, ctx)
1468 Ecore_IMF_Context_Data *imf_context_data;
1469 imf_context_data = ecore_imf_context_data_get(ctx);
1470 imf_context_data_destroy(imf_context_data);
1482 xim_instantiate_callback(Display *display,
1483 XPointer client_data,
1484 XPointer call_data __UNUSED__)
1486 XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1489 im = XOpenIM(display, NULL, NULL, NULL);
1493 fprintf(stderr, "Failed to connect to IM\n");
1500 XUnregisterIMInstantiateCallback(display, NULL, NULL, NULL,
1501 xim_instantiate_callback,
1503 info->reconnecting = EINA_FALSE;
1507 setup_im(XIM_Im_Info *info)
1509 XIMValuesList *ic_values = NULL;
1510 XIMCallback im_destroy_callback;
1515 im_destroy_callback.client_data = (XPointer)info;
1516 im_destroy_callback.callback = (XIMProc)xim_destroy_callback;
1517 XSetIMValues(info->im,
1518 XNDestroyCallback, &im_destroy_callback,
1521 XGetIMValues(info->im,
1522 XNQueryInputStyle, &info->xim_styles,
1523 XNQueryICValuesList, &ic_values,
1530 for (i = 0; i < ic_values->count_values; i++)
1532 if (!strcmp(ic_values->supported_values[i],
1533 XNStringConversionCallback))
1534 info->supports_string_conversion = EINA_TRUE;
1535 if (!strcmp(ic_values->supported_values[i],
1537 info->supports_cursor = EINA_TRUE;
1540 printf("values........\n");
1541 for (i = 0; i < ic_values->count_values; i++)
1542 printf("%s\n", ic_values->supported_values[i]);
1543 printf("styles........\n");
1544 for (i = 0; i < info->xim_styles->count_styles; i++)
1545 printf("%lx\n", info->xim_styles->supported_styles[i]);
1552 xim_destroy_callback(XIM xim __UNUSED__,
1553 XPointer client_data,
1554 XPointer call_data __UNUSED__)
1556 XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1558 if (info->user) info->user->ic = NULL;
1560 // reinitialize_ic(ctx);
1561 xim_info_try_im(info);
1566 #endif /* ENABLE_XIM */