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, &index);
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 if (!imf_context_data) return;
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);
157 imf_context_data->finalizing = EINA_TRUE;
158 if (imf_context_data->im_info && !imf_context_data->im_info->ics->next)
160 if (imf_context_data->im_info->reconnecting == EINA_TRUE)
162 Ecore_X_Display *dsp;
163 dsp = ecore_x_display_get();
164 XUnregisterIMInstantiateCallback(dsp,
166 xim_instantiate_callback,
167 (XPointer)imf_context_data->im_info);
169 else if (imf_context_data->im_info->im)
171 XIMCallback im_destroy_callback;
172 im_destroy_callback.client_data = NULL;
173 im_destroy_callback.callback = NULL;
174 XSetIMValues(imf_context_data->im_info->im,
175 XNDestroyCallback, &im_destroy_callback,
180 set_ic_client_window(ctx, 0);
182 imf_context_data_destroy(imf_context_data);
189 _ecore_imf_context_xim_client_window_set(Ecore_IMF_Context *ctx,
194 set_ic_client_window(ctx, (Ecore_X_Window)((Ecore_Window)window));
202 _ecore_imf_context_xim_preedit_string_get(Ecore_IMF_Context *ctx,
208 Ecore_IMF_Context_Data *imf_context_data;
211 imf_context_data = ecore_imf_context_data_get(ctx);
212 if (imf_context_data->preedit_chars)
214 utf8 = eina_unicode_unicode_to_utf8(imf_context_data->preedit_chars,
230 *cursor_pos = imf_context_data->preedit_cursor;
241 _ecore_imf_context_xim_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
249 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
251 _ecore_imf_context_xim_preedit_string_get(ctx, str, cursor_pos);
254 if (!imf_context_data || !imf_context_data->feedbacks) return;
257 XIMFeedback last_feedback = 0;
260 for (i = 0; i < imf_context_data->preedit_length; i++)
262 XIMFeedback new_feedback = imf_context_data->feedbacks[i] & FEEDBACK_MASK;
264 if (new_feedback != last_feedback)
267 add_feedback_attr(attrs, *str, last_feedback, start, i);
269 last_feedback = new_feedback;
275 add_feedback_attr(attrs, *str, last_feedback, start, i);
288 _ecore_imf_context_xim_focus_in(Ecore_IMF_Context *ctx)
293 Ecore_IMF_Context_Data *imf_context_data;
294 imf_context_data = ecore_imf_context_data_get(ctx);
295 ic = imf_context_data->ic;
296 imf_context_data->has_focus = EINA_TRUE;
301 #ifdef X_HAVE_UTF8_STRING
302 if ((str = Xutf8ResetIC(ic)))
304 if ((str = XmbResetIC(ic)))
316 _ecore_imf_context_xim_focus_out(Ecore_IMF_Context *ctx)
318 EINA_LOG_DBG("%s in", __FUNCTION__);
321 Ecore_IMF_Context_Data *imf_context_data;
322 imf_context_data = ecore_imf_context_data_get(ctx);
323 if (imf_context_data->has_focus == EINA_TRUE)
325 imf_context_data->has_focus = EINA_FALSE;
326 ic = imf_context_data->ic;
336 _ecore_imf_context_xim_reset(Ecore_IMF_Context *ctx)
338 EINA_LOG_DBG("%s in", __FUNCTION__);
341 Ecore_IMF_Context_Data *imf_context_data;
344 /* restore conversion state after resetting ic later */
345 XIMPreeditState preedit_state = XIMPreeditUnKnown;
346 XVaNestedList preedit_attr;
347 Eina_Bool have_preedit_state = EINA_FALSE;
349 imf_context_data = ecore_imf_context_data_get(ctx);
350 ic = imf_context_data->ic;
354 if (imf_context_data->preedit_length == 0)
357 preedit_attr = XVaCreateNestedList(0,
358 XNPreeditState, &preedit_state,
360 if (!XGetICValues(ic,
361 XNPreeditAttributes, preedit_attr,
363 have_preedit_state = EINA_TRUE;
367 result = XmbResetIC(ic);
369 preedit_attr = XVaCreateNestedList(0,
370 XNPreeditState, preedit_state,
372 if (have_preedit_state)
374 XNPreeditAttributes, preedit_attr,
379 if (imf_context_data->feedbacks)
381 free(imf_context_data->feedbacks);
382 imf_context_data->feedbacks = NULL;
385 if (imf_context_data->preedit_length)
387 imf_context_data->preedit_length = 0;
388 free(imf_context_data->preedit_chars);
389 imf_context_data->preedit_chars = NULL;
391 ecore_imf_context_preedit_changed_event_add(ctx);
392 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
397 char *result_utf8 = strdup(result);
400 ecore_imf_context_commit_event_add(ctx, result_utf8);
401 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, result_utf8);
413 _ecore_imf_context_xim_use_preedit_set(Ecore_IMF_Context *ctx,
414 Eina_Bool use_preedit)
418 Ecore_IMF_Context_Data *imf_context_data;
419 imf_context_data = ecore_imf_context_data_get(ctx);
421 use_preedit = use_preedit != EINA_FALSE;
423 if (imf_context_data->use_preedit != use_preedit)
425 imf_context_data->use_preedit = use_preedit;
426 reinitialize_ic(ctx);
436 add_feedback_attr(Eina_List **attrs,
438 XIMFeedback feedback,
442 Ecore_IMF_Preedit_Attr *attr = NULL;
444 unsigned int start_index = utf8_offset_to_index(str, start_pos);
445 unsigned int end_index = utf8_offset_to_index(str, end_pos);
447 if (feedback & FEEDBACK_MASK)
449 attr = (Ecore_IMF_Preedit_Attr *)calloc(1, sizeof(Ecore_IMF_Preedit_Attr));
450 attr->start_index = start_index;
451 attr->end_index = end_index;
452 *attrs = eina_list_append(*attrs, (void *)attr);
455 if (feedback & XIMUnderline)
456 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
458 if (feedback & XIMReverse)
459 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
461 if (feedback & XIMHighlight)
462 attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
468 _ecore_imf_context_xim_cursor_location_set(Ecore_IMF_Context *ctx,
469 int x, int y, int w, int h)
471 EINA_LOG_DBG("%s in", __FUNCTION__);
474 Ecore_IMF_Context_Data *imf_context_data;
476 XVaNestedList preedit_attr;
479 imf_context_data = ecore_imf_context_data_get(ctx);
480 ic = imf_context_data->ic;
487 preedit_attr = XVaCreateNestedList(0,
488 XNSpotLocation, &spot,
491 XNPreeditAttributes, preedit_attr,
501 (void)(w); // yes w is unused, but only a bi-product of the algorithm
506 _ecore_x_event_reverse_modifiers(unsigned int state)
508 unsigned int modifiers = 0;
510 /**< "Control" is pressed */
511 if (state & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
512 modifiers |= ControlMask;
514 /**< "Alt" is pressed */
515 if (state & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
516 modifiers |= Mod1Mask;
518 /**< "Shift" is pressed */
519 if (state & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
520 modifiers |= ShiftMask;
522 /**< "Win" (between "Ctrl" and "A */
523 if (state & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
524 modifiers |= Mod5Mask;
530 _ecore_x_event_reverse_locks(unsigned int state)
532 unsigned int locks = 0;
534 /**< "Num" lock is active */
535 if (state & ECORE_IMF_KEYBOARD_LOCK_NUM)
538 if (state & ECORE_IMF_KEYBOARD_LOCK_CAPS)
541 #if 0 /* FIXME: add mask. */
542 if (state & ECORE_IMF_KEYBOARD_LOCK_SCROLL)
550 _keycode_get(Ecore_X_Display *dsp,
555 // EINA_LOG_DBG("keyname:%s keysym:%lu", keyname, XStringToKeysym(keyname));
556 if (strcmp(keyname, "Keycode-0") == 0)
561 keycode = XKeysymToKeycode(dsp, XStringToKeysym(keyname));
570 _ecore_imf_context_xim_filter_event(Ecore_IMF_Context *ctx,
571 Ecore_IMF_Event_Type type,
572 Ecore_IMF_Event *event)
574 EINA_LOG_DBG("%s in", __FUNCTION__);
576 Ecore_IMF_Context_Data *imf_context_data;
579 Ecore_X_Display *dsp;
583 char compose_buffer[256];
585 char *compose = NULL;
587 Eina_Bool result = EINA_FALSE;
589 imf_context_data = ecore_imf_context_data_get(ctx);
590 ic = imf_context_data->ic;
596 if (type == ECORE_IMF_EVENT_KEY_DOWN)
598 XKeyPressedEvent xev;
599 Ecore_IMF_Event_Key_Down *ev = (Ecore_IMF_Event_Key_Down *)event;
600 EINA_LOG_DBG("ECORE_IMF_EVENT_KEY_DOWN");
602 dsp = ecore_x_display_get();
603 win = imf_context_data->win;
606 xev.serial = 0; /* hope it doesn't matter */
610 xev.root = ecore_x_window_root_get(win);
612 xev.time = ev->timestamp;
613 xev.x = xev.x_root = 0;
614 xev.y = xev.y_root = 0;
616 xev.state |= _ecore_x_event_reverse_modifiers(ev->modifiers);
617 xev.state |= _ecore_x_event_reverse_locks(ev->locks);
618 xev.keycode = _keycode_get(dsp, ev->keyname);
619 xev.same_screen = True;
624 #ifdef X_HAVE_UTF8_STRING
625 val = Xutf8LookupString(ic,
628 sizeof(compose_buffer) - 1,
631 #else /* ifdef X_HAVE_UTF8_STRING */
632 val = XmbLookupString(ic,
635 sizeof(compose_buffer) - 1,
638 #endif /* ifdef X_HAVE_UTF8_STRING */
639 if (mbstatus == XBufferOverflow)
641 tmp = malloc(sizeof (char) * (val + 1));
649 #ifdef X_HAVE_UTF8_STRING
650 val = Xutf8LookupString(ic,
656 #else /* ifdef X_HAVE_UTF8_STRING */
657 val = XmbLookupString(ic,
663 #endif /* ifdef X_HAVE_UTF8_STRING */
667 #ifndef X_HAVE_UTF8_STRING
668 compose = eina_str_convert(nl_langinfo(CODESET),
672 #endif /* ifndef X_HAVE_UTF8_STRING */
679 compose_buffer[val] = '\0';
680 #ifdef X_HAVE_UTF8_STRING
681 compose = strdup(compose_buffer);
682 #else /* ifdef X_HAVE_UTF8_STRING */
683 compose = eina_str_convert(nl_langinfo(CODESET), "UTF-8",
685 #endif /* ifdef X_HAVE_UTF8_STRING */
689 XComposeStatus status;
690 val = XLookupString(&xev,
692 sizeof(compose_buffer),
697 compose_buffer[val] = '\0';
698 compose = eina_str_convert(nl_langinfo(CODESET),
699 "UTF-8", compose_buffer);
705 Eina_Unicode *unicode;
707 unicode = eina_unicode_utf8_to_unicode(compose, &len);
708 if (!unicode) abort();
709 if (unicode[0] >= 0x20 && unicode[0] != 0x7f)
711 ecore_imf_context_commit_event_add(ctx, compose);
712 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, compose);
729 static const Ecore_IMF_Context_Info xim_info = {
731 .description = _("X input method"),
732 .default_locales = "ko:ja:th:zh",
733 .canvas_type = "evas",
734 .canvas_required = 1,
737 static Ecore_IMF_Context_Class xim_class = {
738 .add = _ecore_imf_context_xim_add,
739 .del = _ecore_imf_context_xim_del,
740 .client_window_set = _ecore_imf_context_xim_client_window_set,
741 .client_canvas_set = NULL,
744 .preedit_string_get = _ecore_imf_context_xim_preedit_string_get,
745 .focus_in = _ecore_imf_context_xim_focus_in,
746 .focus_out = _ecore_imf_context_xim_focus_out,
747 .reset = _ecore_imf_context_xim_reset,
748 .cursor_position_set = NULL,
749 .use_preedit_set = _ecore_imf_context_xim_use_preedit_set,
750 .input_mode_set = NULL,
751 .filter_event = _ecore_imf_context_xim_filter_event,
752 .preedit_string_with_attributes_get = _ecore_imf_context_xim_preedit_string_with_attributes_get,
753 .prediction_allow_set = NULL,
754 .autocapital_type_set = NULL,
755 .control_panel_show = NULL,
756 .control_panel_hide = NULL,
757 .input_panel_layout_set = NULL,
758 .input_panel_layout_get = NULL,
759 .input_panel_language_set = NULL,
760 .input_panel_language_get = NULL,
761 .cursor_location_set = _ecore_imf_context_xim_cursor_location_set,
762 .input_panel_imdata_set = NULL,
763 .input_panel_imdata_get = NULL,
766 static Ecore_IMF_Context *
767 xim_imf_module_create(void)
769 EINA_LOG_DBG("%s in", __FUNCTION__);
770 Ecore_IMF_Context *ctx = NULL;
772 ctx = ecore_imf_context_new(&xim_class);
783 static Ecore_IMF_Context *
784 xim_imf_module_exit(void)
790 ecore_imf_xim_init(void)
792 EINA_LOG_DBG("%s in", __FUNCTION__);
795 ecore_imf_module_register(&xim_info,
796 xim_imf_module_create,
797 xim_imf_module_exit);
803 ecore_imf_xim_shutdown(void)
807 XIM_Im_Info *info = open_ims->data;
808 Ecore_X_Display *display = ecore_x_display_get();
810 xim_info_display_closed(display, EINA_FALSE, info);
818 EINA_MODULE_INIT(ecore_imf_xim_init);
819 EINA_MODULE_SHUTDOWN(ecore_imf_xim_shutdown);
825 Ecore_IMF_Context_Data *
826 imf_context_data_new()
828 Ecore_IMF_Context_Data *imf_context_data = NULL;
831 locale = setlocale(LC_CTYPE, "");
832 if (!locale) return NULL;
834 if (!XSupportsLocale()) return NULL;
836 imf_context_data = calloc(1, sizeof(Ecore_IMF_Context_Data));
837 if (!imf_context_data) return NULL;
839 imf_context_data->locale = strdup(locale);
840 if (!imf_context_data->locale) goto error;
842 return imf_context_data;
844 imf_context_data_destroy(imf_context_data);
849 imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data)
851 if (!imf_context_data)
854 if (imf_context_data->ic)
855 XDestroyIC(imf_context_data->ic);
857 free(imf_context_data->preedit_chars);
859 if (imf_context_data->feedbacks)
861 free(imf_context_data->feedbacks);
862 imf_context_data->feedbacks = NULL;
865 free(imf_context_data->locale);
866 free(imf_context_data);
870 preedit_start_callback(XIC xic __UNUSED__,
871 XPointer client_data,
872 XPointer call_data __UNUSED__)
875 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
876 Ecore_IMF_Context_Data *imf_context_data;
877 imf_context_data = ecore_imf_context_data_get(ctx);
879 if (imf_context_data->finalizing == EINA_FALSE)
881 ecore_imf_context_preedit_start_event_add(ctx);
882 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
888 preedit_done_callback(XIC xic __UNUSED__,
889 XPointer client_data,
890 XPointer call_data __UNUSED__)
893 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
894 Ecore_IMF_Context_Data *imf_context_data;
895 imf_context_data = ecore_imf_context_data_get(ctx);
897 if (imf_context_data->preedit_length)
899 imf_context_data->preedit_length = 0;
900 free(imf_context_data->preedit_chars);
901 imf_context_data->preedit_chars = NULL;
902 ecore_imf_context_preedit_changed_event_add(ctx);
903 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
906 if (imf_context_data->finalizing == EINA_FALSE)
908 ecore_imf_context_preedit_end_event_add(ctx);
909 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
915 xim_text_to_utf8(Ecore_IMF_Context *ctx __UNUSED__,
922 if (xim_text && xim_text->string.multi_byte)
924 if (xim_text->encoding_is_wchar)
926 EINA_LOG_WARN("Wide character return from Xlib not currently supported");
931 /* XXX Convert to UTF-8 */
932 result = strdup(xim_text->string.multi_byte);
935 text_length = eina_unicode_utf8_get_len(result);
936 if (text_length != xim_text->length)
938 EINA_LOG_WARN("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length);
942 EINA_LOG_WARN("Error converting text from IM to UCS-4");
957 preedit_draw_callback(XIC xic __UNUSED__,
958 XPointer client_data,
959 XIMPreeditDrawCallbackStruct *call_data)
962 Eina_Bool ret = EINA_FALSE;
963 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
964 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
965 XIMText *t = call_data->text;
967 Eina_Unicode *new_text = NULL;
968 Eina_UStrbuf *preedit_bufs = NULL;
972 preedit_bufs = eina_ustrbuf_new();
973 if (imf_context_data->preedit_chars)
975 ret = eina_ustrbuf_append(preedit_bufs, imf_context_data->preedit_chars);
976 if (ret == EINA_FALSE) goto done;
979 new_text_length = xim_text_to_utf8(ctx, t, &tmp);
983 new_text = eina_unicode_utf8_to_unicode((const char *)tmp, &tmp_len);
990 ret = eina_ustrbuf_remove(preedit_bufs,
991 call_data->chg_first, call_data->chg_length);
993 else if (call_data->chg_length == 0)
996 ret = eina_ustrbuf_insert(preedit_bufs, new_text, call_data->chg_first);
998 else if (call_data->chg_length > 0)
1000 /* replace string */
1001 ret = eina_ustrbuf_remove(preedit_bufs,
1002 call_data->chg_first, call_data->chg_length);
1003 if (ret == EINA_FALSE) goto done;
1005 ret = eina_ustrbuf_insert_n(preedit_bufs, new_text,
1006 new_text_length, call_data->chg_first);
1007 if (ret == EINA_FALSE) goto done;
1014 if (ret == EINA_TRUE)
1016 free(imf_context_data->preedit_chars);
1017 imf_context_data->preedit_chars =
1018 eina_ustrbuf_string_steal(preedit_bufs);
1019 imf_context_data->preedit_length =
1020 eina_unicode_strlen(imf_context_data->preedit_chars);
1022 if (imf_context_data->feedbacks)
1024 free(imf_context_data->feedbacks);
1025 imf_context_data->feedbacks = NULL;
1028 if (imf_context_data->preedit_length > 0)
1030 imf_context_data->feedbacks = calloc(imf_context_data->preedit_length, sizeof(XIMFeedback));
1032 for (i = 0; i < imf_context_data->preedit_length; i++)
1033 imf_context_data->feedbacks[i] = t->feedback[i];
1036 ecore_imf_context_preedit_changed_event_add(ctx);
1037 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1041 eina_ustrbuf_free(preedit_bufs);
1045 preedit_caret_callback(XIC xic __UNUSED__,
1046 XPointer client_data,
1047 XIMPreeditCaretCallbackStruct *call_data)
1050 Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)client_data;
1051 Ecore_IMF_Context_Data *imf_context_data;
1052 imf_context_data = ecore_imf_context_data_get(ctx);
1054 if (call_data->direction == XIMAbsolutePosition)
1056 // printf("call_data->position:%d\n", call_data->position);
1057 imf_context_data->preedit_cursor = call_data->position;
1058 if (imf_context_data->finalizing == EINA_FALSE)
1060 ecore_imf_context_preedit_changed_event_add(ctx);
1061 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1066 static XVaNestedList
1067 preedit_callback_set(Ecore_IMF_Context *ctx)
1069 Ecore_IMF_Context_Data *imf_context_data;
1070 imf_context_data = ecore_imf_context_data_get(ctx);
1072 imf_context_data->preedit_start_cb.client_data = (XPointer)ctx;
1073 imf_context_data->preedit_start_cb.callback = (XIMProc)preedit_start_callback;
1075 imf_context_data->preedit_done_cb.client_data = (XPointer)ctx;
1076 imf_context_data->preedit_done_cb.callback = (XIMProc)preedit_done_callback;
1078 imf_context_data->preedit_draw_cb.client_data = (XPointer)ctx;
1079 imf_context_data->preedit_draw_cb.callback = (XIMProc)preedit_draw_callback;
1081 imf_context_data->preedit_caret_cb.client_data = (XPointer)ctx;
1082 imf_context_data->preedit_caret_cb.callback = (XIMProc)preedit_caret_callback;
1084 return XVaCreateNestedList(0,
1085 XNPreeditStartCallback,
1086 &imf_context_data->preedit_start_cb,
1087 XNPreeditDoneCallback,
1088 &imf_context_data->preedit_done_cb,
1089 XNPreeditDrawCallback,
1090 &imf_context_data->preedit_draw_cb,
1091 XNPreeditCaretCallback,
1092 &imf_context_data->preedit_caret_cb,
1097 get_ic(Ecore_IMF_Context *ctx)
1099 Ecore_IMF_Context_Data *imf_context_data;
1101 imf_context_data = ecore_imf_context_data_get(ctx);
1102 ic = imf_context_data->ic;
1105 XIM_Im_Info *im_info = imf_context_data->im_info;
1106 XVaNestedList preedit_attr = NULL;
1107 XIMStyle im_style = 0;
1108 XPoint spot = { 0, 0 };
1113 EINA_LOG_WARN("Doesn't open XIM.");
1120 if (im_info->xim_styles)
1122 for (i = 0; i < im_info->xim_styles->count_styles; i++)
1125 if (im_info->xim_styles->supported_styles[i] & XIMPreeditCallbacks)
1126 printf("XIMPreeditCallbacks | ");
1127 if (im_info->xim_styles->supported_styles[i] & XIMPreeditPosition)
1128 printf("XIMPreeditPosition | ");
1129 if (im_info->xim_styles->supported_styles[i] & XIMPreeditArea)
1130 printf("XIMPreeditArea | ");
1131 if (im_info->xim_styles->supported_styles[i] & XIMPreeditNothing)
1132 printf("XIMPreeditNothing | ");
1133 if (im_info->xim_styles->supported_styles[i] & XIMPreeditNone)
1134 printf("XIMPreeditNone | ");
1135 if (im_info->xim_styles->supported_styles[i] & XIMStatusArea)
1136 printf("XIMStatusArea | ");
1137 if (im_info->xim_styles->supported_styles[i] & XIMStatusCallbacks)
1138 printf("XIMStatusCallbacks | ");
1139 if (im_info->xim_styles->supported_styles[i] & XIMStatusNothing)
1140 printf("XIMStatusNothing | ");
1141 if (im_info->xim_styles->supported_styles[i] & XIMStatusNone)
1142 printf("XIMStatusNone | ");
1147 // "OverTheSpot" = XIMPreeditPosition | XIMStatusNothing
1148 // "OffTheSpot" = XIMPreeditArea | XIMStatusArea
1149 // "Root" = XIMPreeditNothing | XIMStatusNothing
1151 if (imf_context_data->use_preedit == EINA_TRUE)
1153 if (im_info->supports_cursor)
1155 // kinput2 DOES do this...
1157 char **missing_charset_list;
1158 int missing_charset_count;
1161 im_style |= XIMPreeditPosition;
1162 im_style |= XIMStatusNothing;
1163 fs = XCreateFontSet(ecore_x_display_get(),
1165 &missing_charset_list,
1166 &missing_charset_count,
1168 preedit_attr = XVaCreateNestedList(0,
1169 XNSpotLocation, &spot,
1175 im_style |= XIMPreeditCallbacks;
1176 im_style |= XIMStatusNothing;
1177 preedit_attr = preedit_callback_set(ctx);
1179 name = XNPreeditAttributes;
1183 im_style |= XIMPreeditNothing;
1184 im_style |= XIMStatusNothing;
1189 ic = XCreateIC(im_info->im,
1190 XNInputStyle, im_style,
1191 XNClientWindow, imf_context_data->win,
1192 name, preedit_attr, NULL);
1194 XFree(preedit_attr);
1197 unsigned long mask = 0xaaaaaaaa;
1199 XNFilterEvents, &mask,
1201 imf_context_data->mask = mask;
1202 ecore_x_event_mask_set(imf_context_data->win, mask);
1205 imf_context_data->ic = ic;
1206 if (ic && imf_context_data->has_focus == EINA_TRUE)
1214 reinitialize_ic(Ecore_IMF_Context *ctx)
1216 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1217 XIC ic = imf_context_data->ic;
1221 imf_context_data->ic = NULL;
1222 if (imf_context_data->preedit_length)
1224 imf_context_data->preedit_length = 0;
1225 free(imf_context_data->preedit_chars);
1226 imf_context_data->preedit_chars = NULL;
1227 ecore_imf_context_preedit_changed_event_add(ctx);
1228 ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1234 reinitialize_all_ics(XIM_Im_Info *info)
1236 Eina_List *tmp_list;
1237 Ecore_IMF_Context *ctx;
1239 EINA_LIST_FOREACH (info->ics, tmp_list, ctx)
1240 reinitialize_ic(ctx);
1244 set_ic_client_window(Ecore_IMF_Context *ctx,
1245 Ecore_X_Window window)
1248 Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1249 Ecore_X_Window old_win;
1251 /* reinitialize IC */
1252 reinitialize_ic(ctx);
1254 old_win = imf_context_data->win;
1255 EINA_LOG_DBG("old_win:%d window:%d ", old_win, window);
1256 if (old_win != 0 && old_win != window) /* XXX how do check window... */
1259 info = imf_context_data->im_info;
1260 info->ics = eina_list_remove(info->ics, imf_context_data);
1261 imf_context_data->im_info = NULL;
1264 imf_context_data->win = window;
1266 if (window) /* XXX */
1268 XIM_Im_Info *info = NULL;
1269 info = get_im(window, imf_context_data->locale);
1270 imf_context_data->im_info = info;
1271 imf_context_data->im_info->ics =
1272 eina_list_prepend(imf_context_data->im_info->ics,
1277 static XIM_Im_Info *
1278 get_im(Ecore_X_Window window,
1284 XIM_Im_Info *im_info = NULL;
1285 XIM_Im_Info *info = NULL;
1286 EINA_LIST_FOREACH (open_ims, l, im_info) {
1287 if (strcmp(im_info->locale, locale) == 0)
1302 info = calloc(1, sizeof(XIM_Im_Info));
1303 if (!info) return NULL;
1304 open_ims = eina_list_prepend(open_ims, info);
1306 info->locale = strdup(locale);
1307 info->reconnecting = EINA_FALSE;
1310 xim_info_try_im(info);
1314 /* initialize info->im */
1316 xim_info_try_im(XIM_Im_Info *info)
1318 Ecore_X_Display *dsp;
1320 assert(info->im == NULL);
1321 if (info->reconnecting == EINA_TRUE)
1324 if (XSupportsLocale())
1326 if (!XSetLocaleModifiers(""))
1327 EINA_LOG_WARN("Unable to set locale modifiers with XSetLocaleModifiers()");
1328 dsp = ecore_x_display_get();
1329 info->im = XOpenIM(dsp, NULL, NULL, NULL);
1332 XRegisterIMInstantiateCallback(dsp,
1334 xim_instantiate_callback,
1336 info->reconnecting = EINA_TRUE;
1344 xim_info_display_closed(Ecore_X_Display *display __UNUSED__,
1345 int is_error __UNUSED__,
1348 Eina_List *ics, *tmp_list;
1349 Ecore_IMF_Context *ctx;
1351 open_ims = eina_list_remove(open_ims, info);
1356 EINA_LIST_FOREACH (ics, tmp_list, ctx)
1357 set_ic_client_window(ctx, 0);
1359 EINA_LIST_FREE (ics, ctx) {
1360 Ecore_IMF_Context_Data *imf_context_data;
1361 imf_context_data = ecore_imf_context_data_get(ctx);
1362 imf_context_data_destroy(imf_context_data);
1374 xim_instantiate_callback(Display *display,
1375 XPointer client_data,
1376 XPointer call_data __UNUSED__)
1378 XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1381 im = XOpenIM(display, NULL, NULL, NULL);
1385 fprintf(stderr, "Failed to connect to IM\n");
1392 XUnregisterIMInstantiateCallback(display, NULL, NULL, NULL,
1393 xim_instantiate_callback,
1395 info->reconnecting = EINA_FALSE;
1399 setup_im(XIM_Im_Info *info)
1401 XIMValuesList *ic_values = NULL;
1402 XIMCallback im_destroy_callback;
1407 im_destroy_callback.client_data = (XPointer)info;
1408 im_destroy_callback.callback = (XIMProc)xim_destroy_callback;
1409 XSetIMValues(info->im,
1410 XNDestroyCallback, &im_destroy_callback,
1413 XGetIMValues(info->im,
1414 XNQueryInputStyle, &info->xim_styles,
1415 XNQueryICValuesList, &ic_values,
1422 for (i = 0; i < ic_values->count_values; i++)
1424 if (!strcmp(ic_values->supported_values[i],
1425 XNStringConversionCallback))
1426 info->supports_string_conversion = EINA_TRUE;
1427 if (!strcmp(ic_values->supported_values[i],
1429 info->supports_cursor = EINA_TRUE;
1432 printf("values........\n");
1433 for (i = 0; i < ic_values->count_values; i++)
1434 printf("%s\n", ic_values->supported_values[i]);
1435 printf("styles........\n");
1436 for (i = 0; i < info->xim_styles->count_styles; i++)
1437 printf("%lx\n", info->xim_styles->supported_styles[i]);
1444 xim_destroy_callback(XIM xim __UNUSED__,
1445 XPointer client_data,
1446 XPointer call_data __UNUSED__)
1448 XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1451 reinitialize_all_ics(info);
1452 xim_info_try_im(info);
1457 #endif /* ENABLE_XIM */