Revert "Merge remote-tracking branch 'remotes/origin/upstream'"
[framework/uifw/ecore.git] / src / modules / immodules / xim / ecore_imf_xim.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <Eina.h>
6 #include <Ecore.h>
7 #include <Ecore_Input.h>
8 #include <Ecore_IMF.h>
9 #include <Ecore_X.h>
10 #include <X11/Xlib.h>
11 #include <X11/Xlocale.h>
12 #include <X11/Xutil.h>
13 #include <X11/keysym.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <langinfo.h>
18 #include <assert.h>
19
20 #define CLAMP(x, low, high) (x > high) ? high : (x < low) ? low : x
21 #define _(x)                x
22
23 #ifdef ENABLE_XIM
24 static Eina_List *open_ims = NULL;
25 #endif
26
27 #define FEEDBACK_MASK (XIMReverse | XIMUnderline | XIMHighlight)
28
29 typedef struct _XIM_Im_Info XIM_Im_Info;
30 struct _XIM_Im_Info
31 {
32    Ecore_X_Window win;
33    char          *locale;
34    XIM            im;
35    Eina_List     *ics;
36    Eina_Bool      reconnecting;
37    XIMStyles     *xim_styles;
38    Eina_Bool      supports_string_conversion : 1;
39    Eina_Bool      supports_cursor : 1;
40 };
41
42 typedef struct _Ecore_IMF_Context_Data Ecore_IMF_Context_Data;
43 struct _Ecore_IMF_Context_Data
44 {
45    Ecore_X_Window win;
46    long           mask;
47    XIC            ic; /* Input context for composed characters */
48    char          *locale;
49    XIM_Im_Info   *im_info;
50    int            preedit_length;
51    int            preedit_cursor;
52    Eina_Unicode  *preedit_chars;
53    Eina_Bool      use_preedit;
54    Eina_Bool      finalizing;
55    Eina_Bool      has_focus;
56    Eina_Bool      in_toplevel;
57    XIMFeedback   *feedbacks;
58
59    XIMCallback    preedit_start_cb;
60    XIMCallback    preedit_done_cb;
61    XIMCallback    preedit_draw_cb;
62    XIMCallback    preedit_caret_cb;
63 };
64
65 /* prototype */
66 Ecore_IMF_Context_Data *imf_context_data_new();
67 void                    imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data);
68
69 #ifdef ENABLE_XIM
70 static void          add_feedback_attr(Eina_List **attrs,
71                                        const char *str,
72                                        XIMFeedback feedback,
73                                        int start_pos,
74                                        int end_pos);
75
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,
81                                             XPointer client_data,
82                                             XPointer call_data);
83 static void          preedit_done_callback(XIC xic,
84                                            XPointer client_data,
85                                            XPointer call_data);
86 static int           xim_text_to_utf8(Ecore_IMF_Context *ctx,
87                                       XIMText *xim_text,
88                                       char **text);
89 static void          preedit_draw_callback(XIC xic,
90                                            XPointer client_data,
91                                            XIMPreeditDrawCallbackStruct *call_data);
92 static void          preedit_caret_callback(XIC xic,
93                                             XPointer client_data,
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,
98                             char *locale);
99 static void          xim_info_try_im(XIM_Im_Info *info);
100 static void          xim_info_display_closed(Ecore_X_Display *display,
101                                              int is_error,
102                                              XIM_Im_Info *info);
103 static void          xim_instantiate_callback(Display *display,
104                                               XPointer client_data,
105                                               XPointer call_data);
106 static void          setup_im(XIM_Im_Info *info);
107 static void          xim_destroy_callback(XIM xim,
108                                           XPointer client_data,
109                                           XPointer call_data);
110 #endif
111
112 #ifdef ENABLE_XIM
113 static unsigned int
114 utf8_offset_to_index(const char *str, int offset)
115 {
116    int idx = 0;
117    int i;
118    for (i = 0; i < offset; i++)
119      {
120         eina_unicode_utf8_get_next(str, &idx);
121      }
122
123    return idx;
124 }
125
126 #endif
127
128 static void
129 _ecore_imf_context_xim_add(Ecore_IMF_Context *ctx)
130 {
131    EINA_LOG_DBG("in");
132 #ifdef ENABLE_XIM
133    Ecore_IMF_Context_Data *imf_context_data = NULL;
134
135    imf_context_data = imf_context_data_new();
136    EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
137
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;
142
143    ecore_imf_context_data_set(ctx, imf_context_data);
144 #else
145    (void)ctx;
146 #endif
147 }
148
149 static void
150 _ecore_imf_context_xim_del(Ecore_IMF_Context *ctx)
151 {
152    EINA_LOG_DBG("in");
153 #ifdef ENABLE_XIM
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);
157
158    imf_context_data->finalizing = EINA_TRUE;
159    if (imf_context_data->im_info && !imf_context_data->im_info->ics->next)
160      {
161         if (imf_context_data->im_info->reconnecting == EINA_TRUE)
162           {
163              Ecore_X_Display *dsp;
164              dsp = ecore_x_display_get();
165              XUnregisterIMInstantiateCallback(dsp,
166                                               NULL, NULL, NULL,
167                                               xim_instantiate_callback,
168                                               (XPointer)imf_context_data->im_info);
169           }
170         else if (imf_context_data->im_info->im)
171           {
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,
177                           NULL);
178           }
179      }
180
181    set_ic_client_window(ctx, 0);
182
183    imf_context_data_destroy(imf_context_data);
184 #else
185    (void)ctx;
186 #endif
187 }
188
189 static void
190 _ecore_imf_context_xim_client_window_set(Ecore_IMF_Context *ctx,
191                                          void *window)
192 {
193    EINA_LOG_DBG("in");
194 #ifdef ENABLE_XIM
195    set_ic_client_window(ctx, (Ecore_X_Window)((Ecore_Window)window));
196 #else
197    (void)ctx;
198    (void)window;
199 #endif
200 }
201
202 static void
203 _ecore_imf_context_xim_preedit_string_get(Ecore_IMF_Context *ctx,
204                                           char **str,
205                                           int *cursor_pos)
206 {
207    EINA_LOG_DBG("in");
208 #ifdef ENABLE_XIM
209    Ecore_IMF_Context_Data *imf_context_data;
210    char *utf8;
211    int len;
212    imf_context_data = ecore_imf_context_data_get(ctx);
213    EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
214
215    if (imf_context_data->preedit_chars)
216      {
217         utf8 = eina_unicode_unicode_to_utf8(imf_context_data->preedit_chars,
218                                             &len);
219         if (str)
220           *str = utf8;
221         else
222           free(utf8);
223      }
224    else
225      {
226         if (str)
227           *str = NULL;
228         if (cursor_pos)
229           *cursor_pos = 0;
230      }
231
232    if (cursor_pos)
233      *cursor_pos = imf_context_data->preedit_cursor;
234 #else
235    (void)ctx;
236    if (str)
237      *str = NULL;
238    if (cursor_pos)
239      *cursor_pos = 0;
240 #endif
241 }
242
243 static void
244 _ecore_imf_context_xim_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
245                                                           char **str,
246                                                           Eina_List **attrs,
247                                                           int *cursor_pos)
248 {
249    EINA_LOG_DBG("in");
250
251 #ifdef ENABLE_XIM
252    Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
253
254    _ecore_imf_context_xim_preedit_string_get(ctx, str, cursor_pos);
255
256    if (!attrs) return;
257    if (!imf_context_data || !imf_context_data->feedbacks) return;
258
259    int i = 0;
260    XIMFeedback last_feedback = 0;
261    int start = -1;
262
263    for (i = 0; i < imf_context_data->preedit_length; i++)
264      {
265         XIMFeedback new_feedback = imf_context_data->feedbacks[i] & FEEDBACK_MASK;
266
267         if (new_feedback != last_feedback)
268           {
269              if (start >= 0)
270                add_feedback_attr(attrs, *str, last_feedback, start, i);
271
272              last_feedback = new_feedback;
273              start = i;
274           }
275      }
276
277    if (start >= 0)
278      add_feedback_attr(attrs, *str, last_feedback, start, i);
279 #else
280    (void)ctx;
281    if (str)
282      *str = NULL;
283    if (attrs)
284      *attrs = NULL;
285    if (cursor_pos)
286      *cursor_pos = 0;
287 #endif
288 }
289
290 static void
291 _ecore_imf_context_xim_focus_in(Ecore_IMF_Context *ctx)
292 {
293    EINA_LOG_DBG("in");
294 #ifdef ENABLE_XIM
295    XIC ic;
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);
299
300    ic = imf_context_data->ic;
301    imf_context_data->has_focus = EINA_TRUE;
302
303    if (ecore_imf_context_input_panel_enabled_get(ctx))
304      ecore_imf_context_input_panel_show(ctx);
305
306    if (ic)
307      {
308         char *str;
309
310 #ifdef X_HAVE_UTF8_STRING
311         if ((str = Xutf8ResetIC(ic)))
312 #else
313         if ((str = XmbResetIC(ic)))
314 #endif
315           XFree(str);
316
317         XSetICFocus(ic);
318      }
319 #else
320    (void)ctx;
321 #endif
322 }
323
324 static void
325 _ecore_imf_context_xim_focus_out(Ecore_IMF_Context *ctx)
326 {
327    EINA_LOG_DBG("%s in", __FUNCTION__);
328 #ifdef ENABLE_XIM
329    XIC ic;
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);
333
334    if (imf_context_data->has_focus == EINA_TRUE)
335      {
336         imf_context_data->has_focus = EINA_FALSE;
337         ic = imf_context_data->ic;
338         if (ic)
339           XUnsetICFocus(ic);
340
341         if (ecore_imf_context_input_panel_enabled_get(ctx))
342           ecore_imf_context_input_panel_hide(ctx);
343      }
344 #else
345    (void)ctx;
346 #endif
347 }
348
349 static void
350 _ecore_imf_context_xim_reset(Ecore_IMF_Context *ctx)
351 {
352    EINA_LOG_DBG("%s in", __FUNCTION__);
353 #ifdef ENABLE_XIM
354    XIC ic;
355    Ecore_IMF_Context_Data *imf_context_data;
356    char *result;
357
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;
362
363    imf_context_data = ecore_imf_context_data_get(ctx);
364    EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
365
366    ic = imf_context_data->ic;
367    if (!ic)
368      return;
369
370    if (imf_context_data->preedit_length == 0)
371      return;
372
373    preedit_attr = XVaCreateNestedList(0,
374                                       XNPreeditState, &preedit_state,
375                                       NULL);
376    if (!XGetICValues(ic,
377                      XNPreeditAttributes, preedit_attr,
378                      NULL))
379      have_preedit_state = EINA_TRUE;
380
381    XFree(preedit_attr);
382
383    result = XmbResetIC(ic);
384
385    preedit_attr = XVaCreateNestedList(0,
386                                       XNPreeditState, preedit_state,
387                                       NULL);
388    if (have_preedit_state)
389      XSetICValues(ic,
390                   XNPreeditAttributes, preedit_attr,
391                   NULL);
392
393    XFree(preedit_attr);
394
395    if (imf_context_data->feedbacks)
396      {
397         free(imf_context_data->feedbacks);
398         imf_context_data->feedbacks = NULL;
399      }
400
401    if (imf_context_data->preedit_length)
402      {
403         imf_context_data->preedit_length = 0;
404         free(imf_context_data->preedit_chars);
405         imf_context_data->preedit_chars = NULL;
406
407         ecore_imf_context_preedit_changed_event_add(ctx);
408         ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
409      }
410
411    if (result)
412      {
413         char *result_utf8 = strdup(result);
414         if (result_utf8)
415           {
416              ecore_imf_context_commit_event_add(ctx, result_utf8);
417              ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, result_utf8);
418              free(result_utf8);
419           }
420      }
421
422    XFree(result);
423 #else
424    (void)ctx;
425 #endif
426 }
427
428 static void
429 _ecore_imf_context_xim_use_preedit_set(Ecore_IMF_Context *ctx,
430                                        Eina_Bool use_preedit)
431 {
432    EINA_LOG_DBG("in");
433 #ifdef ENABLE_XIM
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);
437
438    use_preedit = use_preedit != EINA_FALSE;
439
440    if (imf_context_data->use_preedit != use_preedit)
441      {
442         imf_context_data->use_preedit = use_preedit;
443         reinitialize_ic(ctx);
444      }
445 #else
446    (void)ctx;
447    (void)use_preedit;
448 #endif
449 }
450
451 #ifdef ENABLE_XIM
452 static void
453 add_feedback_attr(Eina_List **attrs,
454                   const char *str,
455                   XIMFeedback feedback,
456                   int start_pos,
457                   int end_pos)
458 {
459    Ecore_IMF_Preedit_Attr *attr = NULL;
460
461    unsigned int start_index = utf8_offset_to_index(str, start_pos);
462    unsigned int end_index = utf8_offset_to_index(str, end_pos);
463
464    if (feedback & FEEDBACK_MASK)
465      {
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);
470      }
471
472    if (feedback & XIMUnderline)
473      attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
474
475    if (feedback & XIMReverse)
476      attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
477
478    if (feedback & XIMHighlight)
479      attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB3;
480 }
481
482 #endif
483
484 static void
485 _ecore_imf_context_xim_cursor_location_set(Ecore_IMF_Context *ctx,
486                                            int x, int y, int w, int h)
487 {
488    EINA_LOG_DBG("%s in", __FUNCTION__);
489
490 #ifdef ENABLE_XIM
491    Ecore_IMF_Context_Data *imf_context_data;
492    XIC ic;
493    XVaNestedList preedit_attr;
494    XPoint spot;
495
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;
499    if (!ic)
500      return;
501
502    spot.x = x;
503    spot.y = y + h;
504
505    preedit_attr = XVaCreateNestedList(0,
506                                       XNSpotLocation, &spot,
507                                       NULL);
508    XSetICValues(ic,
509                 XNPreeditAttributes, preedit_attr,
510                 NULL);
511
512    XFree(preedit_attr);
513 #else
514    (void)ctx;
515    (void)x;
516    (void)y;
517    (void)h;
518 #endif
519    (void)(w); // yes w is unused, but only a bi-product of the algorithm
520 }
521
522 static void
523 _ecore_imf_context_xim_input_panel_show(Ecore_IMF_Context *ctx)
524 {
525    EINA_LOG_DBG("%s in", __FUNCTION__);
526
527 #ifdef ENABLE_XIM
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);
531
532    ecore_x_e_virtual_keyboard_state_set
533         (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_ON);
534 #else
535    (void)ctx;
536 #endif
537 }
538
539 static void
540 _ecore_imf_context_xim_input_panel_hide(Ecore_IMF_Context *ctx)
541 {
542    EINA_LOG_DBG("%s in", __FUNCTION__);
543
544 #ifdef ENABLE_XIM
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);
548
549    ecore_x_e_virtual_keyboard_state_set
550         (imf_context_data->win, ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF);
551 #else
552    (void)ctx;
553 #endif
554 }
555
556 #ifdef ENABLE_XIM
557 static unsigned int
558 _ecore_x_event_reverse_modifiers(unsigned int state)
559 {
560    unsigned int modifiers = 0;
561
562    /**< "Control" is pressed */
563    if (state & ECORE_IMF_KEYBOARD_MODIFIER_CTRL)
564      modifiers |= ControlMask;
565
566    /**< "Alt" is pressed */
567    if (state & ECORE_IMF_KEYBOARD_MODIFIER_ALT)
568      modifiers |= Mod1Mask;
569
570    /**< "Shift" is pressed */
571    if (state & ECORE_IMF_KEYBOARD_MODIFIER_SHIFT)
572      modifiers |= ShiftMask;
573
574    /**< "Win" (between "Ctrl" and "A */
575    if (state & ECORE_IMF_KEYBOARD_MODIFIER_WIN)
576      modifiers |= Mod5Mask;
577
578    return modifiers;
579 }
580
581 static unsigned int
582 _ecore_x_event_reverse_locks(unsigned int state)
583 {
584    unsigned int locks = 0;
585
586    /**< "Num" lock is active */
587    if (state & ECORE_IMF_KEYBOARD_LOCK_NUM)
588      locks |= Mod3Mask;
589
590    if (state & ECORE_IMF_KEYBOARD_LOCK_CAPS)
591      locks |= LockMask;
592
593 #if 0 /* FIXME: add mask. */
594    if (state & ECORE_IMF_KEYBOARD_LOCK_SCROLL)
595      ;
596 #endif
597
598    return locks;
599 }
600
601 static KeyCode
602 _keycode_get(Ecore_X_Display *dsp,
603              const char *keyname)
604 {
605    KeyCode keycode;
606
607    // EINA_LOG_DBG("keyname:%s keysym:%lu", keyname, XStringToKeysym(keyname));
608    if (strcmp(keyname, "Keycode-0") == 0)
609      keycode = 0;
610    else
611      keycode = XKeysymToKeycode(dsp, XStringToKeysym(keyname));
612
613    return keycode;
614 }
615
616 #endif
617
618 static Eina_Bool
619 _ecore_imf_context_xim_filter_event(Ecore_IMF_Context *ctx,
620                                     Ecore_IMF_Event_Type type,
621                                     Ecore_IMF_Event *event)
622 {
623    EINA_LOG_DBG("%s in", __FUNCTION__);
624 #ifdef ENABLE_XIM
625    Ecore_IMF_Context_Data *imf_context_data;
626    XIC ic;
627
628    Ecore_X_Display *dsp;
629    Ecore_X_Window win;
630
631    int val;
632    char compose_buffer[256];
633    KeySym sym;
634    char *compose = NULL;
635    char *tmp = NULL;
636    Eina_Bool result = EINA_FALSE;
637
638    imf_context_data = ecore_imf_context_data_get(ctx);
639    if (!imf_context_data) return EINA_FALSE;
640    ic = imf_context_data->ic;
641    if (!ic)
642      ic = get_ic(ctx);
643
644    if (type == ECORE_IMF_EVENT_KEY_DOWN)
645      {
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");
649
650         dsp = ecore_x_display_get();
651         win = imf_context_data->win;
652
653         xev.type = KeyPress;
654         xev.serial = 0; /* hope it doesn't matter */
655         xev.send_event = 0;
656         xev.display = dsp;
657         xev.window = win;
658         xev.root = ecore_x_window_root_get(win);
659         xev.subwindow = win;
660         xev.time = ev->timestamp;
661         xev.x = xev.x_root = 0;
662         xev.y = xev.y_root = 0;
663         xev.state = 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;
668
669         if (ic)
670           {
671              Status mbstatus;
672 #ifdef X_HAVE_UTF8_STRING
673              val = Xutf8LookupString(ic,
674                                      &xev,
675                                      compose_buffer,
676                                      sizeof(compose_buffer) - 1,
677                                      &sym,
678                                      &mbstatus);
679 #else /* ifdef X_HAVE_UTF8_STRING */
680              val = XmbLookupString(ic,
681                                    &xev,
682                                    compose_buffer,
683                                    sizeof(compose_buffer) - 1,
684                                    &sym,
685                                    &mbstatus);
686 #endif /* ifdef X_HAVE_UTF8_STRING */
687              if (mbstatus == XBufferOverflow)
688                {
689                   tmp = malloc(sizeof (char) * (val + 1));
690                   if (!tmp)
691                     return EINA_FALSE;
692
693                   compose = tmp;
694
695 #ifdef X_HAVE_UTF8_STRING
696                   val = Xutf8LookupString(ic,
697                                           (XKeyEvent *)&xev,
698                                           tmp,
699                                           val,
700                                           &sym,
701                                           &mbstatus);
702 #else /* ifdef X_HAVE_UTF8_STRING */
703                   val = XmbLookupString(ic,
704                                         (XKeyEvent *)&xev,
705                                         tmp,
706                                         val,
707                                         &sym,
708                                         &mbstatus);
709 #endif /* ifdef X_HAVE_UTF8_STRING */
710                   if (val > 0)
711                     {
712                        tmp[val] = '\0';
713 #ifndef X_HAVE_UTF8_STRING
714                        compose = eina_str_convert(nl_langinfo(CODESET),
715                                                   "UTF-8", tmp);
716                        free(tmp);
717                        tmp = compose;
718 #endif /* ifndef X_HAVE_UTF8_STRING */
719                     }
720                   else
721                     compose = NULL;
722                }
723              else if (val > 0)
724                {
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",
730                                              compose_buffer);
731 #endif /* ifdef X_HAVE_UTF8_STRING */
732                }
733           }
734         else
735           {
736              XComposeStatus status;
737              val = XLookupString(&xev,
738                                  compose_buffer,
739                                  sizeof(compose_buffer),
740                                  &sym,
741                                  &status);
742              if (val > 0)
743                {
744                   compose_buffer[val] = '\0';
745                   compose = eina_str_convert(nl_langinfo(CODESET),
746                                              "UTF-8", compose_buffer);
747                }
748           }
749
750         if (compose)
751           {
752              Eina_Unicode *unicode;
753              int len;
754              unicode = eina_unicode_utf8_to_unicode(compose, &len);
755              if (!unicode) abort();
756              if (unicode[0] >= 0x20 && unicode[0] != 0x7f)
757                {
758                   ecore_imf_context_commit_event_add(ctx, compose);
759                   ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_COMMIT, compose);
760                   result = EINA_TRUE;
761                }
762              free(compose);
763              free(unicode);
764           }
765      }
766
767    return result;
768 #else
769    (void)ctx;
770    (void)type;
771    (void)event;
772    return EINA_FALSE;
773 #endif
774 }
775
776 static const Ecore_IMF_Context_Info xim_info = {
777    .id = "xim",
778    .description = _("X input method"),
779    .default_locales = "ko:ja:th:zh",
780    .canvas_type = "evas",
781    .canvas_required = 1,
782 };
783
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
814 };
815
816 static Ecore_IMF_Context *
817 xim_imf_module_create(void)
818 {
819    EINA_LOG_DBG("%s in", __FUNCTION__);
820    Ecore_IMF_Context *ctx = NULL;
821
822    ctx = ecore_imf_context_new(&xim_class);
823    if (!ctx)
824      goto error;
825
826    return ctx;
827
828 error:
829    free(ctx);
830    return NULL;
831 }
832
833 static Ecore_IMF_Context *
834 xim_imf_module_exit(void)
835 {
836    return NULL;
837 }
838
839 Eina_Bool
840 ecore_imf_xim_init(void)
841 {
842    EINA_LOG_DBG("%s in", __FUNCTION__);
843    eina_init();
844    ecore_x_init(NULL);
845    ecore_imf_module_register(&xim_info,
846                              xim_imf_module_create,
847                              xim_imf_module_exit);
848
849    return EINA_TRUE;
850 }
851
852 void
853 ecore_imf_xim_shutdown(void)
854 {
855 #ifdef ENABLE_XIM
856    while (open_ims)
857      {
858         XIM_Im_Info *info = open_ims->data;
859         Ecore_X_Display *display = ecore_x_display_get();
860
861         xim_info_display_closed(display, EINA_FALSE, info);
862      }
863 #endif
864
865    ecore_x_shutdown();
866    eina_shutdown();
867 }
868
869 EINA_MODULE_INIT(ecore_imf_xim_init);
870 EINA_MODULE_SHUTDOWN(ecore_imf_xim_shutdown);
871
872 #ifdef ENABLE_XIM
873 /*
874  * internal functions
875  */
876 Ecore_IMF_Context_Data *
877 imf_context_data_new()
878 {
879    Ecore_IMF_Context_Data *imf_context_data = NULL;
880    char *locale;
881
882    locale = setlocale(LC_CTYPE, "");
883    if (!locale) return NULL;
884
885    if (!XSupportsLocale()) return NULL;
886
887    imf_context_data = calloc(1, sizeof(Ecore_IMF_Context_Data));
888    EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
889
890    imf_context_data->locale = strdup(locale);
891    if (!imf_context_data->locale) goto error;
892
893    return imf_context_data;
894 error:
895    imf_context_data_destroy(imf_context_data);
896    return NULL;
897 }
898
899 void
900 imf_context_data_destroy(Ecore_IMF_Context_Data *imf_context_data)
901 {
902    if (!imf_context_data)
903      return;
904
905    if (imf_context_data->ic)
906      XDestroyIC(imf_context_data->ic);
907
908    free(imf_context_data->preedit_chars);
909
910    if (imf_context_data->feedbacks)
911      {
912         free(imf_context_data->feedbacks);
913         imf_context_data->feedbacks = NULL;
914      }
915
916    free(imf_context_data->locale);
917    free(imf_context_data);
918 }
919
920 static int
921 preedit_start_callback(XIC xic __UNUSED__,
922                        XPointer client_data,
923                        XPointer call_data __UNUSED__)
924 {
925    EINA_LOG_DBG("in");
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;
930
931    if (imf_context_data->finalizing == EINA_FALSE)
932      {
933         ecore_imf_context_preedit_start_event_add(ctx);
934         ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_START, NULL);
935      }
936    return -1;
937 }
938
939 static void
940 preedit_done_callback(XIC xic __UNUSED__,
941                       XPointer client_data,
942                       XPointer call_data __UNUSED__)
943 {
944    EINA_LOG_DBG("in");
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);
949
950    if (imf_context_data->preedit_length)
951      {
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);
957      }
958
959    if (imf_context_data->finalizing == EINA_FALSE)
960      {
961         ecore_imf_context_preedit_end_event_add(ctx);
962         ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
963      }
964 }
965
966 /* FIXME */
967 static int
968 xim_text_to_utf8(Ecore_IMF_Context *ctx __UNUSED__,
969                  XIMText *xim_text,
970                  char **text)
971 {
972    int text_length = 0;
973    char *result = NULL;
974
975    if (xim_text && xim_text->string.multi_byte)
976      {
977         if (xim_text->encoding_is_wchar)
978           {
979              EINA_LOG_WARN("Wide character return from Xlib not currently supported");
980              *text = NULL;
981              return 0;
982           }
983
984         /* XXX Convert to UTF-8 */
985         result = strdup(xim_text->string.multi_byte);
986         if (result)
987           {
988              text_length = eina_unicode_utf8_get_len(result);
989              if (text_length != xim_text->length)
990                {
991                   EINA_LOG_WARN("Size mismatch when converting text from input method: supplied length = %d\n, result length = %d", xim_text->length, text_length);
992                }
993           }
994         else
995           {
996              EINA_LOG_WARN("Error converting text from IM to UCS-4");
997              *text = NULL;
998              return 0;
999           }
1000
1001         *text = result;
1002         return text_length;
1003      }
1004    else
1005      {
1006         *text = NULL;
1007         return 0;
1008      }
1009 }
1010
1011 static void
1012 preedit_draw_callback(XIC xic __UNUSED__,
1013                       XPointer client_data,
1014                       XIMPreeditDrawCallbackStruct *call_data)
1015 {
1016    EINA_LOG_DBG("in");
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;
1021    char *tmp;
1022    Eina_Unicode *new_text = NULL;
1023    Eina_UStrbuf *preedit_bufs = NULL;
1024    int new_text_length;
1025    int i = 0;
1026
1027    EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1028
1029    preedit_bufs = eina_ustrbuf_new();
1030    if (imf_context_data->preedit_chars)
1031      {
1032         ret = eina_ustrbuf_append(preedit_bufs, imf_context_data->preedit_chars);
1033         if (ret == EINA_FALSE) goto done;
1034      }
1035
1036    new_text_length = xim_text_to_utf8(ctx, t, &tmp);
1037    if (tmp)
1038      {
1039         int tmp_len;
1040         new_text = eina_unicode_utf8_to_unicode((const char *)tmp, &tmp_len);
1041         free(tmp);
1042      }
1043
1044    if (t == NULL)
1045      {
1046         /* delete string */
1047         ret = eina_ustrbuf_remove(preedit_bufs,
1048                                   call_data->chg_first, call_data->chg_length);
1049      }
1050    else if (call_data->chg_length == 0)
1051      {
1052         /* insert string */
1053         ret = eina_ustrbuf_insert(preedit_bufs, new_text, call_data->chg_first);
1054      }
1055    else if (call_data->chg_length > 0)
1056      {
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;
1061
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;
1065      }
1066    else
1067      {
1068         ret = EINA_FALSE;
1069      }
1070
1071 done:
1072    if (ret == EINA_TRUE)
1073      {
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);
1079
1080         if (imf_context_data->feedbacks)
1081           {
1082              free(imf_context_data->feedbacks);
1083              imf_context_data->feedbacks = NULL;
1084           }
1085
1086         if (imf_context_data->preedit_length > 0)
1087           {
1088              imf_context_data->feedbacks = calloc(imf_context_data->preedit_length, sizeof(XIMFeedback));
1089
1090              for (i = 0; i < imf_context_data->preedit_length; i++)
1091                imf_context_data->feedbacks[i] = t->feedback[i];
1092           }
1093
1094         ecore_imf_context_preedit_changed_event_add(ctx);
1095         ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1096      }
1097
1098    free(new_text);
1099    eina_ustrbuf_free(preedit_bufs);
1100 }
1101
1102 static void
1103 preedit_caret_callback(XIC xic __UNUSED__,
1104                        XPointer client_data,
1105                        XIMPreeditCaretCallbackStruct *call_data)
1106 {
1107    EINA_LOG_DBG("in");
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);
1112
1113    if (call_data->direction == XIMAbsolutePosition)
1114      {
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)
1118           {
1119              ecore_imf_context_preedit_changed_event_add(ctx);
1120              ecore_imf_context_event_callback_call(ctx, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, NULL);
1121           }
1122      }
1123 }
1124
1125 static XVaNestedList
1126 preedit_callback_set(Ecore_IMF_Context *ctx)
1127 {
1128    Ecore_IMF_Context_Data *imf_context_data;
1129    imf_context_data = ecore_imf_context_data_get(ctx);
1130
1131    imf_context_data->preedit_start_cb.client_data = (XPointer)ctx;
1132    imf_context_data->preedit_start_cb.callback = (XIMProc)preedit_start_callback;
1133
1134    imf_context_data->preedit_done_cb.client_data = (XPointer)ctx;
1135    imf_context_data->preedit_done_cb.callback = (XIMProc)preedit_done_callback;
1136
1137    imf_context_data->preedit_draw_cb.client_data = (XPointer)ctx;
1138    imf_context_data->preedit_draw_cb.callback = (XIMProc)preedit_draw_callback;
1139
1140    imf_context_data->preedit_caret_cb.client_data = (XPointer)ctx;
1141    imf_context_data->preedit_caret_cb.callback = (XIMProc)preedit_caret_callback;
1142
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,
1152                               NULL);
1153 }
1154
1155 static XIC
1156 get_ic(Ecore_IMF_Context *ctx)
1157 {
1158    Ecore_IMF_Context_Data *imf_context_data;
1159    XIC ic;
1160    imf_context_data = ecore_imf_context_data_get(ctx);
1161    EINA_SAFETY_ON_NULL_RETURN_VAL(imf_context_data, NULL);
1162
1163    ic = imf_context_data->ic;
1164    if (!ic)
1165      {
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 };
1170         char *name = NULL;
1171
1172         if (!im_info)
1173           {
1174              EINA_LOG_WARN("Doesn't open XIM.");
1175              return NULL;
1176           }
1177
1178         // supported styles
1179 #if 0
1180         int i;
1181         if (im_info->xim_styles)
1182           {
1183              for (i = 0; i < im_info->xim_styles->count_styles; i++)
1184                {
1185                   printf("%i: ", 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 | ");
1204                   printf("\n");
1205                }
1206           }
1207 #endif
1208         // "OverTheSpot" = XIMPreeditPosition | XIMStatusNothing
1209         // "OffTheSpot" = XIMPreeditArea | XIMStatusArea
1210         // "Root" = XIMPreeditNothing | XIMStatusNothing
1211
1212         if (imf_context_data->use_preedit == EINA_TRUE)
1213           {
1214              if (im_info->supports_cursor)
1215                {
1216                   // kinput2 DOES do this...
1217                   XFontSet fs;
1218                   char **missing_charset_list;
1219                   int missing_charset_count;
1220                   char *def_string;
1221
1222                   im_style |= XIMPreeditPosition;
1223                   im_style |= XIMStatusNothing;
1224                   fs = XCreateFontSet(ecore_x_display_get(),
1225                                       "fixed",
1226                                       &missing_charset_list,
1227                                       &missing_charset_count,
1228                                       &def_string);
1229                   preedit_attr = XVaCreateNestedList(0,
1230                                                      XNSpotLocation, &spot,
1231                                                      XNFontSet, fs,
1232                                                      NULL);
1233                }
1234              else
1235                {
1236                   im_style |= XIMPreeditCallbacks;
1237                   im_style |= XIMStatusNothing;
1238                   preedit_attr = preedit_callback_set(ctx);
1239                }
1240              name = XNPreeditAttributes;
1241           }
1242         else
1243           {
1244              im_style |= XIMPreeditNothing;
1245              im_style |= XIMStatusNothing;
1246           }
1247
1248         if (!im_info->xim_styles)
1249           {
1250              EINA_LOG_WARN("No XIM styles supported! Wanted %#llx",
1251                            (unsigned long long)im_style);
1252              im_style = 0;
1253           }
1254         else
1255           {
1256              XIMStyle fallback = 0;
1257              int i;
1258
1259              for (i = 0; i < im_info->xim_styles->count_styles; i++)
1260                {
1261                   XIMStyle cur = im_info->xim_styles->supported_styles[i];
1262                   if (cur == im_style)
1263                     break;
1264                   else if (cur == (XIMPreeditNothing | XIMStatusNothing))
1265                     /* TODO: fallback is just that or the anyone? */
1266                     fallback = cur;
1267                }
1268
1269              if (i == im_info->xim_styles->count_styles)
1270                {
1271                   if (fallback)
1272                     {
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;
1278                     }
1279                   else
1280                     {
1281                        EINA_LOG_WARN("Wanted XIM style %#llx not found, "
1282                                      "no fallback supported.",
1283                                      (unsigned long long)im_style);
1284                        im_style = 0;
1285                     }
1286                }
1287           }
1288
1289         if ((im_info->im) && (im_style))
1290           {
1291              ic = XCreateIC(im_info->im,
1292                             XNInputStyle, im_style,
1293                             XNClientWindow, imf_context_data->win,
1294                             name, preedit_attr, NULL);
1295           }
1296         XFree(preedit_attr);
1297         if (ic)
1298           {
1299              unsigned long mask = 0xaaaaaaaa;
1300              XGetICValues(ic,
1301                           XNFilterEvents, &mask,
1302                           NULL);
1303              imf_context_data->mask = mask;
1304              ecore_x_event_mask_set(imf_context_data->win, mask);
1305           }
1306
1307         imf_context_data->ic = ic;
1308         if (ic && imf_context_data->has_focus == EINA_TRUE)
1309           XSetICFocus(ic);
1310      }
1311
1312    return ic;
1313 }
1314
1315 static void
1316 reinitialize_ic(Ecore_IMF_Context *ctx)
1317 {
1318    Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1319    EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1320
1321    XIC ic = imf_context_data->ic;
1322    if (ic)
1323      {
1324         XDestroyIC(ic);
1325         imf_context_data->ic = NULL;
1326         if (imf_context_data->preedit_length)
1327           {
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);
1333           }
1334      }
1335 }
1336
1337 static void
1338 reinitialize_all_ics(XIM_Im_Info *info)
1339 {
1340    Eina_List *tmp_list;
1341    Ecore_IMF_Context *ctx;
1342
1343    EINA_LIST_FOREACH (info->ics, tmp_list, ctx)
1344      reinitialize_ic(ctx);
1345 }
1346
1347 static void
1348 set_ic_client_window(Ecore_IMF_Context *ctx,
1349                      Ecore_X_Window window)
1350 {
1351    EINA_LOG_DBG("in");
1352    Ecore_IMF_Context_Data *imf_context_data = ecore_imf_context_data_get(ctx);
1353    Ecore_X_Window old_win;
1354
1355    EINA_SAFETY_ON_NULL_RETURN(imf_context_data);
1356
1357    /* reinitialize IC */
1358    reinitialize_ic(ctx);
1359
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... */
1363      {
1364         XIM_Im_Info *info;
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;
1368      }
1369
1370    imf_context_data->win = window;
1371
1372    if (window) /* XXX */
1373      {
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,
1379                             imf_context_data);
1380      }
1381 }
1382
1383 static XIM_Im_Info *
1384 get_im(Ecore_X_Window window,
1385        char *locale)
1386 {
1387    EINA_LOG_DBG("in");
1388
1389    Eina_List *l;
1390    XIM_Im_Info *im_info = NULL;
1391    XIM_Im_Info *info = NULL;
1392    EINA_LIST_FOREACH (open_ims, l, im_info)
1393      {
1394         if (strcmp(im_info->locale, locale) == 0)
1395           {
1396              if (im_info->im)
1397                {
1398                   return im_info;
1399                }
1400              else
1401                {
1402                   info = im_info;
1403                   break;
1404                }
1405           }
1406      }
1407
1408    if (!info)
1409      {
1410         info = calloc(1, sizeof(XIM_Im_Info));
1411         if (!info) return NULL;
1412         open_ims = eina_list_prepend(open_ims, info);
1413         info->win = window;
1414         info->locale = strdup(locale);
1415         info->reconnecting = EINA_FALSE;
1416      }
1417
1418    xim_info_try_im(info);
1419    return info;
1420 }
1421
1422 /* initialize info->im */
1423 static void
1424 xim_info_try_im(XIM_Im_Info *info)
1425 {
1426    Ecore_X_Display *dsp;
1427
1428    assert(info->im == NULL);
1429    if (info->reconnecting == EINA_TRUE)
1430      return;
1431
1432    if (XSupportsLocale())
1433      {
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);
1438         if (!info->im)
1439           {
1440              XRegisterIMInstantiateCallback(dsp,
1441                                             NULL, NULL, NULL,
1442                                             xim_instantiate_callback,
1443                                             (XPointer)info);
1444              info->reconnecting = EINA_TRUE;
1445              return;
1446           }
1447         setup_im(info);
1448      }
1449 }
1450
1451 static void
1452 xim_info_display_closed(Ecore_X_Display *display __UNUSED__,
1453                         int is_error __UNUSED__,
1454                         XIM_Im_Info *info)
1455 {
1456    Eina_List *ics, *tmp_list;
1457    Ecore_IMF_Context *ctx;
1458
1459    open_ims = eina_list_remove(open_ims, info);
1460
1461    ics = info->ics;
1462    info->ics = NULL;
1463
1464    EINA_LIST_FOREACH (ics, tmp_list, ctx)
1465      set_ic_client_window(ctx, 0);
1466
1467    EINA_LIST_FREE (ics, ctx)
1468      {
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);
1472      }
1473
1474    free(info->locale);
1475
1476    if (info->im)
1477      XCloseIM(info->im);
1478
1479    free(info);
1480 }
1481
1482 static void
1483 xim_instantiate_callback(Display *display,
1484                          XPointer client_data,
1485                          XPointer call_data __UNUSED__)
1486 {
1487    XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1488    XIM im = NULL;
1489
1490    im = XOpenIM(display, NULL, NULL, NULL);
1491
1492    if (!im)
1493      {
1494         fprintf(stderr, "Failed to connect to IM\n");
1495         return;
1496      }
1497
1498    info->im = im;
1499    setup_im(info);
1500
1501    XUnregisterIMInstantiateCallback(display, NULL, NULL, NULL,
1502                                     xim_instantiate_callback,
1503                                     (XPointer)info);
1504    info->reconnecting = EINA_FALSE;
1505 }
1506
1507 static void
1508 setup_im(XIM_Im_Info *info)
1509 {
1510    XIMValuesList *ic_values = NULL;
1511    XIMCallback im_destroy_callback;
1512
1513    if (!info->im)
1514      return;
1515
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,
1520                 NULL);
1521
1522    XGetIMValues(info->im,
1523                 XNQueryInputStyle, &info->xim_styles,
1524                 XNQueryICValuesList, &ic_values,
1525                 NULL);
1526
1527    if (ic_values)
1528      {
1529         int i;
1530
1531         for (i = 0; i < ic_values->count_values; i++)
1532           {
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],
1537                          XNCursor))
1538                info->supports_cursor = EINA_TRUE;
1539           }
1540 #if 0
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]);
1547 #endif
1548         XFree(ic_values);
1549      }
1550 }
1551
1552 static void
1553 xim_destroy_callback(XIM xim __UNUSED__,
1554                      XPointer client_data,
1555                      XPointer call_data __UNUSED__)
1556 {
1557    XIM_Im_Info *info = (XIM_Im_Info *)client_data;
1558    info->im = NULL;
1559
1560    reinitialize_all_ics(info);
1561    xim_info_try_im(info);
1562
1563    return;
1564 }
1565
1566 #endif  /* ENABLE_XIM */