Modified to send the destory message to ISF panel
[platform/core/uifw/e-mod-tizen-wl-textinput.git] / src / e_mod_main.c
1 #define E_COMP_WL
2 #include "e.h"
3 #include "e_mod_main.h"
4 #include "e_mod_input_method_manager.h"
5 #include <text-server-protocol.h>
6 #include <input-method-server-protocol.h>
7 #include <vconf.h>
8 #include <vconf-keys.h>
9 #include <Eeze.h>
10 #include <dlog.h>
11 #include <stdlib.h>
12 #include <system_info.h>
13
14 #ifdef LOG_TAG
15 #undef LOG_TAG
16 #endif
17 #define LOG_TAG "WL_TEXTINPUT"
18
19 #define WTI_WARNING(resource, code, msg)     (_e_text_input_log_show((resource), (code), (msg), __func__))
20
21 tizen_profile_t _get_tizen_profile()
22 {
23    static tizen_profile_t profile = TIZEN_PROFILE_UNKNOWN;
24    if (__builtin_expect(profile != TIZEN_PROFILE_UNKNOWN, 1))
25      return profile;
26
27    char *profileName;
28    system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
29    switch (*profileName)
30      {
31       case 'm':
32       case 'M':
33          profile = TIZEN_PROFILE_MOBILE;
34          break;
35       case 'w':
36       case 'W':
37          profile = TIZEN_PROFILE_WEARABLE;
38          break;
39       case 't':
40       case 'T':
41          profile = TIZEN_PROFILE_TV;
42          break;
43       case 'i':
44       case 'I':
45          profile = TIZEN_PROFILE_IVI;
46          break;
47       default: // common or unknown ==> ALL ARE COMMON.
48          profile = TIZEN_PROFILE_COMMON;
49      }
50    free(profileName);
51
52    return profile;
53 }
54
55 static Eina_Bool _e_text_input_method_context_cb_client_resize(void *data EINA_UNUSED, int type, void *event);
56 static void set_soft_keyboard_mode();
57
58 typedef struct _E_Text_Input E_Text_Input;
59 typedef struct _E_Text_Input_Mgr E_Text_Input_Mgr;
60 typedef struct _E_Input_Method E_Input_Method;
61 typedef struct _E_Input_Method_Context E_Input_Method_Context;
62 typedef struct _E_Mod_Text_Input_Shutdown_Cb E_Mod_Text_Input_Shutdown_Cb;
63
64 struct _E_Text_Input
65 {
66    struct wl_resource *resource;
67
68    Eina_List *input_methods;
69    Eina_Bool input_panel_visible;
70    Eina_Bool input_panel_show_requested;
71    uint32_t id;
72 };
73
74 struct _E_Text_Input_Mgr
75 {
76    struct wl_global *global;
77    struct wl_resource *resource;
78
79    Eina_List *text_input_list;
80 };
81
82 struct _E_Input_Method
83 {
84    struct wl_global *global;
85    struct wl_resource *resource;
86
87    E_Text_Input *input;
88    E_Input_Method_Context *context;
89 };
90
91 static struct wl_resource *destroyed_resource = NULL;
92
93 struct _E_Input_Method_Context
94 {
95    struct wl_resource *resource;
96
97    E_Text_Input *input;
98    E_Input_Method *input_method;
99
100 #if ENABLE_GRAB_KEYBOARD
101    struct
102    {
103       struct wl_resource *resource;
104       Eina_List *handlers;
105       Eina_Bool grabbed;
106       struct xkb_keymap *keymap;
107       struct xkb_state *state;
108       xkb_mod_mask_t mod_depressed, mod_latched, mod_locked;
109       xkb_layout_index_t mod_group;
110       int mod_changed;
111    } kbd;
112 #endif
113 };
114
115 struct _E_Mod_Text_Input_Shutdown_Cb
116 {
117    void (*func)(void *data);
118    void *data;
119 };
120
121 /* This represents the overall input panel's state including the candidate area */
122 enum _E_Input_Panel_State
123 {
124     E_INPUT_PANEL_STATE_DID_HIDE,
125     E_INPUT_PANEL_STATE_WILL_HIDE,
126     E_INPUT_PANEL_STATE_DID_SHOW,
127     E_INPUT_PANEL_STATE_WILL_SHOW,
128 };
129
130 static E_Input_Method *g_input_method = NULL;
131 static E_Text_Input *g_text_input = NULL;
132 static struct wl_client *g_client = NULL;
133 static Eina_List *shutdown_list = NULL;
134 static Eina_Bool g_disable_show_panel = EINA_FALSE;
135 static Eeze_Udev_Watch *eeze_udev_watch_hander = NULL;
136 static Ecore_Event_Handler *ecore_key_down_handler = NULL;
137 static Eina_List *handlers = NULL;
138 static uint32_t g_text_input_count = 1;
139 static Ecore_Timer *g_timer_will_hide  = NULL;
140 static enum _E_Input_Panel_State g_input_panel_state = E_INPUT_PANEL_STATE_DID_HIDE;
141 static E_Client *client_surface_ec = NULL;
142 static E_Text_Input *g_show_text_input = NULL;
143 static struct wl_client *g_show_client = NULL;
144 static Eina_Bool g_updated_geometry = EINA_FALSE;
145 static Eina_Bool g_input_panel_enabled = EINA_TRUE;
146
147 /* The candidate's show state that was requested by the application or IME */
148 static Eina_Bool g_show_state_candidate = EINA_FALSE;
149
150 static Eina_List *hooks_ec = NULL;
151
152 const int WILL_HIDE_TIMER_INTERVAL = 1.0f;
153
154 #undef E_CLIENT_HOOK_APPEND
155 #define E_CLIENT_HOOK_APPEND(l, t, cb, d) \
156   do                                      \
157     {                                     \
158        E_Client_Hook *_h;                 \
159        _h = e_client_hook_add(t, cb, d);  \
160        assert(_h);                        \
161        l = eina_list_append(l, _h);       \
162     }                                     \
163   while (0)
164
165 static void _e_text_input_cb_input_panel_show(struct wl_client *client, struct wl_resource *resource);
166 static void _e_text_input_deactivate(E_Text_Input *text_input, E_Input_Method *input_method, Eina_Bool need_focus_in);
167 static Eina_Bool _e_text_input_method_create_context(struct wl_client *client, E_Input_Method *input_method, E_Text_Input *text_input, Eina_Bool need_focus_out);
168 static void send_hide_input_panel(E_Input_Method *input_method);
169
170 E_Client *
171 e_text_input_client_surface_get(void)
172 {
173    return client_surface_ec;
174 }
175
176 static void
177 _e_text_input_log_show(struct wl_resource *resource, uint32_t code, const char *msg, const char *warning_msg)
178 {
179    LOGE("%s() is failed. msg : %s\n", warning_msg, msg);
180 }
181
182 static void
183 _e_text_input_send_input_panel_geometry(struct wl_resource *resource, int x, int y, int w, int h)
184 {
185    int angle = 0;
186    char geometry[128];
187
188    if (client_surface_ec)
189      {
190         angle = client_surface_ec->e.state.rot.ang.next < 0 ?
191                 client_surface_ec->e.state.rot.ang.curr :
192                 client_surface_ec->e.state.rot.ang.next;
193
194         LOGI("curr : %d, next : %d, angle : %d\n", client_surface_ec->e.state.rot.ang.curr,
195            client_surface_ec->e.state.rot.ang.next, angle);
196      }
197
198    snprintf(geometry, sizeof(geometry), "%d,%d,%d,%d", x, y, w, h);
199
200    switch(angle)
201      {
202       case 90:
203       case 270:
204          vconf_set_str(VCONFKEY_ISF_IME_RECENT_LAND_GEOMETRY, geometry);
205          break;
206       default:
207          vconf_set_str(VCONFKEY_ISF_IME_RECENT_PORT_GEOMETRY, geometry);
208          break;
209      }
210
211    LOGI("angle : %d, x : %d, y : %d, w : %d, h : %d\n", angle, x, y, w, h);
212
213    wl_text_input_send_input_panel_geometry(resource, x, y, w, h);
214 }
215
216 static Eina_Bool
217 _will_hide_timer_handler(void *data)
218 {
219    INF("TIMED OUT while waiting for WILL_HIDE_ACK : %d", g_input_panel_state);
220    if (g_input_panel_state == E_INPUT_PANEL_STATE_WILL_HIDE)
221      {
222         e_input_panel_visibility_change(EINA_FALSE);
223         e_input_panel_transient_for_set(NULL);
224         g_input_panel_state = E_INPUT_PANEL_STATE_DID_HIDE;
225      }
226
227    if (g_timer_will_hide)
228      {
229         ecore_timer_del(g_timer_will_hide);
230         g_timer_will_hide = NULL;
231      }
232
233    return ECORE_CALLBACK_CANCEL;
234 }
235
236 static void
237 _input_panel_hide(struct wl_client *client, struct wl_resource *resource, Eina_Bool force_hide)
238 {
239    E_Text_Input *text_input = wl_resource_get_user_data(resource);
240    E_Input_Method *input_method = NULL;
241    Eina_Bool _context_created = EINA_FALSE;
242    E_Zone *zone = NULL;
243    double timeout;
244    int effect_run;
245
246    if (!text_input)
247      {
248         WTI_WARNING(resource,
249                     WL_DISPLAY_ERROR_INVALID_OBJECT,
250                     "No Text Input For Resource");
251         return;
252      }
253
254    text_input->input_panel_visible = EINA_FALSE;
255
256    if (text_input->resource)
257      {
258         wl_text_input_send_input_panel_geometry(text_input->resource, 0, 0, 0, 0);
259         wl_text_input_send_input_panel_state(text_input->resource, WL_TEXT_INPUT_INPUT_PANEL_STATE_HIDE);
260      }
261
262    if (force_hide)
263      {
264         e_input_panel_visibility_change(EINA_FALSE);
265         e_input_panel_transient_for_set(NULL);
266         g_input_panel_state = E_INPUT_PANEL_STATE_DID_HIDE;
267      }
268    else
269      {
270         g_input_panel_state = E_INPUT_PANEL_STATE_WILL_HIDE;
271         /* Temporarily sending private command, will need for a new wayland protocol */
272         if (text_input->resource)
273           wl_text_input_send_private_command(text_input->resource, 0, "CONFORMANT_RESET");
274
275         if (g_timer_will_hide)
276           {
277              ecore_timer_del(g_timer_will_hide);
278              g_timer_will_hide = NULL;
279           }
280
281         zone = e_zone_current_get();
282         effect_run = e_input_panel_is_effect_running();
283         if (zone && (zone->display_state == E_ZONE_DISPLAY_STATE_OFF))
284           timeout = 0.0f;
285         else if (effect_run)
286           timeout = 0.0f;
287         else
288           timeout = WILL_HIDE_TIMER_INTERVAL;
289         g_timer_will_hide = ecore_timer_add(timeout, _will_hide_timer_handler, NULL);
290      }
291
292    if (g_input_method && g_input_method->resource)
293      input_method = wl_resource_get_user_data(g_input_method->resource);
294
295    /*
296       If input_method->context is already deleted, create context struct again to send input_panel_hide event to Input Method(IME) correctly.
297       Because input_panel_hide event can be called after focus_out(deactivate) by application.
298       And Input Method(IME) should know the state of their own input_panel to manage their resource when the input_panel is hidden.
299     */
300    if (input_method &&
301        ((!input_method->context) || (!input_method->context->resource)))
302      _context_created = _e_text_input_method_create_context(client, input_method, text_input, EINA_FALSE);
303
304    send_hide_input_panel(input_method);
305
306    if (_context_created)
307      _e_text_input_deactivate(text_input, input_method, EINA_FALSE);
308
309    e_input_panel_wait_update_set(EINA_FALSE);
310
311    /* When the input panel suface is hidden, the candidate will hide too */
312    g_show_state_candidate = EINA_FALSE;
313 }
314
315 static void send_hide_input_panel(E_Input_Method *input_method)
316 {
317    if (input_method && input_method->resource && input_method->context && input_method->context->resource)
318      {
319         LOGI("Request to hide IME");
320         wl_input_method_send_hide_input_panel(input_method->resource, input_method->context->resource);
321      }
322 }
323
324 static void
325 _keyboard_mode_changed_cb(keynode_t *key, void* data)
326 {
327    bool val = vconf_keynode_get_bool(key);
328    LOGI("keyboard mode : %d\n", val);
329
330    if (val == false)
331      {
332         if (!g_disable_show_panel && g_text_input && g_text_input->resource && g_client && g_input_panel_state == E_INPUT_PANEL_STATE_DID_HIDE && g_text_input->input_panel_show_requested)
333           _e_text_input_cb_input_panel_show(g_client, g_text_input->resource);
334
335 #ifdef SUPPORT_CANDIDATE_ONEWINDOW
336         /* Switching to S/W keyboard mode, hide input panel since it could be displaying candidate only */
337         if (g_disable_show_panel && g_text_input && g_text_input->resource && g_client)
338           _input_panel_hide(g_client, g_text_input->resource, EINA_FALSE);
339 #endif
340         g_disable_show_panel = EINA_FALSE;
341      }
342    else
343      {
344 #ifdef SUPPORT_CANDIDATE_ONEWINDOW
345         /* Switching to H/W keyboard mode, hide input panel only if there is no candidate */
346         if (!g_show_state_candidate && g_text_input && g_text_input->resource && g_client)
347 #else
348         if (g_text_input && g_text_input->resource && g_client)
349 #endif
350           _input_panel_hide(g_client, g_text_input->resource, EINA_FALSE);
351
352         g_disable_show_panel = EINA_TRUE;
353      }
354 }
355
356
357 #if ENABLE_GRAB_KEYBOARD
358 static void
359 _e_text_input_method_context_keyboard_grab_keyboard_state_update(E_Input_Method_Context *context, uint32_t keycode, Eina_Bool pressed)
360 {
361    enum xkb_key_direction dir;
362
363    if (!context->kbd.state) return;
364
365    if (pressed) dir = XKB_KEY_DOWN;
366    else dir = XKB_KEY_UP;
367
368    context->kbd.mod_changed =
369      xkb_state_update_key(context->kbd.state, keycode + 8, dir);
370 }
371
372 static void
373 _e_text_input_method_context_keyboard_grab_keyboard_modifiers_update(E_Input_Method_Context *context, struct wl_resource *keyboard)
374 {
375    uint32_t serial;
376
377    if (!context->input) return;
378    if (!context->kbd.state) return;
379
380    context->kbd.mod_depressed =
381      xkb_state_serialize_mods(context->kbd.state, XKB_STATE_DEPRESSED);
382    context->kbd.mod_latched =
383      xkb_state_serialize_mods(context->kbd.state, XKB_STATE_MODS_LATCHED);
384    context->kbd.mod_locked =
385      xkb_state_serialize_mods(context->kbd.state, XKB_STATE_MODS_LOCKED);
386    context->kbd.mod_group =
387      xkb_state_serialize_layout(context->kbd.state, XKB_STATE_LAYOUT_EFFECTIVE);
388
389    serial = wl_display_next_serial(e_comp_wl->wl.disp);
390    wl_keyboard_send_modifiers(keyboard, serial,
391                               context->kbd.mod_depressed,
392                               context->kbd.mod_latched,
393                               context->kbd.mod_locked,
394                               context->kbd.mod_group);
395 }
396
397 static void
398 _e_text_input_method_context_key_send(E_Input_Method_Context *context, unsigned int keycode, unsigned int timestamp, enum wl_keyboard_key_state state)
399 {
400    uint32_t serial, nk;
401
402    if (!context->input) return;
403    nk = keycode - 8;
404
405    /* update modifier state */
406    _e_text_input_method_context_keyboard_grab_keyboard_state_update(context, nk, state == WL_KEYBOARD_KEY_STATE_PRESSED);
407
408    serial = wl_display_next_serial(e_comp_wl->wl.disp);
409
410    wl_keyboard_send_key(context->kbd.resource, serial, timestamp, nk, state);
411    if (context->kbd.mod_changed)
412      {
413         _e_text_input_method_context_keyboard_grab_keyboard_modifiers_update(context, context->kbd.resource);
414         context->kbd.mod_changed = 0;
415      }
416 }
417
418 static Eina_Bool
419 _e_text_input_method_context_ecore_cb_key_down(void *data, int ev_type EINA_UNUSED, Ecore_Event_Key *ev)
420 {
421    E_Input_Method_Context *context = data;
422
423    _e_text_input_method_context_key_send(context, ev->keycode, ev->timestamp,
424                                          WL_KEYBOARD_KEY_STATE_PRESSED);
425
426    return ECORE_CALLBACK_RENEW;
427 }
428
429 static Eina_Bool
430 _e_text_input_method_context_ecore_cb_key_up(void *data, int ev_type EINA_UNUSED, Ecore_Event_Key *ev)
431 {
432    E_Input_Method_Context *context = data;
433
434    _e_text_input_method_context_key_send(context, ev->keycode, ev->timestamp,
435                                          WL_KEYBOARD_KEY_STATE_RELEASED);
436
437    return ECORE_CALLBACK_RENEW;
438 }
439
440 static void
441 _e_text_input_method_context_grab_set(E_Input_Method_Context *context, Eina_Bool set)
442 {
443    if (set == context->kbd.grabbed)
444      return;
445
446    if (!context->input)
447      return;
448
449    context->kbd.grabbed = set;
450
451    if (set)
452      {
453         if (context->kbd.keymap) xkb_map_unref(context->kbd.keymap);
454         if (context->kbd.state) xkb_state_unref(context->kbd.state);
455         context->kbd.keymap = xkb_map_ref(e_comp_wl->xkb.keymap);
456         context->kbd.state = xkb_state_new(e_comp_wl->xkb.keymap);
457         E_LIST_HANDLER_APPEND(context->kbd.handlers, ECORE_EVENT_KEY_DOWN,
458                               _e_text_input_method_context_ecore_cb_key_down,
459                               context);
460         E_LIST_HANDLER_APPEND(context->kbd.handlers, ECORE_EVENT_KEY_UP,
461                               _e_text_input_method_context_ecore_cb_key_up,
462                               context);
463
464         e_comp_grab_input(0, 1);
465      }
466    else
467      {
468         E_FREE_LIST(context->kbd.handlers, ecore_event_handler_del);
469
470         e_comp_ungrab_input(0, 1);
471
472         if (context->kbd.keymap)
473           {
474              xkb_map_unref(context->kbd.keymap);
475              context->kbd.keymap = NULL;
476           }
477
478         if (context->kbd.state)
479           {
480              xkb_state_unref(context->kbd.state);
481              context->kbd.state = NULL;
482           }
483      }
484 }
485 #endif
486
487 static void
488 _e_mod_text_input_shutdown_cb_add(void (*func)(void *data), void *data)
489 {
490    E_Mod_Text_Input_Shutdown_Cb *cb;
491
492    if (!(cb = E_NEW(E_Mod_Text_Input_Shutdown_Cb, 1)))
493      {
494         ERR("Could not allocate space for Text Input Shutdown Callback");
495         return;
496      }
497
498    cb->func = func;
499    cb->data = data;
500
501    shutdown_list = eina_list_append(shutdown_list, cb);
502 }
503
504 static void
505 _e_text_input_method_context_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
506 {
507    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
508
509    LOGD("resource(%p), context(%p), context->input(%p), context->input_method(%p)", resource, context, context->input, context->input_method);
510
511    wl_resource_destroy(resource);
512 }
513
514 static void
515 _e_text_input_method_context_cb_string_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *text)
516 {
517    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
518
519    if (!context)
520      {
521         WTI_WARNING(resource,
522                     WL_DISPLAY_ERROR_INVALID_OBJECT,
523                     "No Input Method Context For Resource");
524         return;
525      }
526
527    if ((context->input) && (context->input->resource))
528      wl_text_input_send_commit_string(context->input->resource,
529                                       serial, text);
530 }
531
532 static void
533 _e_text_input_method_context_cb_preedit_string(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *text, const char *commit)
534 {
535    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
536
537    if (!context)
538      {
539         WTI_WARNING(resource,
540                     WL_DISPLAY_ERROR_INVALID_OBJECT,
541                     "No Input Method Context For Resource");
542         return;
543      }
544
545    if ((context->input) && (context->input->resource))
546      wl_text_input_send_preedit_string(context->input->resource,
547                                        serial, text, commit);
548 }
549
550 static void
551 _e_text_input_method_context_cb_recapture_string(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, int32_t index, uint32_t length, const char *preedit, const char *preedit_commit, const char *commit)
552 {
553    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
554
555    if (!context)
556      {
557         WTI_WARNING(resource,
558                     WL_DISPLAY_ERROR_INVALID_OBJECT,
559                     "No Input Method Context For Resource");
560         return;
561      }
562
563    if ((context->input) && (context->input->resource))
564      wl_text_input_send_recapture_string(context->input->resource,
565                                          serial, index, length, preedit, preedit_commit, commit);
566 }
567
568 static void
569 _e_text_input_method_context_cb_preedit_styling(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t index, uint32_t length, uint32_t style)
570 {
571    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
572
573    if (!context)
574      {
575         WTI_WARNING(resource,
576                     WL_DISPLAY_ERROR_INVALID_OBJECT,
577                     "No Input Method Context For Resource");
578         return;
579      }
580
581    if ((context->input) && (context->input->resource))
582      wl_text_input_send_preedit_styling(context->input->resource,
583                                         index, length, style);
584 }
585
586 static void
587 _e_text_input_method_context_cb_preedit_cursor(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t cursor)
588 {
589    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
590
591    if (!context)
592      {
593         WTI_WARNING(resource,
594                     WL_DISPLAY_ERROR_INVALID_OBJECT,
595                     "No Input Method Context For Resource");
596         return;
597      }
598
599    if ((context->input) && (context->input->resource))
600      wl_text_input_send_preedit_cursor(context->input->resource,
601                                        cursor);
602 }
603
604 static void
605 _e_text_input_method_context_cb_surrounding_text_delete(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t index, uint32_t length)
606 {
607    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
608
609    if (!context)
610      {
611         WTI_WARNING(resource,
612                     WL_DISPLAY_ERROR_INVALID_OBJECT,
613                     "No Input Method Context For Resource");
614         return;
615      }
616
617    if ((context->input) && (context->input->resource))
618      wl_text_input_send_delete_surrounding_text(context->input->resource,
619                                                 index, length);
620 }
621
622 static void
623 _e_text_input_method_context_cb_cursor_position(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t index, int32_t anchor)
624 {
625    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
626
627    if (!context)
628      {
629         WTI_WARNING(resource,
630                     WL_DISPLAY_ERROR_INVALID_OBJECT,
631                     "No Input Method Context For Resource");
632         return;
633      }
634
635    if ((context->input) && (context->input->resource))
636      wl_text_input_send_cursor_position(context->input->resource,
637                                         index, anchor);
638 }
639
640 static void
641 _e_text_input_method_context_cb_modifiers_map(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_array *map)
642 {
643    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
644
645    if (!context)
646      {
647         WTI_WARNING(resource,
648                     WL_DISPLAY_ERROR_INVALID_OBJECT,
649                     "No Input Method Context For Resource");
650         return;
651      }
652
653    if ((context->input) && (context->input->resource))
654      wl_text_input_send_modifiers_map(context->input->resource, map);
655 }
656
657 static void
658 _e_keyevent_free(void *data EINA_UNUSED, void *ev)
659 {
660    Ecore_Event_Key *e = ev;
661
662    if (e->keyname)
663      eina_stringshare_del(e->keyname);
664
665    if (e->key)
666      eina_stringshare_del(e->key);
667
668    if (e->compose)
669      eina_stringshare_del(e->compose);
670
671    if (e->string)
672      eina_stringshare_del(e->string);
673
674    E_FREE(e);
675 }
676
677 static void
678 feed_key_event(const char *keyname, const char *key, const char *string, int keycode, int state)
679 {
680    Ecore_Event_Key *e = E_NEW(Ecore_Event_Key, 1);
681    if (!e) return;
682
683    e->keyname = (char *)eina_stringshare_add(keyname);
684    e->key = (char *)eina_stringshare_add(key);
685    e->string = (char *)eina_stringshare_add(string);
686    e->compose = (char *)eina_stringshare_add(e->string);
687
688    e->timestamp = 0; /* For distinguishing S/W keyboard event */
689    e->same_screen = 1;
690    e->keycode = keycode;
691
692    ecore_event_add(state ? ECORE_EVENT_KEY_DOWN : ECORE_EVENT_KEY_UP, e, _e_keyevent_free, NULL);
693 }
694
695 static void
696 _e_text_input_method_context_cb_keysym(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers)
697 {
698    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
699
700    if (!context)
701      {
702         WTI_WARNING(resource,
703                     WL_DISPLAY_ERROR_INVALID_OBJECT,
704                     "No Input Method Context For Resource");
705         return;
706      }
707
708    if ((context->input) && (context->input->resource))
709      {
710         wl_text_input_send_keysym(context->input->resource,
711                                   serial, time, sym, state, modifiers);
712      }
713    else
714      {
715         char string[32], key[32], keyname[32];
716
717         memset(keyname, 0, sizeof(keyname));
718         xkb_keysym_get_name(sym, keyname, sizeof(keyname));
719         if (keyname[0] == '\0')
720           snprintf(keyname, sizeof(keyname), "Keysym-%u", sym);
721
722         if (strcmp(keyname, "BackSpace") == 0)
723           {
724              /* backspace key should be supported in the multibutton entry of elementary
725                 even though it losts focus */
726              memset(key, 0, sizeof(key));
727              xkb_keysym_get_name(sym, key, sizeof(key));
728
729              memset(string, 0, sizeof(string));
730              xkb_keysym_to_utf8(sym, string, 32);
731
732              if (state)
733                {
734                   /* Backspace keycode (22) */
735                   feed_key_event(keyname, key, string, 22, 1); /* key down */
736                   feed_key_event(keyname, key, string, 22, 0); /* key up */
737                }
738           }
739      }
740 }
741
742 #if ENABLE_GRAB_KEYBOARD
743 static void
744 _e_text_input_method_context_keyboard_grab_cb_resource_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
745 {
746    wl_resource_destroy(resource);
747 }
748
749 static const struct wl_keyboard_interface _e_keyboard_grab_interface =
750 {
751    _e_text_input_method_context_keyboard_grab_cb_resource_destroy
752 };
753
754 static void
755 _e_text_input_method_context_keyboard_grab_cb_keyboard_unbind(struct wl_resource *resource)
756 {
757    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
758
759    if (!context)
760      {
761         WTI_WARNING(resource,
762                     WL_DISPLAY_ERROR_INVALID_OBJECT,
763                     "No Input Method Context For Resource");
764         return;
765      }
766
767    _e_text_input_method_context_grab_set(context, EINA_FALSE);
768
769    context->kbd.resource = NULL;
770 }
771 #endif
772
773 static void
774 _e_text_input_method_context_cb_keyboard_grab(struct wl_client *client, struct wl_resource *resource, uint32_t id)
775 {
776    DBG("Input Method Context - grab keyboard %d", wl_resource_get_id(resource));
777 #if ENABLE_GRAB_KEYBOARD
778    E_Input_Method_Context *context  = wl_resource_get_user_data(resource);
779    struct wl_resource *keyboard = NULL;
780
781    if (!context)
782      {
783         WTI_WARNING(resource,
784                     WL_DISPLAY_ERROR_INVALID_OBJECT,
785                     "No Input Method Context For Resource");
786         return;
787      }
788
789    keyboard = wl_resource_create(client, &wl_keyboard_interface, 1, id);
790    if (!keyboard)
791      {
792         wl_client_post_no_memory(client);
793         return;
794      }
795
796    wl_resource_set_implementation(keyboard, &_e_keyboard_grab_interface, context, _e_text_input_method_context_keyboard_grab_cb_keyboard_unbind);
797
798    /* send current keymap */
799    wl_keyboard_send_keymap(keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
800                            e_comp_wl->xkb.fd, e_comp_wl->xkb.size);
801
802    context->kbd.resource = keyboard;
803
804    _e_text_input_method_context_grab_set(context, EINA_TRUE);
805 #endif
806 }
807
808 static void
809 _e_text_input_method_context_cb_key(struct wl_client *client, struct wl_resource *resource, uint32_t serial, uint32_t time, uint32_t key, uint32_t state_w)
810 {
811    DBG("Input Method Context - key %d", wl_resource_get_id(resource));
812
813    (void)client;
814    (void)resource;
815    (void)serial;
816    (void)time;
817    (void)key;
818    (void)state_w;
819 }
820
821 static void
822 _e_text_input_method_context_cb_modifiers(struct wl_client *client, struct wl_resource *resource, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
823 {
824    DBG("Input Method Context - modifiers %d", wl_resource_get_id(resource));
825
826    (void)client;
827    (void)resource;
828    (void)serial;
829    (void)mods_depressed;
830    (void)mods_latched;
831    (void)mods_locked;
832    (void)group;
833 }
834
835 static void
836 _e_text_input_method_context_cb_language(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *language)
837 {
838    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
839
840    if (!context)
841      {
842         WTI_WARNING(resource,
843                     WL_DISPLAY_ERROR_INVALID_OBJECT,
844                     "No Input Method Context For Resource");
845         return;
846      }
847
848    if ((context->input) && (context->input->resource))
849      wl_text_input_send_language(context->input->resource,
850                                  serial, language);
851 }
852
853 static void
854 _e_text_input_method_context_cb_text_direction(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, uint32_t direction)
855 {
856    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
857
858    if (!context)
859      {
860         WTI_WARNING(resource,
861                     WL_DISPLAY_ERROR_INVALID_OBJECT,
862                     "No Input Method Context For Resource");
863         return;
864      }
865
866    if ((context->input) && (context->input->resource))
867      wl_text_input_send_text_direction(context->input->resource,
868                                        serial, direction);
869 }
870
871 static void
872 _e_text_input_method_context_cb_selection_region(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, int32_t start, int32_t end)
873 {
874    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
875
876    if (!context)
877      {
878         WTI_WARNING(resource,
879                     WL_DISPLAY_ERROR_INVALID_OBJECT,
880                     "No Input Method Context For Resource");
881         return;
882      }
883
884    if ((context->input) && (context->input->resource))
885      wl_text_input_send_selection_region(context->input->resource,
886                                          serial, start, end);
887 }
888
889 static void
890 _e_text_input_method_context_cb_private_command(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *command)
891 {
892    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
893
894    if (!context)
895      {
896         WTI_WARNING(resource,
897                     WL_DISPLAY_ERROR_INVALID_OBJECT,
898                     "No Input Method Context For Resource");
899         return;
900      }
901
902    if ((context->input) && (context->input->resource))
903      wl_text_input_send_private_command(context->input->resource,
904                                         serial, command);
905 }
906
907 static void
908 _e_text_input_method_context_cb_commit_content(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *content, const char *description, const char *mime_types)
909 {
910    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
911
912    if (!context)
913      {
914         WTI_WARNING(resource,
915                     WL_DISPLAY_ERROR_INVALID_OBJECT,
916                     "No Input Method Context For Resource");
917         return;
918      }
919
920    if ((context->input) && (context->input->resource))
921      wl_text_input_send_commit_content(context->input->resource,
922                                        serial, content, description, mime_types);
923 }
924
925 static void
926 _e_text_input_method_context_cb_input_panel_event(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, uint32_t event_type, uint32_t value)
927 {
928    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
929
930    if (!context)
931      {
932         WTI_WARNING(resource,
933                     WL_DISPLAY_ERROR_INVALID_OBJECT,
934                     "No Input Method Context For Resource");
935         return;
936      }
937
938    if ((context->input) && (context->input->resource))
939      wl_text_input_send_input_panel_event(context->input->resource,
940                                           serial, event_type, value);
941 }
942
943 static void
944 _e_text_input_method_context_cb_update_candidate_state(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t state)
945 {
946     E_Input_Method_Context *context = wl_resource_get_user_data(resource);
947
948     if (!context)
949       {
950          WTI_WARNING(resource,
951                      WL_DISPLAY_ERROR_INVALID_OBJECT,
952                      "No Input Method Context For Resource");
953          return;
954       }
955
956     LOGI("Candidate State : %d", state);
957     Eina_Bool prev_show_state = g_show_state_candidate;
958     g_show_state_candidate = state;
959     if (g_input_panel_state == E_INPUT_PANEL_STATE_DID_HIDE)
960       prev_show_state = EINA_FALSE;
961
962     if (!state)
963       {
964          /* If the candidate state has been changed to OFF when panel is not in show state, */
965          if (!g_show_state_candidate && prev_show_state && g_disable_show_panel && g_client && g_text_input)
966             _input_panel_hide(g_client, g_text_input->resource, EINA_FALSE);
967       }
968     else
969       {
970          /* If the candidate state has been changed to ON when panel is not in show state */
971          if (g_show_state_candidate && !prev_show_state && g_disable_show_panel && g_client && g_text_input)
972             {
973                _e_text_input_cb_input_panel_show(g_client, g_text_input->resource);
974                int x = 0, y = 0, w = 0, h = 0;
975                if (e_input_panel_client_geometry_get(NULL, &x, &y, &w, &h) && !(w <= 1 || h <= 1))
976                  _e_text_input_send_input_panel_geometry(g_text_input->resource, x, y, w, h);
977             }
978       }
979 }
980
981 static void
982 _e_text_input_method_context_cb_input_panel_data_update(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *data, uint32_t length)
983 {
984    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
985
986    if (!context)
987      {
988         WTI_WARNING(resource,
989                     WL_DISPLAY_ERROR_INVALID_OBJECT,
990                     "No Input Method Context For Resource");
991         return;
992      }
993
994    if ((context->input) && (context->input->resource))
995      wl_text_input_send_input_panel_data(context->input->resource,
996                                          serial, data, length);
997 }
998
999 static void
1000 _e_text_input_method_context_cb_hide_input_panel(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial)
1001 {
1002    E_Text_Input *text_input = g_text_input;
1003    E_Input_Method *input_method = NULL;
1004
1005    if (!text_input)
1006      {
1007         WTI_WARNING(resource,
1008                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1009                     "No Text Input For Resource");
1010         return;
1011      }
1012
1013    text_input->input_panel_visible = EINA_FALSE;
1014
1015    if (g_text_input && g_text_input->resource && g_client)
1016      _input_panel_hide(g_client, g_text_input->resource, EINA_FALSE);
1017
1018    if (g_input_method && g_input_method->resource)
1019      input_method = wl_resource_get_user_data(g_input_method->resource);
1020
1021    send_hide_input_panel(input_method);
1022 }
1023
1024 static void
1025 _e_text_input_method_context_cb_get_selection_text(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t fd)
1026 {
1027    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
1028
1029    if (!context)
1030      {
1031         WTI_WARNING(resource,
1032                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1033                     "No Input Method Context For Resource");
1034         close (fd);
1035         return;
1036      }
1037
1038    if ((context->input) && (context->input->resource))
1039      wl_text_input_send_get_selection_text(context->input->resource, fd);
1040
1041    close (fd);
1042 }
1043
1044 static void
1045 _e_text_input_method_context_cb_get_surrounding_text(struct wl_client *client EINA_UNUSED, struct wl_resource *resource,
1046                                                      uint32_t maxlen_before, uint32_t maxlen_after, int32_t fd)
1047 {
1048    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
1049
1050    if (!context)
1051      {
1052         WTI_WARNING(resource,
1053                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1054                     "No Input Method Context For Resource");
1055         close (fd);
1056         return;
1057      }
1058
1059    if ((context->input) && (context->input->resource))
1060      wl_text_input_send_get_surrounding_text(context->input->resource, maxlen_before, maxlen_after, fd);
1061
1062    close (fd);
1063 }
1064
1065 static void
1066 _e_text_input_method_context_cb_filter_key_event_done(struct wl_client *client EINA_UNUSED, struct wl_resource *resource,
1067                                                       uint32_t serial, uint32_t state)
1068 {
1069     E_Input_Method_Context *context = wl_resource_get_user_data(resource);
1070
1071     if (!context)
1072       {
1073          WTI_WARNING(resource,
1074                      WL_DISPLAY_ERROR_INVALID_OBJECT,
1075                      "No Input Method Context For Resource");
1076          return;
1077       }
1078
1079     if ((context->input) && (context->input->resource))
1080       wl_text_input_send_filter_key_event_done(context->input->resource,
1081                                           serial, state);
1082 }
1083
1084 static void
1085 _e_text_input_method_context_cb_update_ise_geometry(struct wl_client *client EINA_UNUSED, struct wl_resource *resource,
1086                                                       uint32_t serial, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
1087 {
1088     E_Input_Method_Context *context = wl_resource_get_user_data(resource);
1089
1090     if (!context)
1091       {
1092          WTI_WARNING(resource,
1093                      WL_DISPLAY_ERROR_INVALID_OBJECT,
1094                      "No Input Method Context For Resource");
1095          return;
1096       }
1097
1098     if ((context->input) && (context->input->resource))
1099       {
1100          _e_text_input_send_input_panel_geometry(context->input->resource, x, y, width, height);
1101          g_updated_geometry = EINA_TRUE;
1102       }
1103 }
1104
1105 static void
1106 _e_text_input_method_context_cb_reshow_input_panel(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
1107 {
1108     e_input_panel_transient_for_set(client_surface_ec);
1109     e_input_panel_wait_update_set(EINA_TRUE);
1110 }
1111
1112 static const struct wl_input_method_context_interface _e_text_input_method_context_implementation = {
1113      _e_text_input_method_context_cb_destroy,
1114      _e_text_input_method_context_cb_string_commit,
1115      _e_text_input_method_context_cb_preedit_string,
1116      _e_text_input_method_context_cb_preedit_styling,
1117      _e_text_input_method_context_cb_preedit_cursor,
1118      _e_text_input_method_context_cb_surrounding_text_delete,
1119      _e_text_input_method_context_cb_cursor_position,
1120      _e_text_input_method_context_cb_modifiers_map,
1121      _e_text_input_method_context_cb_keysym,
1122      _e_text_input_method_context_cb_keyboard_grab,
1123      _e_text_input_method_context_cb_key,
1124      _e_text_input_method_context_cb_modifiers,
1125      _e_text_input_method_context_cb_language,
1126      _e_text_input_method_context_cb_text_direction,
1127      _e_text_input_method_context_cb_selection_region,
1128      _e_text_input_method_context_cb_private_command,
1129      _e_text_input_method_context_cb_input_panel_data_update,
1130      _e_text_input_method_context_cb_hide_input_panel,
1131      _e_text_input_method_context_cb_get_selection_text,
1132      _e_text_input_method_context_cb_get_surrounding_text,
1133      _e_text_input_method_context_cb_filter_key_event_done,
1134      _e_text_input_method_context_cb_update_ise_geometry,
1135      _e_text_input_method_context_cb_recapture_string,
1136      _e_text_input_method_context_cb_input_panel_event,
1137      _e_text_input_method_context_cb_commit_content,
1138      _e_text_input_method_context_cb_update_candidate_state,
1139      _e_text_input_method_context_cb_reshow_input_panel,
1140 };
1141
1142 static void
1143 _e_text_input_method_context_cb_resource_destroy(struct wl_resource *resource)
1144 {
1145    E_Input_Method_Context *context = wl_resource_get_user_data(resource);
1146
1147    if (!context)
1148      {
1149         WTI_WARNING(resource,
1150                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1151                     "No Input Method Context For Resource");
1152         return;
1153      }
1154
1155 #if ENABLE_GRAB_KEYBOARD
1156    if (context->kbd.resource)
1157      {
1158         wl_resource_destroy(context->kbd.resource);
1159         context->kbd.resource = NULL;
1160      }
1161 #endif
1162
1163    LOGI("resource(%p), context(%p)", resource, context);
1164
1165    if ((context->input_method) &&
1166        (context->input_method->context == context))
1167      context->input_method->context = NULL;
1168
1169    free(context);
1170 }
1171
1172 static Eina_Bool is_number_key(const char *str)
1173  {
1174     if (!str) return EINA_FALSE;
1175
1176     int result = atoi(str);
1177
1178     if (result == 0)
1179       {
1180          if (!strcmp(str, "0"))
1181            return EINA_TRUE;
1182          else
1183            return EINA_FALSE;
1184       }
1185     else
1186       return EINA_TRUE;
1187 }
1188
1189 static Eina_Bool
1190 _e_mod_ecore_key_down_cb(void *data, int type, void *event)
1191 {
1192    Ecore_Event_Key *ev = (Ecore_Event_Key *)event;
1193    if (ev->event_flags & ECORE_EVENT_FLAG_CANCEL)
1194      {
1195         SECURE_LOGI("%s key is cancelled.", ev->key);
1196         return ECORE_CALLBACK_PASS_ON;
1197      }
1198
1199    if (g_disable_show_panel == EINA_TRUE)
1200      return ECORE_CALLBACK_PASS_ON;
1201
1202    /* process remote controller key exceptionally */
1203    if (((!strcmp(ev->key, "Down") ||
1204          !strcmp(ev->key, "KP_Down") ||
1205          !strcmp(ev->key, "Up") ||
1206          !strcmp(ev->key, "KP_Up") ||
1207          !strcmp(ev->key, "Right") ||
1208          !strcmp(ev->key, "KP_Right") ||
1209          !strcmp(ev->key, "Left") ||
1210          !strcmp(ev->key, "KP_Left")) && !ev->string) ||
1211        !strcmp(ev->key, "Return") ||
1212        !strcmp(ev->key, "Pause") ||
1213        !strcmp(ev->key, "NoSymbol") ||
1214        !strncmp(ev->key, "XF86", 4) ||
1215        !strncmp(ev->key, "Cancel", 5) ||
1216        (is_number_key(ev->string) && _TV))
1217      return ECORE_CALLBACK_PASS_ON;
1218
1219    SECURE_LOGI("Hide IME (key : %s)", ev->key);
1220
1221    if (g_text_input && g_text_input->resource && g_client)
1222      _input_panel_hide(g_client, g_text_input->resource, EINA_FALSE);
1223
1224    g_disable_show_panel = EINA_TRUE;
1225
1226    return ECORE_CALLBACK_PASS_ON;
1227 }
1228
1229 static void
1230 _e_text_input_deactivate(E_Text_Input *text_input, E_Input_Method *input_method, Eina_Bool need_focus_in)
1231 {
1232    if (text_input == g_text_input)
1233      {
1234         g_text_input = NULL;
1235         g_client = NULL;
1236      }
1237
1238    if (input_method->input == text_input)
1239      {
1240         if ((input_method->context) && (input_method->resource))
1241           {
1242 #if ENABLE_GRAB_KEYBOARD
1243              _e_text_input_method_context_grab_set(input_method->context,
1244                                                    EINA_FALSE);
1245 #endif
1246              if (input_method->resource == destroyed_resource)
1247                {
1248                   LOGI("deactivate skipped : %p %p", input_method->resource,
1249                        input_method->context->resource);
1250                }
1251              else
1252                {
1253                   /* TODO: finish the grab of keyboard. */
1254                   wl_input_method_send_deactivate(input_method->resource,
1255                                                   input_method->context->resource,
1256                                                   need_focus_in);
1257                   LOGI("wm_map TEXTINPUT deactivate : %p %p", input_method->resource,
1258                        input_method->context->resource);
1259                }
1260           }
1261
1262         if (ecore_key_down_handler)
1263           {
1264              ecore_event_handler_del(ecore_key_down_handler);
1265              ecore_key_down_handler = NULL;
1266           }
1267
1268         LOGI("Resetting input_method->input : %p, text_input : %p, %p %p",
1269              input_method->input, text_input,
1270              input_method->resource,
1271              (input_method->context ? input_method->context->resource : NULL));
1272         input_method->input = NULL;
1273         if (input_method->context) input_method->context->input = NULL;
1274         input_method->context = NULL;
1275
1276         text_input->input_panel_show_requested = EINA_FALSE;
1277         text_input->input_methods = eina_list_remove(text_input->input_methods, input_method);
1278
1279         if (text_input->resource)
1280           wl_text_input_send_leave(text_input->resource);
1281
1282         if (_TV || _WEARABLE)
1283           g_disable_show_panel = EINA_FALSE;
1284      }
1285 }
1286
1287 static void
1288 _e_text_input_cb_activate(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, struct wl_resource *surface)
1289 {
1290    E_Text_Input *text_input = NULL;
1291    E_Input_Method *input_method = NULL;
1292    E_Text_Input *old = NULL;
1293    E_Input_Method_Context *context = NULL;
1294    E_Client *ec = NULL;
1295
1296    EINA_SAFETY_ON_NULL_GOTO(resource, err);
1297    EINA_SAFETY_ON_NULL_GOTO(seat, err);
1298    EINA_SAFETY_ON_NULL_GOTO(g_input_method, err);
1299    EINA_SAFETY_ON_NULL_GOTO(g_input_method->resource, err);
1300
1301    /* Store application window's E_Client* value for setting transient_for information later */
1302    ec = wl_resource_get_user_data(surface);
1303    EINA_SAFETY_ON_NULL_GOTO(ec, err);
1304    EINA_SAFETY_ON_TRUE_GOTO(e_object_is_del(E_OBJECT(ec)), err);
1305    client_surface_ec = ec;
1306
1307    text_input = wl_resource_get_user_data(resource);
1308    g_text_input = text_input;
1309    g_client = client;
1310
1311    /* FIXME: should get input_method object from seat. */
1312    input_method = wl_resource_get_user_data(g_input_method->resource);
1313    EINA_SAFETY_ON_NULL_GOTO(input_method, err);
1314
1315    old = input_method->input;
1316
1317    LOGI("old : %p, text_input : %p, %d", old, text_input, g_input_panel_state);
1318    if (old == text_input)
1319      return;
1320
1321    if (old)
1322      _e_text_input_deactivate(old, input_method, EINA_TRUE);
1323
1324    input_method->input = text_input;
1325    text_input->input_methods = eina_list_append(text_input->input_methods, input_method);
1326
1327    if (input_method->resource)
1328      {
1329         if (!(context = E_NEW(E_Input_Method_Context, 1)))
1330           {
1331              wl_client_post_no_memory(client);
1332              ERR("Could not allocate space for Input_Method_Context");
1333              return;
1334           }
1335
1336         if (!ecore_key_down_handler)
1337           ecore_key_down_handler = ecore_event_handler_prepend(ECORE_EVENT_KEY_DOWN,
1338                                                            _e_mod_ecore_key_down_cb,
1339                                                            NULL);
1340
1341         context->resource =
1342            wl_resource_create(wl_resource_get_client(input_method->resource),
1343                               &wl_input_method_context_interface, 1, 0);
1344
1345         if (context->resource)
1346           wl_resource_set_implementation(context->resource,
1347                                          &_e_text_input_method_context_implementation,
1348                                          context, _e_text_input_method_context_cb_resource_destroy);
1349
1350         context->input = text_input;
1351         context->input_method = input_method;
1352         input_method->context = context;
1353
1354         if (context->resource)
1355           {
1356              wl_input_method_send_activate(input_method->resource, context->resource, text_input->id, EINA_TRUE);
1357              LOGI("wm_map TEXTINPUT activate : %p %p", input_method->resource,
1358                   context->resource);
1359
1360              destroyed_resource = NULL;
1361           }
1362         else
1363           WRN("Failed to send activate due to no resource in context");
1364      }
1365    else
1366      WRN("no inputmethod resource");
1367
1368    if (_TV || _WEARABLE)
1369      set_soft_keyboard_mode();
1370
1371    if (text_input->resource)
1372      wl_text_input_send_enter(text_input->resource, surface);
1373
1374    return;
1375
1376 err:
1377    if (resource)
1378      WTI_WARNING(resource,
1379                  WL_DISPLAY_ERROR_INVALID_OBJECT,
1380                  "No Text Input For Resource");
1381
1382    if (seat)
1383      WTI_WARNING(seat,
1384                  WL_DISPLAY_ERROR_INVALID_OBJECT,
1385                  "No Comp Data For Seat");
1386 }
1387
1388 static void
1389 _e_text_input_cb_deactivate(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat)
1390 {
1391    LOGI("");
1392    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1393    E_Input_Method *input_method = NULL;
1394
1395    if (!text_input)
1396      {
1397         WTI_WARNING(resource,
1398                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1399                     "No Text Input For Resource");
1400         return;
1401      }
1402
1403    if (text_input == g_text_input)
1404      {
1405         g_text_input = NULL;
1406         g_client = NULL;
1407      }
1408
1409    /* FIXME: should get input_method object from seat. */
1410    if (g_input_method && g_input_method->resource)
1411      input_method = wl_resource_get_user_data(g_input_method->resource);
1412
1413    if (!input_method)
1414      {
1415         WTI_WARNING(seat,
1416                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1417                     "No Input Method For Seat");
1418         return;
1419      }
1420
1421    _e_text_input_deactivate(text_input, input_method, EINA_TRUE);
1422 }
1423
1424 static Eina_Bool
1425 _e_text_input_method_create_context(struct wl_client *client, E_Input_Method *input_method, E_Text_Input *text_input, Eina_Bool need_focus_out)
1426 {
1427    E_Input_Method_Context *context = NULL;
1428
1429    EINA_SAFETY_ON_NULL_RETURN_VAL(input_method, EINA_FALSE);
1430    EINA_SAFETY_ON_NULL_RETURN_VAL(input_method->resource, EINA_FALSE);
1431    EINA_SAFETY_ON_NULL_RETURN_VAL(text_input, EINA_FALSE);
1432
1433    g_text_input = text_input;
1434    g_client = client;
1435    input_method->input = text_input;
1436    text_input->input_methods = eina_list_append(text_input->input_methods, input_method);
1437
1438    if (!(context = E_NEW(E_Input_Method_Context, 1)))
1439      {
1440         wl_client_post_no_memory(client);
1441         ERR("Could not allocate space for Input_Method_Context");
1442         return EINA_FALSE;
1443      }
1444
1445    context->resource =
1446       wl_resource_create(wl_resource_get_client(input_method->resource),
1447                          &wl_input_method_context_interface, 1, 0);
1448
1449    if (context->resource)
1450      wl_resource_set_implementation(context->resource,
1451                                     &_e_text_input_method_context_implementation,
1452                                     context, _e_text_input_method_context_cb_resource_destroy);
1453
1454    context->input = text_input;
1455    context->input_method = input_method;
1456    input_method->context = context;
1457
1458    wl_input_method_send_activate(input_method->resource, context->resource, text_input->id, need_focus_out);
1459
1460    LOGI("wm_map TEXTINPUT activate : input_method->resource(%p) context->resource(%p)",
1461         input_method->resource, context->resource);
1462
1463    destroyed_resource = NULL;
1464
1465    return EINA_TRUE;
1466 }
1467
1468 static void
1469 _e_text_input_cb_input_panel_show(struct wl_client *client, struct wl_resource *resource)
1470 {
1471    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1472    E_Input_Method *input_method = NULL;
1473
1474    LOGI("text_input : %p\n", text_input);
1475
1476    if (!text_input)
1477      {
1478         WTI_WARNING(resource,
1479                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1480                     "No Text Input For Resource");
1481         return;
1482      }
1483
1484    text_input->input_panel_show_requested = EINA_TRUE;
1485
1486 #ifndef SUPPORT_CANDIDATE_ONEWINDOW
1487    if (g_disable_show_panel == EINA_TRUE)
1488      return;
1489 #endif
1490
1491    if (g_input_method && g_input_method->resource)
1492      input_method = wl_resource_get_user_data(g_input_method->resource);
1493
1494    /* If input_method->context doesn't exist, create context struct to send input_panel_show event to Input Method(IME) correctly.
1495     * Because input_panel_show event can be called before focus_in(activate) by application.
1496     * And Input Method(IME) should know the state of their own input_panel to manage their resource when the input_panel is shown. */
1497    if (input_method && (!input_method->context || !input_method->context->resource))
1498      _e_text_input_method_create_context(client, input_method, text_input, EINA_TRUE);
1499
1500 #ifdef SUPPORT_CANDIDATE_ONEWINDOW
1501    if (g_disable_show_panel == EINA_TRUE)
1502      {
1503         if (g_show_state_candidate == EINA_TRUE)
1504           {
1505              g_input_panel_state = E_INPUT_PANEL_STATE_DID_SHOW;
1506              g_show_client = client;
1507              e_input_panel_visibility_change(EINA_TRUE);
1508              e_input_panel_transient_for_set(client_surface_ec);
1509           }
1510        return;
1511      }
1512 #endif
1513
1514    if (input_method)
1515      {
1516         if (input_method->resource && input_method->context && input_method->context->resource)
1517           {
1518              /* DO NOT show input panel surface until we get message "show complete" from input method,
1519               * in order to give a change to update UI */
1520              LOGI("IM::SHOW::WAIT_FOR_READY\n");
1521
1522              g_show_client = client;
1523              int angle = 0;
1524              if (client_surface_ec) angle = client_surface_ec->e.state.rot.ang.curr;
1525              wl_input_method_send_show_input_panel(input_method->resource, input_method->context->resource, angle);
1526
1527              /* we need to force update in order to release buffer
1528               * if we do not, client can't update
1529               * because they may in manual render state by frame callback mechanism,
1530               * and also don't have released buffer */
1531              e_input_panel_wait_update_set(EINA_TRUE);
1532           }
1533         else
1534           {
1535              LOGW("Failed to send show input panel. inputmethod : %p, input_method->resource : %p, input_method->context : %p", input_method, input_method->resource, input_method->context);
1536              if (input_method->context)
1537                LOGW("Failed to send show input panel. input_method->context->resource : %p", input_method->context->resource);
1538           }
1539      }
1540    else
1541      {
1542         LOGW("No input method");
1543      }
1544
1545    /* If the input panel state was WILL_HIDE, it means that the conformant area information needs to be restored */
1546    if (g_input_panel_state == E_INPUT_PANEL_STATE_WILL_HIDE)
1547      {
1548         if (text_input->resource)
1549           wl_text_input_send_private_command(text_input->resource, 0, "CONFORMANT_RESTORE");
1550      }
1551
1552    text_input->input_panel_visible = EINA_TRUE;
1553    g_input_panel_state = E_INPUT_PANEL_STATE_WILL_SHOW;
1554    g_show_text_input = text_input;
1555
1556    g_updated_geometry = EINA_FALSE;
1557
1558    e_input_panel_transient_for_set(client_surface_ec);
1559 }
1560
1561 static void
1562 _e_text_input_cb_input_panel_hide(struct wl_client *client, struct wl_resource *resource)
1563 {
1564    if (g_show_client == client) {
1565       _input_panel_hide(client, resource, EINA_FALSE);
1566       g_show_text_input = NULL;
1567       g_show_client = NULL;
1568    }
1569 }
1570
1571 static void
1572 _e_text_input_cb_reset(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
1573 {
1574    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1575    E_Input_Method *input_method = NULL;
1576    Eina_List *l = NULL;
1577
1578    if (!text_input)
1579      {
1580         WTI_WARNING(resource,
1581                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1582                     "No Text Input For Resource");
1583         return;
1584      }
1585
1586    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1587      {
1588         if (!input_method || !input_method->context) continue;
1589         if (input_method->context->resource)
1590           wl_input_method_context_send_reset(input_method->context->resource);
1591      }
1592 }
1593
1594 static void
1595 _e_text_input_cb_content_type_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t hint, uint32_t purpose)
1596 {
1597    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1598    E_Input_Method *input_method = NULL;
1599    Eina_List *l = NULL;
1600
1601    if (!text_input)
1602      {
1603         WTI_WARNING(resource,
1604                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1605                     "No Text Input For Resource");
1606         return;
1607      }
1608
1609    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1610      {
1611         if (!input_method || !input_method->context) continue;
1612
1613         if (input_method->context->resource)
1614           wl_input_method_context_send_content_type(input_method->context->resource,
1615                                                     hint, purpose);
1616      }
1617 }
1618
1619 static void
1620 _e_text_input_cb_cursor_rectangle_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
1621 {
1622    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1623
1624    if (!text_input)
1625      {
1626         WTI_WARNING(resource,
1627                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1628                     "No Text Input For Resource");
1629         return;
1630      }
1631
1632    /* TODO: issue event update input_panel */
1633 }
1634
1635 static void
1636 _e_text_input_cb_preferred_language_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *language)
1637 {
1638    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1639    E_Input_Method *input_method = NULL;
1640    Eina_List *l = NULL;
1641
1642    if (!text_input)
1643      {
1644         WTI_WARNING(resource,
1645                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1646                     "No Text Input For Resource");
1647         return;
1648      }
1649
1650    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1651      {
1652         if (!input_method || !input_method->context) continue;
1653
1654         if (input_method->context->resource)
1655           wl_input_method_context_send_preferred_language(input_method->context->resource,
1656                                                           language);
1657      }
1658 }
1659
1660 static void
1661 _e_text_input_cb_state_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial)
1662 {
1663    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1664    E_Input_Method *input_method = NULL;
1665    Eina_List *l = NULL;
1666
1667    if (!text_input)
1668      {
1669         WTI_WARNING(resource,
1670                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1671                     "No Text Input For Resource");
1672         return;
1673      }
1674
1675    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1676      {
1677         if (!input_method || !input_method->context) continue;
1678
1679         if (input_method->context->resource)
1680           wl_input_method_context_send_commit_state(input_method->context->resource, serial);
1681      }
1682 }
1683
1684 static void
1685 _e_text_input_cb_action_invoke(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t button, uint32_t index)
1686 {
1687    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1688    E_Input_Method *input_method = NULL;
1689    Eina_List *l = NULL;
1690
1691    if (!text_input)
1692      {
1693         WTI_WARNING(resource,
1694                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1695                     "No Text Input For Resource");
1696         return;
1697      }
1698
1699    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1700      {
1701         if (!input_method || !input_method->context) continue;
1702
1703         if (input_method->context->resource)
1704           wl_input_method_context_send_invoke_action(input_method->context->resource,
1705                                                      button, index);
1706      }
1707 }
1708
1709 static void
1710 _e_text_input_cb_return_key_type_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t return_key_type)
1711 {
1712    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1713    E_Input_Method *input_method = NULL;
1714    Eina_List *l = NULL;
1715
1716    if (!text_input)
1717      {
1718         WTI_WARNING(resource,
1719                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1720                     "No Text Input For Resource");
1721         return;
1722      }
1723
1724    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1725      {
1726         if (!input_method || !input_method->context) continue;
1727
1728         if (input_method->context->resource)
1729           wl_input_method_context_send_return_key_type(input_method->context->resource,
1730                                                        return_key_type);
1731      }
1732 }
1733
1734 static void
1735 _e_text_input_cb_return_key_disabled_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t disabled)
1736 {
1737    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1738    E_Input_Method *input_method = NULL;
1739    Eina_List *l = NULL;
1740
1741    if (!text_input)
1742      {
1743         WTI_WARNING(resource,
1744                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1745                     "No Text Input For Resource");
1746         return;
1747      }
1748
1749    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1750      {
1751         if (!input_method || !input_method->context) continue;
1752
1753         if (input_method->context->resource)
1754           wl_input_method_context_send_return_key_disabled(input_method->context->resource,
1755                                                            disabled);
1756      }
1757 }
1758
1759 static void
1760 _e_text_input_cb_input_panel_data_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *data, uint32_t length)
1761 {
1762    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1763    E_Input_Method *input_method = NULL;
1764    Eina_List *l = NULL;
1765
1766    if (!text_input)
1767      {
1768         WTI_WARNING(resource,
1769                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1770                     "No Text Input For Resource");
1771         return;
1772      }
1773
1774    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1775      {
1776         if (!input_method || !input_method->context) continue;
1777
1778         if (input_method->context->resource)
1779           wl_input_method_context_send_input_panel_data(input_method->context->resource,
1780                                                         data, length);
1781      }
1782
1783    /* Temporarily receiving WILL_HIDE_ACK via input_panel_data, will need for a new wayland protocol */
1784    const char *szWillHideAck = "WILL_HIDE_ACK";
1785    if (strncmp(data, szWillHideAck, strlen(szWillHideAck)) == 0)
1786      {
1787         if (g_timer_will_hide)
1788           {
1789              ecore_timer_del(g_timer_will_hide);
1790              g_timer_will_hide = NULL;
1791           }
1792         INF("WILL_HIDE_ACK_RECVED, %d", g_input_panel_state);
1793         if (g_input_panel_state == E_INPUT_PANEL_STATE_WILL_HIDE)
1794           {
1795              e_input_panel_visibility_change(EINA_FALSE);
1796              e_input_panel_transient_for_set(NULL);
1797              g_input_panel_state = E_INPUT_PANEL_STATE_DID_HIDE;
1798           }
1799      }
1800 }
1801
1802 static void
1803 _e_text_input_cb_bidi_direction_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t bidi_direction)
1804 {
1805    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1806    E_Input_Method *input_method = NULL;
1807    Eina_List *l = NULL;
1808
1809    if (!text_input)
1810      {
1811         WTI_WARNING(resource,
1812                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1813                     "No Text Input For Resource");
1814         return;
1815      }
1816
1817    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1818      {
1819         if (!input_method || !input_method->context) continue;
1820
1821         if (input_method->context->resource)
1822           wl_input_method_context_send_bidi_direction(input_method->context->resource,
1823                                                        bidi_direction);
1824      }
1825 }
1826
1827 static void
1828 _e_text_input_cb_cursor_position_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource,  uint32_t cursor_position)
1829 {
1830    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1831    E_Input_Method *input_method = NULL;
1832    Eina_List *l = NULL;
1833
1834    if (!text_input)
1835      {
1836         WTI_WARNING(resource,
1837                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1838                     "No Text Input For Resource");
1839         return;
1840      }
1841
1842    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1843      {
1844         if (!input_method || !input_method->context) continue;
1845
1846         if (input_method->context->resource)
1847           wl_input_method_context_send_cursor_position(input_method->context->resource, cursor_position);
1848      }
1849 }
1850
1851 static void
1852 _e_text_input_cb_process_input_device_event(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t type, const char *data, uint32_t length)
1853 {
1854    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1855    E_Input_Method *input_method = NULL;
1856    Eina_List *l = NULL;
1857
1858    if (!text_input)
1859      {
1860         WTI_WARNING(resource,
1861                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1862                     "No Text Input For Resource");
1863         return;
1864      }
1865
1866    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1867      {
1868         if (!input_method || !input_method->context) continue;
1869
1870         if (input_method->context->resource)
1871           wl_input_method_context_send_process_input_device_event(input_method->context->resource,
1872                                                                   type, data, length);
1873      }
1874 }
1875
1876 static void
1877 _e_text_input_cb_filter_key_event(struct wl_client *client EINA_UNUSED, struct wl_resource *resource,
1878                                   uint32_t serial, uint32_t time, const char *keyname, uint32_t state,
1879                                   uint32_t modifiers, const char *dev_name, uint32_t dev_class,
1880                                   uint32_t dev_subclass, uint32_t keycode)
1881
1882 {
1883   E_Text_Input *text_input = wl_resource_get_user_data(resource);
1884   E_Input_Method *input_method = NULL;
1885
1886   if (!text_input)
1887     {
1888        WTI_WARNING(resource,
1889                    WL_DISPLAY_ERROR_INVALID_OBJECT,
1890                    "No Text Input For Resource");
1891        return;
1892     }
1893
1894    /* FIXME: should get input_method object from seat. */
1895    if (g_input_method && g_input_method->resource)
1896      input_method = wl_resource_get_user_data(g_input_method->resource);
1897
1898    if (input_method && input_method->context && input_method->context->resource)
1899      {
1900         wl_input_method_context_send_filter_key_event(input_method->context->resource,
1901                                                       serial, time, keyname, state, modifiers,
1902                                                       dev_name, dev_class, dev_subclass, keycode);
1903      }
1904    else
1905      {
1906         if (text_input->resource)
1907           wl_text_input_send_filter_key_event_done(text_input->resource, serial, false);
1908
1909         WTI_WARNING(resource,
1910                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1911                     "No Input Method");
1912      }
1913
1914 }
1915
1916 static void
1917 _e_text_input_cb_get_hide_permission(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
1918 {
1919    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1920    uint32_t permission = 1;
1921    E_Client *focused_ec = NULL;
1922
1923    if (!text_input)
1924      {
1925         WTI_WARNING(resource,
1926                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1927                     "No Text Input For Resource");
1928         return;
1929      }
1930
1931    focused_ec = e_client_focused_get();
1932    if (focused_ec)
1933      {
1934         if (focused_ec != client_surface_ec)
1935           {
1936              E_Window_Type focus_win_type = focused_ec->netwm.type;
1937              LOGI("Window ID : 0x%08x, Name : %s, type : %d\n", (unsigned int)e_client_util_win_get(focused_ec), (char *)e_client_util_name_get(focused_ec), focus_win_type);
1938
1939              if (focus_win_type == E_WINDOW_TYPE_NOTIFICATION ||
1940                  focus_win_type == E_WINDOW_TYPE_POPUP_MENU)
1941                permission = 0;
1942           }
1943      }
1944    else
1945      {
1946         LOGI("Can't get focus window\n");
1947      }
1948
1949    if (text_input->resource)
1950      wl_text_input_send_hide_permission(text_input->resource, permission);
1951 }
1952
1953 static void
1954 _e_text_input_cb_set_capital_mode(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t mode)
1955 {
1956    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1957    E_Input_Method *input_method = NULL;
1958    Eina_List *l = NULL;
1959
1960    if (!text_input)
1961      {
1962         WTI_WARNING(resource,
1963                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1964                     "No Text Input For Resource");
1965         return;
1966      }
1967
1968    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1969      {
1970         if (!input_method || !input_method->context) continue;
1971         if (input_method->context->resource)
1972           wl_input_method_context_send_capital_mode(input_method->context->resource, mode);
1973      }
1974 }
1975
1976 static void
1977 _e_text_input_cb_prediction_hint_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *prediction_hint)
1978 {
1979    E_Text_Input *text_input = wl_resource_get_user_data(resource);
1980    E_Input_Method *input_method = NULL;
1981    Eina_List *l = NULL;
1982
1983    if (!text_input)
1984      {
1985         WTI_WARNING(resource,
1986                     WL_DISPLAY_ERROR_INVALID_OBJECT,
1987                     "No Text Input For Resource");
1988         return;
1989      }
1990
1991    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
1992      {
1993         if (!input_method || !input_method->context) continue;
1994
1995         if (input_method->context->resource)
1996           wl_input_method_context_send_prediction_hint(input_method->context->resource, prediction_hint);
1997      }
1998 }
1999
2000 static void
2001 _e_text_input_cb_prediction_hint_data_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *key, const char *value)
2002 {
2003    E_Text_Input *text_input = wl_resource_get_user_data(resource);
2004    E_Input_Method *input_method = NULL;
2005    Eina_List *l = NULL;
2006
2007    if (!text_input)
2008      {
2009         WTI_WARNING(resource,
2010                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2011                     "No Text Input For Resource");
2012         return;
2013      }
2014
2015    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
2016      {
2017         if (!input_method || !input_method->context) continue;
2018
2019         if (input_method->context->resource)
2020           wl_input_method_context_send_prediction_hint_data(input_method->context->resource, key, value);
2021      }
2022 }
2023
2024 static void
2025 _e_text_input_cb_input_panel_enabled_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t enabled)
2026 {
2027    E_Text_Input *text_input = wl_resource_get_user_data(resource);
2028
2029    if (!text_input)
2030      {
2031         WTI_WARNING(resource,
2032                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2033                     "No Text Input For Resource");
2034         return;
2035      }
2036
2037    g_input_panel_enabled = enabled;
2038 }
2039
2040 static void
2041 _e_text_input_cb_mime_type_accept_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *mime_type)
2042 {
2043    E_Text_Input *text_input = wl_resource_get_user_data(resource);
2044    E_Input_Method *input_method = NULL;
2045    Eina_List *l = NULL;
2046
2047    if (!text_input)
2048      {
2049         WTI_WARNING(resource,
2050                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2051                     "No Text Input For Resource");
2052         return;
2053      }
2054
2055    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
2056      {
2057         if (!input_method || !input_method->context) continue;
2058
2059         if (input_method->context->resource)
2060           wl_input_method_context_send_mime_type(input_method->context->resource, mime_type);
2061      }
2062 }
2063
2064 static void
2065 _e_text_input_cb_input_panel_position_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t x, uint32_t y)
2066 {
2067    E_Text_Input *text_input = wl_resource_get_user_data(resource);
2068
2069    if (!text_input)
2070      {
2071         WTI_WARNING(resource,
2072                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2073                     "No Text Input For Resource");
2074         return;
2075      }
2076    e_input_panel_floating_position_set(x, y);
2077 }
2078
2079 static void
2080 _e_text_input_cb_finalize_content(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *text, uint32_t cursor_position)
2081 {
2082    E_Text_Input *text_input = wl_resource_get_user_data(resource);
2083    E_Input_Method *input_method = NULL;
2084    Eina_List *l = NULL;
2085
2086    if (!text_input)
2087      {
2088         WTI_WARNING(resource,
2089                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2090                     "No Text Input For Resource");
2091         return;
2092      }
2093
2094    EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
2095      {
2096         if (!input_method || !input_method->context) continue;
2097
2098         if (input_method->context->resource)
2099           wl_input_method_context_send_finalized_content(input_method->context->resource, text, cursor_position);
2100      }
2101 }
2102
2103 static void
2104 _e_text_input_cb_resource_destroy(struct wl_resource *resource)
2105 {
2106    E_Text_Input *text_input = wl_resource_get_user_data(resource);
2107    E_Input_Method *input_method = NULL;
2108
2109    if (!text_input)
2110      {
2111         WTI_WARNING(resource,
2112                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2113                     "No Text Input For Resource");
2114         return;
2115      }
2116
2117    LOGI("resource : %p", resource);
2118
2119    if (g_show_text_input == text_input)
2120      {
2121         if (text_input->input_panel_visible)
2122           {
2123               _input_panel_hide(g_client, resource, EINA_TRUE);
2124           }
2125
2126         g_show_text_input = NULL;
2127      }
2128
2129    if (g_text_input == text_input)
2130      {
2131         g_text_input = NULL;
2132         g_client = NULL;
2133      }
2134
2135    EINA_LIST_FREE(text_input->input_methods, input_method)
2136      {
2137         if (input_method)
2138           _e_text_input_deactivate(text_input, input_method, EINA_TRUE);
2139      }
2140
2141    free(text_input);
2142 }
2143
2144 static void
2145 _e_text_input_cb_destroy(struct wl_client *client, struct wl_resource *resource)
2146 {
2147    E_Text_Input *text_input = wl_resource_get_user_data(resource);
2148    E_Input_Method *input_method = NULL;
2149
2150    if (!text_input)
2151      {
2152         WTI_WARNING(resource,
2153                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2154                     "No Text Input For Resource");
2155         return;
2156      }
2157
2158    if (g_input_method && g_input_method->resource)
2159      input_method = wl_resource_get_user_data(g_input_method->resource);
2160
2161    if (!input_method)
2162      {
2163         WTI_WARNING(resource,
2164                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2165                     "No Input Method For Seat");
2166         return;
2167      }
2168
2169    LOGI("text_input(%p), focus(%d), input_method(%p), input_method->resource(%p), context(%p), context->resource(%p), resource(%p)",
2170         text_input, (text_input == g_text_input), input_method, input_method->resource, input_method->context,
2171         (input_method->context ? input_method->context->resource : NULL), resource);
2172
2173    if (input_method->input)
2174      _e_text_input_deactivate(text_input, input_method, EINA_FALSE);
2175
2176    if ((!input_method->context) || (!input_method->context->resource))
2177      _e_text_input_method_create_context(client, input_method, text_input, EINA_FALSE);
2178
2179    if (text_input == g_text_input &&
2180        input_method->resource && input_method->context && input_method->context->resource)
2181      {
2182         wl_input_method_send_destroy(input_method->resource, input_method->context->resource);
2183         LOGI("wm_map TEXTINPUT destroy : input_method->resource(%p) input_method->context->resource(%p)",
2184              input_method->resource, input_method->context->resource);
2185
2186         destroyed_resource = input_method->resource;
2187      }
2188 }
2189
2190 static const struct wl_text_input_interface _e_text_input_implementation = {
2191      _e_text_input_cb_destroy,
2192      _e_text_input_cb_activate,
2193      _e_text_input_cb_deactivate,
2194      _e_text_input_cb_input_panel_show,
2195      _e_text_input_cb_input_panel_hide,
2196      _e_text_input_cb_reset,
2197      _e_text_input_cb_content_type_set,
2198      _e_text_input_cb_cursor_rectangle_set,
2199      _e_text_input_cb_preferred_language_set,
2200      _e_text_input_cb_state_commit,
2201      _e_text_input_cb_action_invoke,
2202      _e_text_input_cb_return_key_type_set,
2203      _e_text_input_cb_return_key_disabled_set,
2204      _e_text_input_cb_input_panel_data_set,
2205      _e_text_input_cb_bidi_direction_set,
2206      _e_text_input_cb_cursor_position_set,
2207      _e_text_input_cb_process_input_device_event,
2208      _e_text_input_cb_filter_key_event,
2209      _e_text_input_cb_get_hide_permission,
2210      _e_text_input_cb_set_capital_mode,
2211      _e_text_input_cb_prediction_hint_set,
2212      _e_text_input_cb_mime_type_accept_set,
2213      _e_text_input_cb_input_panel_position_set,
2214      _e_text_input_cb_finalize_content,
2215      _e_text_input_cb_prediction_hint_data_set,
2216      _e_text_input_cb_input_panel_enabled_set
2217 };
2218
2219 static void
2220 _e_text_input_manager_cb_text_input_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)
2221 {
2222    E_Text_Input_Mgr *text_input_mgr = wl_resource_get_user_data(resource);
2223    E_Text_Input *text_input = NULL;
2224
2225    if (!text_input_mgr)
2226      {
2227         WTI_WARNING(resource,
2228                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2229                     "No Text Input Manager For Resource");
2230         return;
2231      }
2232
2233    if (!(text_input = E_NEW(E_Text_Input, 1)))
2234      {
2235         wl_client_post_no_memory(client);
2236         ERR("Could not allocate space for Text_Input");
2237         return;
2238      }
2239
2240    text_input->resource =
2241       wl_resource_create(client, &wl_text_input_interface, 1, id);
2242
2243    if (!text_input->resource)
2244      {
2245         wl_client_post_no_memory(client);
2246         ERR("Could not create the resource for text_input");
2247         free(text_input);
2248         return;
2249      }
2250    text_input->id = g_text_input_count++;
2251
2252    wl_resource_set_implementation(text_input->resource,
2253                                   &_e_text_input_implementation,
2254                                   text_input, _e_text_input_cb_resource_destroy);
2255 }
2256
2257 static const struct wl_text_input_manager_interface _e_text_input_manager_implementation = {
2258      _e_text_input_manager_cb_text_input_create
2259 };
2260
2261 static void
2262 _e_text_cb_bind_text_input_manager(struct wl_client *client, void *data, uint32_t version EINA_UNUSED, uint32_t id)
2263 {
2264    E_Text_Input_Mgr *text_input_mgr = data;
2265
2266    text_input_mgr->resource =
2267       wl_resource_create(client,
2268                          &wl_text_input_manager_interface, 1, id);
2269
2270    if (text_input_mgr->resource)
2271      wl_resource_set_implementation(text_input_mgr->resource,
2272                                     &_e_text_input_manager_implementation,
2273                                     text_input_mgr, NULL);
2274 }
2275
2276 static void
2277 _e_text_input_method_cb_unbind(struct wl_resource *resource)
2278 {
2279    LOGI("");
2280    E_Input_Method *input_method = wl_resource_get_user_data(resource);
2281
2282    if (!input_method)
2283      {
2284         WTI_WARNING(resource,
2285                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2286                     "No Input Method For Resource");
2287         return;
2288      }
2289
2290    if (input_method->resource != resource) return;
2291
2292    if (input_method->input)
2293      _e_text_input_deactivate(input_method->input, input_method, EINA_TRUE);
2294
2295    input_method->resource = NULL;
2296    input_method->context = NULL;
2297
2298    if (vconf_set_bool(VCONFKEY_ISF_BIND, 0) != 0)
2299      LOGW("failed to set isf bind\n");
2300 }
2301
2302 static void
2303 _e_text_input_method_cb_bind(struct wl_client *client, void *data, uint32_t version EINA_UNUSED, uint32_t id)
2304 {
2305    LOGI("");
2306    E_Input_Method *input_method = data;
2307    struct wl_resource *resource = NULL;
2308
2309    if (!input_method) return;
2310
2311    if (input_method->resource)
2312      _e_text_input_method_cb_unbind(input_method->resource);
2313
2314    if (input_method->resource)
2315      {
2316         WTI_WARNING(input_method->resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
2317                     "input_method object already bound");
2318         return;
2319      }
2320
2321    resource = wl_resource_create(client, &wl_input_method_interface, 1, id);
2322    if (EINA_UNLIKELY(!resource))
2323      return;
2324
2325    input_method->resource = resource;
2326
2327    wl_resource_set_implementation(resource, NULL, input_method,
2328                                   _e_text_input_method_cb_unbind);
2329
2330    if (vconf_set_bool(VCONFKEY_ISF_BIND, 1) != 0)
2331      LOGW("failed to set isf bind\n");
2332 }
2333
2334 static void
2335 _e_text_input_method_destroy(void *data)
2336 {
2337    E_Input_Method *input_method = data;
2338
2339    if (!input_method)
2340      return;
2341
2342    if (input_method->global)
2343      {
2344         wl_global_destroy(input_method->global);
2345         input_method->global = NULL;
2346      }
2347
2348    free(input_method);
2349 }
2350
2351 static Eina_Bool
2352 _e_text_input_method_create(void)
2353 {
2354    if (!(g_input_method = E_NEW(E_Input_Method, 1)))
2355      {
2356         ERR("Could not allocate space for Input_Method");
2357         return EINA_FALSE;
2358      }
2359
2360    g_input_method->global =
2361       wl_global_create(e_comp_wl->wl.disp, &wl_input_method_interface, 1,
2362                        g_input_method, _e_text_input_method_cb_bind);
2363
2364    if (!g_input_method->global)
2365      {
2366         free(g_input_method);
2367         g_input_method = NULL;
2368         return EINA_FALSE;
2369      }
2370
2371    _e_mod_text_input_shutdown_cb_add(_e_text_input_method_destroy, g_input_method);
2372
2373    return EINA_TRUE;
2374 }
2375
2376 static void
2377 _e_text_input_manager_destroy(void *data)
2378 {
2379    E_Text_Input_Mgr *text_input_mgr = data;
2380    if (!text_input_mgr) return;
2381
2382    LOGI("input manager : %p", text_input_mgr);
2383
2384    if (text_input_mgr->global)
2385      {
2386         wl_global_destroy(text_input_mgr->global);
2387         text_input_mgr->global = NULL;
2388      }
2389    free(text_input_mgr);
2390 }
2391
2392 static Eina_Bool
2393 _e_text_input_manager_create(void)
2394 {
2395    E_Text_Input_Mgr *text_input_mgr;
2396
2397    if (!(text_input_mgr = E_NEW(E_Text_Input_Mgr, 1)))
2398      {
2399         ERR("Could not allocate space for Text_Input_Manager");
2400         return EINA_FALSE;
2401      }
2402
2403    text_input_mgr->global =
2404       wl_global_create(e_comp_wl->wl.disp,
2405                        &wl_text_input_manager_interface, 1,
2406                        text_input_mgr, _e_text_cb_bind_text_input_manager);
2407
2408    if (!text_input_mgr->global)
2409      {
2410         free(text_input_mgr);
2411         return EINA_FALSE;
2412      }
2413
2414    LOGI("input manager : %p", text_input_mgr);
2415
2416    _e_mod_text_input_shutdown_cb_add(_e_text_input_manager_destroy, text_input_mgr);
2417
2418    return EINA_TRUE;
2419 }
2420
2421 static void
2422 _e_mod_text_input_shutdown(void)
2423 {
2424    E_Mod_Text_Input_Shutdown_Cb *cb;
2425
2426    EINA_LIST_FREE(shutdown_list, cb)
2427      {
2428         if (cb)
2429           {
2430              cb->func(cb->data);
2431              free(cb);
2432           }
2433      }
2434 }
2435
2436 E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Wl_Text_Input" };
2437
2438 static void
2439 set_soft_keyboard_mode()
2440 {
2441    g_disable_show_panel = EINA_FALSE;
2442
2443    /* switch to S/W keyboard mode */
2444    int val = 0;
2445    if (vconf_get_bool(VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, &val) == 0 && val != 0)
2446      vconf_set_bool(VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, 0);
2447 }
2448
2449 static void
2450 _e_mod_eeze_udev_watch_cb(const char *text, Eeze_Udev_Event event, void *data, Eeze_Udev_Watch *watch)
2451 {
2452    if (event == EEZE_UDEV_EVENT_REMOVE)
2453      set_soft_keyboard_mode();
2454 }
2455
2456 static Eina_Bool
2457 e_client_rotation_is_progress(E_Client *ec)
2458 {
2459    if (!ec) return EINA_TRUE;
2460
2461    if (ec->e.state.rot.ang.next == -1)
2462      return EINA_FALSE;
2463    else
2464      return EINA_TRUE;
2465 }
2466
2467 static Eina_Bool
2468 _e_text_input_method_context_cb_client_resize(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
2469 {
2470    E_Event_Client *ev;
2471    E_Client *ec;
2472    Eina_Bool found;
2473
2474    ev = (E_Event_Client *)event;
2475    EINA_SAFETY_ON_NULL_RETURN_VAL(ev, ECORE_CALLBACK_PASS_ON);
2476
2477    ec = ev->ec;
2478    EINA_SAFETY_ON_NULL_RETURN_VAL(ec, ECORE_CALLBACK_PASS_ON);
2479
2480    found = e_input_panel_client_find(ec);
2481    if (!found) return ECORE_CALLBACK_PASS_ON;
2482    if ((ec->w < 1) && (ec->h < 1)) return ECORE_CALLBACK_PASS_ON;
2483
2484    e_text_input_update_input_panel_geometry(ec);
2485
2486    return ECORE_CALLBACK_PASS_ON;
2487 }
2488
2489 static void
2490 _pol_cb_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
2491 {
2492    if (EINA_UNLIKELY(!ec))
2493      return;
2494
2495    if (ec == client_surface_ec)
2496      {
2497         LOGI("transient_for_ec deleted, hiding input panel\n");
2498         e_input_panel_visibility_change(EINA_FALSE);
2499         e_input_panel_transient_for_set(NULL);
2500
2501         if(!e_input_panel_surface_destroy(ec))
2502           LOGE("fail to remove surface\n");
2503
2504         g_input_panel_state = E_INPUT_PANEL_STATE_DID_HIDE;
2505         if (g_timer_will_hide)
2506           {
2507              ecore_timer_del(g_timer_will_hide);
2508              g_timer_will_hide = NULL;
2509           }
2510         client_surface_ec = NULL;
2511         LOGI("TRANSIENT_FOR::Reset transient_for_ec to NULL\n");
2512      }
2513 }
2514
2515 void
2516 e_text_input_update_input_panel_state(Eina_Bool state)
2517 {
2518    if (!g_text_input || !g_text_input->resource) return;
2519
2520    E_Text_Input *text_input = wl_resource_get_user_data(g_text_input->resource);
2521
2522    if (!text_input)
2523      {
2524         WTI_WARNING(g_text_input->resource,
2525                     WL_DISPLAY_ERROR_INVALID_OBJECT,
2526                     "No Text Input For Resource");
2527         return;
2528      }
2529
2530    if (text_input->resource)
2531      {
2532         if (!g_updated_geometry)
2533           {
2534              int x = 0, y = 0, w = 0, h = 0;
2535              if (e_input_panel_client_geometry_get(NULL, &x, &y, &w, &h) && !(w <= 1 || h <= 1))
2536                _e_text_input_send_input_panel_geometry(text_input->resource, x, y, w, h);
2537              g_updated_geometry = EINA_TRUE;
2538           }
2539         uint32_t input_panel_state = WL_TEXT_INPUT_INPUT_PANEL_STATE_HIDE;
2540         if (state) input_panel_state = WL_TEXT_INPUT_INPUT_PANEL_STATE_SHOW;
2541         wl_text_input_send_input_panel_state(text_input->resource, input_panel_state);
2542      }
2543 }
2544
2545 void
2546 e_text_input_update_input_panel_geometry(E_Client *ec)
2547 {
2548    if (g_text_input && g_text_input->resource &&
2549        g_input_panel_state != E_INPUT_PANEL_STATE_WILL_HIDE && g_input_panel_state != E_INPUT_PANEL_STATE_DID_HIDE &&
2550        g_updated_geometry)
2551      {
2552         if (e_client_rotation_is_progress(ec))
2553           {
2554              LOGI("Rotation is not finished");
2555              return;
2556           }
2557
2558         /* The geometry of E_Client may not be valid when IME is shown.
2559            Assume E_Client has a valid geometry when this callback is called after IME has set the size.
2560          */
2561         int x = 0, y = 0, w = 0, h = 0;
2562         if (e_input_panel_client_geometry_get(NULL, &x, &y, &w, &h) && !(w <= 1 || h <= 1))
2563           {
2564              LOGI("x : %d, y : %d, w : %d, h : %d", x, y, w, h);
2565              _e_text_input_send_input_panel_geometry(g_text_input->resource, x, y, w, h);
2566           }
2567      }
2568 }
2569
2570 E_API void *
2571 e_modapi_init(E_Module *m)
2572 {
2573    if (!e_comp_wl) return NULL;
2574
2575    if (!wti_log_init())
2576      return NULL;
2577
2578    /* FIXME: create only one input method object per seat. */
2579    if (!_e_text_input_method_create())
2580      return NULL;
2581
2582    if (!e_input_panel_init())
2583      goto err;
2584
2585    if (!_e_text_input_manager_create())
2586      goto err;
2587
2588    if (!e_input_method_manager_create())
2589      goto err;
2590
2591    E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_RESIZE, _e_text_input_method_context_cb_client_resize, NULL);
2592
2593    if (vconf_notify_key_changed(VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, _keyboard_mode_changed_cb, NULL) != 0)
2594      LOGW ("Failed to register callback function for H/W keyboard input detection.");
2595
2596    eeze_udev_watch_hander = eeze_udev_watch_add(EEZE_UDEV_TYPE_KEYBOARD,
2597                                                 EEZE_UDEV_EVENT_REMOVE,
2598                                                 _e_mod_eeze_udev_watch_cb,
2599                                                 NULL);
2600    if (!eeze_udev_watch_hander)
2601      goto err;
2602
2603    E_CLIENT_HOOK_APPEND(hooks_ec, E_CLIENT_HOOK_DEL, _pol_cb_hook_client_del, NULL);
2604
2605    return m;
2606 err:
2607    _e_mod_text_input_shutdown();
2608    return NULL;
2609 }
2610
2611 E_API int
2612 e_modapi_shutdown(E_Module *m EINA_UNUSED)
2613 {
2614    E_FREE_LIST(handlers, ecore_event_handler_del);
2615    E_FREE_LIST(hooks_ec, e_client_hook_del);
2616
2617    if (g_timer_will_hide)
2618      {
2619         ecore_timer_del(g_timer_will_hide);
2620         g_timer_will_hide = NULL;
2621      }
2622
2623    vconf_ignore_key_changed(VCONFKEY_ISF_HW_KEYBOARD_INPUT_DETECTED, _keyboard_mode_changed_cb);
2624
2625    if (eeze_udev_watch_hander)
2626      {
2627         eeze_udev_watch_del(eeze_udev_watch_hander);
2628         eeze_udev_watch_hander = NULL;
2629      }
2630    _e_mod_text_input_shutdown();
2631
2632    e_input_panel_shutdown();
2633
2634    wti_log_shutdown();
2635
2636    return 1;
2637 }
2638
2639 E_API int
2640 e_modapi_save(E_Module *m EINA_UNUSED)
2641 {
2642    /* do nothing */
2643    return 1;
2644 }