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