update for beta release
[framework/uifw/e17.git] / src / modules / illume-keyboard / e_kbd_int.c
1 #include "e.h"
2 #include "e_kbd_buf.h"
3 #include "e_kbd_int.h"
4 #include "e_kbd_send.h"
5 #include "e_mod_config.h"
6
7 enum 
8 {
9    NORMAL = 0,
10    SHIFT = (1 << 0),
11    CAPSLOCK = (1 << 1),
12    CTRL = (1 << 2),
13    ALT = (1 << 3),
14    ALTGR = (1 << 4)
15 };
16
17 static Evas_Object *_theme_obj_new(Evas *e, const char *custom_dir, const char *group);
18
19 static void _e_kbd_int_layout_next(E_Kbd_Int *ki);
20 static void _e_kbd_int_zoomkey_down(E_Kbd_Int *ki);
21 static void _e_kbd_int_matches_update(void *data);
22 static void _e_kbd_int_dictlist_down(E_Kbd_Int *ki);
23 static void _e_kbd_int_matchlist_down(E_Kbd_Int *ki);
24 static Eina_Bool _e_kbd_int_cb_border_move(void *data, int type, void *event);
25
26
27 static const char *
28 _e_kbd_int_str_unquote(const char *str)
29 {
30    static char buf[256];
31    char *p;
32    
33    snprintf(buf, sizeof(buf), "%s", str + 1);
34    p = strrchr(buf, '"');
35    if (p) *p = 0;
36    return buf;
37 }
38
39 static E_Kbd_Int_Key *
40 _e_kbd_int_at_coord_get(E_Kbd_Int *ki, Evas_Coord x, Evas_Coord y)
41 {
42    Eina_List *l;
43    Evas_Coord dist;
44    E_Kbd_Int_Key *ky;  
45    E_Kbd_Int_Key *closest_ky = NULL;
46
47    EINA_LIST_FOREACH(ki->layout.keys, l, ky)
48      if ((x >= ky->x) && (y >= ky->y) &&
49          (x < (ky->x + ky->w)) && (y < (ky->y + ky->h)))
50        return ky;
51    dist = 0x7fffffff;
52    EINA_LIST_FOREACH(ki->layout.keys, l, ky)
53      {
54         Evas_Coord dx, dy;
55
56         dx = x - (ky->x + (ky->w / 2));
57         dy = y - (ky->y + (ky->h / 2));
58         dx = (dx * dx) + (dy * dy);
59         if (dx < dist)
60           {
61              dist = dx;
62              closest_ky = ky;
63           }
64      }
65    return closest_ky;
66 }
67
68 static E_Kbd_Int_Key_State *
69 _e_kbd_int_key_state_get(E_Kbd_Int *ki, E_Kbd_Int_Key *ky)
70 {
71    E_Kbd_Int_Key_State *found = NULL;
72    E_Kbd_Int_Key_State *st;
73    Eina_List *l;
74
75    EINA_LIST_FOREACH(ky->states, l, st)
76      {
77         if (st->state & ki->layout.state) return st;
78         if (!found && st->state == NORMAL) found = st;
79      }
80    return found;
81 }
82
83 static void
84 _e_kbd_int_layout_buf_update(E_Kbd_Int *ki)
85 {
86    E_Kbd_Int_Key *ky;
87    Eina_List *l, *l2;
88
89    e_kbd_buf_layout_clear(ki->kbuf);
90    e_kbd_buf_layout_size_set(ki->kbuf, ki->layout.w, ki->layout.h);
91    e_kbd_buf_layout_fuzz_set(ki->kbuf, ki->layout.fuzz);
92    EINA_LIST_FOREACH(ki->layout.keys, l, ky)
93      {
94         E_Kbd_Int_Key_State *st;
95         const char *out, *out_shift, *out_capslock, *out_altgr;
96
97         out = NULL;
98         out_shift = NULL;
99         out_capslock = NULL;
100         out_altgr = NULL;
101
102         EINA_LIST_FOREACH(ky->states, l2, st)
103           {
104              if (st->state == NORMAL)
105                out = st->out;
106              else if (st->state == SHIFT)
107                out_shift = st->out;
108              else if (st->state == CAPSLOCK)
109                out_capslock = st->out;
110              else if (st->state == ALTGR)
111                out_altgr = st->out;
112           }
113         if (out)
114           {
115              char *s1 = NULL, *s2 = NULL, *s3 = NULL;
116
117              if ((out) && (out[0] == '"')) 
118                s1 = strdup(_e_kbd_int_str_unquote(out));
119              if ((out_shift) && (out_shift[0] == '"')) 
120                s2 = strdup(_e_kbd_int_str_unquote(out_shift));
121              if ((out_altgr) && (out_altgr[0] == '"')) 
122                s2 = strdup(_e_kbd_int_str_unquote(out_altgr));
123              if ((out_capslock) && (out_capslock[0] == '"')) 
124                s3 = strdup(_e_kbd_int_str_unquote(out_capslock));
125              e_kbd_buf_layout_key_add(ki->kbuf, s1, s2, s3, 
126                                       ky->x, ky->y, ky->w, ky->h);
127              if (s1) free(s1);
128              if (s2) free(s2);
129              if (s3) free(s3);
130           }
131      }
132 }
133
134 static void
135 _e_kbd_int_layout_state_update(E_Kbd_Int *ki)
136 {
137    E_Kbd_Int_Key *ky;
138    Eina_List *l;
139
140    EINA_LIST_FOREACH(ki->layout.keys, l, ky)
141      {
142         E_Kbd_Int_Key_State *st;
143         int selected;
144
145         st = _e_kbd_int_key_state_get(ki, ky);
146         if (st)
147           {
148              if (st->label)
149                edje_object_part_text_set(ky->obj, "e.text.label", st->label);
150              else
151                edje_object_part_text_set(ky->obj, "e.text.label", "");
152              if (st->icon)
153                {
154                   char buf[PATH_MAX];
155                   char *p;
156
157                   snprintf(buf, sizeof(buf), "%s/%s", ki->layout.directory, st->icon);
158                   p = strrchr(st->icon, '.');
159                   if (!strcmp(p, ".edj"))
160                     e_icon_file_edje_set(ky->icon_obj, buf, "icon");
161                   else
162                     e_icon_file_set(ky->icon_obj, buf);
163                }
164              else
165                e_icon_file_set(ky->icon_obj, NULL);
166           }
167         selected = 0;
168         if ((ki->layout.state & SHIFT) && (ky->is_shift)) selected = 1;
169         if ((ki->layout.state & CTRL) && (ky->is_ctrl)) selected = 1;
170         if ((ki->layout.state & ALT) && (ky->is_alt)) selected = 1;
171         if ((ki->layout.state & ALTGR) && (ky->is_altgr)) selected = 1;
172         if ((ki->layout.state & CAPSLOCK) && (ky->is_capslock)) selected = 1;
173         if ((ki->layout.state & (SHIFT | CAPSLOCK)) && (ky->is_multi_shift)) 
174           selected = 1;
175         if (selected)
176           {
177              if (!ky->selected)
178                {
179                   edje_object_signal_emit(ky->obj, "e,state,selected", "e");
180                   ky->selected = 1;
181                }
182           }
183         if (!selected)
184           {
185              if (ky->selected)
186                {
187                   edje_object_signal_emit(ky->obj, "e,state,unselected", "e");
188                   ky->selected = 0;
189                }
190           }
191      }
192 }
193
194 static void
195 _e_kbd_int_string_send(E_Kbd_Int *ki, const char *str)
196 {
197    int pos, newpos, glyph;
198
199    pos = 0;
200    e_kbd_buf_word_use(ki->kbuf, str);
201    for (;;)
202      {
203         char buf[16];
204
205         newpos = evas_string_char_next_get(str, pos, &glyph);
206         if (glyph <= 0) return;
207         strncpy(buf, str + pos, newpos - pos);
208         buf[newpos - pos] = 0;
209         e_kbd_send_string_press(buf, 0);
210         pos = newpos;
211      }
212 }
213
214 static void
215 _e_kbd_int_buf_send(E_Kbd_Int *ki)
216 {
217    const char *str = NULL;
218    const Eina_List *matches;
219
220    matches = e_kbd_buf_string_matches_get(ki->kbuf);
221    if (matches) str = matches->data;
222    else str = e_kbd_buf_actual_string_get(ki->kbuf);
223    if (str) _e_kbd_int_string_send(ki, str);
224 }
225
226 static void
227 _e_kbd_int_cb_match_select(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
228 {
229    E_Kbd_Int_Match *km;
230
231    km = data;
232    _e_kbd_int_string_send(km->ki, km->str);
233    e_kbd_buf_clear(km->ki->kbuf);
234    e_kbd_send_keysym_press("space", 0);
235    if (km->ki->layout.state & (SHIFT | CTRL | ALT | ALTGR))
236      {
237         km->ki->layout.state &= (~(SHIFT | CTRL | ALT | ALTGR));
238         _e_kbd_int_layout_state_update(km->ki);
239      }
240    _e_kbd_int_matches_update(km->ki);
241 }
242
243 static void
244 _e_kbd_int_matches_add(E_Kbd_Int *ki, const char *str, int num)
245 {
246    E_Kbd_Int_Match *km;
247    Evas_Object *o;
248    Evas_Coord mw, mh;
249
250    km = E_NEW(E_Kbd_Int_Match, 1);
251    if (!km) return;
252    o = _theme_obj_new(ki->win->evas, ki->themedir,
253                       "e/modules/kbd/match/word");
254    km->ki = ki;
255    km->str = eina_stringshare_add(str);
256    km->obj = o;
257    ki->matches = eina_list_append(ki->matches, km);
258    edje_object_part_text_set(o, "e.text.label", str);
259    edje_object_size_min_calc(o, &mw, &mh);
260    if (mw < 32) mw = 32;
261    if (num & 0x1) e_box_pack_start(ki->box_obj, o);
262    else e_box_pack_end(ki->box_obj, o);
263    e_box_pack_options_set(o, 1, 1, 1, 1, 0.5, 0.5, mw, mh, 9999, 9999);
264    if (num == 0)
265      edje_object_signal_emit(o, "e,state,selected", "e");
266    edje_object_signal_callback_add(o, "e,action,do,select", "",
267                                    _e_kbd_int_cb_match_select, km);
268    evas_object_show(o);
269 }
270
271 static void
272 _e_kbd_int_matches_free(E_Kbd_Int *ki)
273 {
274    E_Kbd_Int_Match *km;
275
276    EINA_LIST_FREE(ki->matches, km)
277      {
278         if (km->str) eina_stringshare_del(km->str);
279         evas_object_del(km->obj);
280         free(km);
281      }
282 }
283
284 static void
285 _e_kbd_int_matches_update(void *data)
286 {
287    E_Kbd_Int *ki;
288    const Eina_List *l, *matches;
289    const char *actual;
290    Evas_Coord mw, mh, vw, vh;
291
292    if (!(ki = data)) return;
293    evas_event_freeze(ki->win->evas);
294    e_box_freeze(ki->box_obj);
295    _e_kbd_int_matches_free(ki);
296    matches = e_kbd_buf_string_matches_get(ki->kbuf);
297    if (!matches)
298      {
299         actual = e_kbd_buf_actual_string_get(ki->kbuf);
300         if (actual) _e_kbd_int_matches_add(ki, actual, 0);
301      }
302    else
303      {
304         int i = 0;
305
306         for (i = 0, l = matches; l; l = l->next, i++)
307           {
308              _e_kbd_int_matches_add(ki, l->data, i);
309              e_box_size_min_get(ki->box_obj, &mw, &mh);
310              edje_object_part_geometry_get(ki->base_obj, "e.swallow.label", 
311                                            NULL, NULL, &vw, &vh);
312              if (mw > vw) break;
313           }
314
315         if (!l)
316           {
317              actual = e_kbd_buf_actual_string_get(ki->kbuf);
318              if (actual)
319                {
320                   const char *str;
321
322                   EINA_LIST_FOREACH(matches, l, str)
323                     if (!strcmp(str, actual)) break;
324                   if (!l) _e_kbd_int_matches_add(ki, actual, i);
325                }
326           }
327      }
328    e_box_thaw(ki->box_obj);
329    e_box_size_min_get(ki->box_obj, &mw, &mh);
330    edje_extern_object_min_size_set(ki->box_obj, 0, mh);
331    edje_object_part_swallow(ki->base_obj, "e.swallow.label", ki->box_obj);
332    evas_event_thaw(ki->win->evas);
333
334    _e_kbd_int_matchlist_down(ki);
335 }
336
337 static void
338 _e_kbd_int_key_press_handle(E_Kbd_Int *ki, E_Kbd_Int_Key *ky)
339 {
340    E_Kbd_Int_Key_State *st;
341    const char *out = NULL;
342
343    if (!ky) return;
344
345    if (ky->is_shift)
346      {
347         if (ki->layout.state & SHIFT) ki->layout.state &= (~(SHIFT));
348         else ki->layout.state |= SHIFT;
349         _e_kbd_int_layout_state_update(ki);
350         return;
351      }
352    if (ky->is_multi_shift)
353      {
354         if (ki->layout.state & SHIFT)
355           {
356              ki->layout.state &= (~(SHIFT));
357              ki->layout.state |= CAPSLOCK;
358           }
359         else if (ki->layout.state & CAPSLOCK)
360           ki->layout.state &= (~(CAPSLOCK));
361         else
362           ki->layout.state |= SHIFT;
363         _e_kbd_int_layout_state_update(ki);
364         return;
365      }
366    if (ky->is_ctrl)
367      {
368         if (ki->layout.state & CTRL) ki->layout.state &= (~(CTRL));
369         else ki->layout.state |= CTRL;
370         if (e_kbd_buf_actual_string_get(ki->kbuf)) _e_kbd_int_buf_send(ki);
371         e_kbd_buf_clear(ki->kbuf);
372         _e_kbd_int_layout_state_update(ki);
373         _e_kbd_int_matches_update(ki);
374         return;
375      }
376    if (ky->is_alt)
377      {
378         if (ki->layout.state & ALT) ki->layout.state &= (~(ALT));
379         else ki->layout.state |= ALT;
380         if (e_kbd_buf_actual_string_get(ki->kbuf)) _e_kbd_int_buf_send(ki);
381         e_kbd_buf_clear(ki->kbuf);
382         _e_kbd_int_layout_state_update(ki);
383         _e_kbd_int_matches_update(ki);
384         return;
385      }
386    if (ky->is_altgr)
387      {
388         if (ki->layout.state & ALTGR) ki->layout.state &= (~(ALTGR));
389         else ki->layout.state |= ALTGR;
390         _e_kbd_int_layout_state_update(ki);
391         return;
392      }
393    if (ky->is_capslock)
394      {
395         if (ki->layout.state & CAPSLOCK) ki->layout.state &= (~CAPSLOCK);
396         else ki->layout.state |= CAPSLOCK;
397         _e_kbd_int_layout_state_update(ki);
398         return;
399      }
400    st = _e_kbd_int_key_state_get(ki, ky);
401    if (st) out = st->out;
402    if (ki->layout.state & (CTRL | ALT))
403      {
404         if (out)
405           {
406              Kbd_Mod mods = 0;
407
408              if (ki->layout.state & CTRL) mods |= KBD_MOD_CTRL;
409              if (ki->layout.state & ALT) mods |= KBD_MOD_ALT;
410              if (out[0] == '"')
411                e_kbd_send_string_press(_e_kbd_int_str_unquote(out), mods);
412              else
413                e_kbd_send_keysym_press(out, mods);
414           }
415         ki->layout.state &= (~(SHIFT | CTRL | ALT | ALTGR));
416         _e_kbd_int_layout_state_update(ki);
417         e_kbd_buf_lookup(ki->kbuf, _e_kbd_int_matches_update, ki);
418         return;
419      }
420    if (out)
421      {
422         if (out[0] == '"')
423           {
424              if (ki->down.zoom)
425                e_kbd_buf_pressed_key_add(ki->kbuf,
426                                          _e_kbd_int_str_unquote(out), 
427                                          ki->layout.state & SHIFT, 
428                                          ki->layout.state & CAPSLOCK);
429              else
430                e_kbd_buf_pressed_point_add(ki->kbuf,
431                                            ky->x + (ky->w / 2),
432                                            ky->y + (ky->h / 2),
433                                            ki->layout.state & SHIFT, 
434                                            ki->layout.state & CAPSLOCK);
435              e_kbd_buf_lookup(ki->kbuf, _e_kbd_int_matches_update, ki);
436           }
437         else
438           {
439              if (e_kbd_buf_actual_string_get(ki->kbuf)) 
440                _e_kbd_int_buf_send(ki);
441              e_kbd_buf_clear(ki->kbuf);
442              e_kbd_send_keysym_press(out, 0);
443              _e_kbd_int_matches_update(ki);
444           }
445      }
446    if (ki->layout.state & (SHIFT | CTRL | ALT | ALTGR))
447      {
448         printf("CLEARING STATE\n");
449         if (!ky->is_multi_shift) 
450           ki->layout.state &= (~(SHIFT | CTRL | ALT | ALTGR));
451         _e_kbd_int_layout_state_update(ki);
452      }
453 }
454     
455 static void
456 _e_kbd_int_stroke_handle(E_Kbd_Int *ki, int dir)
457 {
458    /* If the keyboard direction is RTL switch dir 3 and 1
459     * i.e, make forward backwards and the other way around */
460    if (ki->layout.direction == E_KBD_INT_DIRECTION_RTL)
461      {
462         if (dir == 3)
463           dir = 1;
464         else if (dir == 1)
465           dir = 3;
466      }
467
468    if (dir == 4) // up
469      _e_kbd_int_layout_next(ki);
470    else if (dir == 3) // left
471      {
472         if (e_kbd_buf_actual_string_get(ki->kbuf))
473           {
474              e_kbd_buf_backspace(ki->kbuf);
475              e_kbd_buf_lookup(ki->kbuf, _e_kbd_int_matches_update, ki);
476           }
477         else
478           e_kbd_send_keysym_press("BackSpace", 0);
479      }
480    else if (dir == 2) // down
481      {
482         if (e_kbd_buf_actual_string_get(ki->kbuf)) _e_kbd_int_buf_send(ki);
483         e_kbd_buf_clear(ki->kbuf);
484         e_kbd_send_keysym_press("Return", 0);
485         _e_kbd_int_matches_update(ki);
486      }
487    else if (dir == 1) // right
488      {
489         if (e_kbd_buf_actual_string_get(ki->kbuf)) _e_kbd_int_buf_send(ki);
490         e_kbd_buf_clear(ki->kbuf);
491         e_kbd_send_keysym_press("space", 0);
492         _e_kbd_int_matches_update(ki);
493      }
494    if (ki->layout.state)
495      {
496         ki->layout.state = 0;
497         _e_kbd_int_layout_state_update(ki);
498      }
499 }
500     
501 static void
502 _e_kbd_int_zoomkey_down(E_Kbd_Int *ki)
503 {
504    const Eina_List *l;
505
506    if (!ki->zoomkey.popup) return;
507    e_object_del(E_OBJECT(ki->zoomkey.popup));
508    ki->zoomkey.popup = NULL;
509    ki->zoomkey.layout_obj = NULL;
510    ki->zoomkey.sublayout_obj = NULL;
511    for (l = ki->layout.keys; l; l = l->next)
512      {
513         E_Kbd_Int_Key *ky;
514
515         ky = l->data;
516         ky->zoom_obj = NULL;
517         ky->zoom_icon_obj = NULL;
518      }
519 }
520
521 static void
522 _e_kbd_int_zoomkey_up(E_Kbd_Int *ki)
523 {
524    const Eina_List *l;
525    Evas_Object *o, *o2;
526    Evas_Coord mw, mh, vw, vh;
527    int sx, sy, sw, sh;
528
529    if (ki->zoomkey.popup) return;
530    ki->zoomkey.popup = e_popup_new(ki->win->border->zone, -1, -1, 1, 1);
531    e_popup_layer_set(ki->zoomkey.popup, 190);
532
533    o = _theme_obj_new(ki->zoomkey.popup->evas, ki->themedir,
534                       "e/modules/kbd/zoom/default");
535    ki->zoomkey.base_obj = o;
536
537    o = e_layout_add(ki->zoomkey.popup->evas);
538    e_layout_virtual_size_set(o, 100, 100);
539    edje_object_part_swallow(ki->zoomkey.base_obj, "e.swallow.content", o);
540    evas_object_show(o);
541    ki->zoomkey.layout_obj = o;
542
543    e_layout_virtual_size_get(ki->layout_obj, &vw, &vh);
544
545    o = e_layout_add(ki->zoomkey.popup->evas);
546    e_layout_virtual_size_set(o, vw, vh);
547    e_layout_pack(ki->zoomkey.layout_obj, o);
548    e_layout_child_move(o, 0, 0);
549    e_layout_child_resize(o,
550                          vw * il_kbd_cfg->zoom_level,
551                          vh * il_kbd_cfg->zoom_level);
552    evas_object_show(o);
553    ki->zoomkey.sublayout_obj = o;
554
555    for (l = ki->layout.keys; l; l = l->next)
556      {
557         E_Kbd_Int_Key *ky;
558         E_Kbd_Int_Key_State *st;
559         const char *label, *icon;
560         int selected;
561
562         ky = l->data;
563         o = _theme_obj_new(ki->zoomkey.popup->evas, ki->themedir,
564                            "e/modules/kbd/zoomkey/default");
565         label = "";
566         icon = NULL;
567         st = _e_kbd_int_key_state_get(ki, ky);
568         if (st)
569           {
570              label = st->label;
571              icon = st->icon;
572           }
573
574         edje_object_part_text_set(o, "e.text.label", label);
575
576         o2 = e_icon_add(ki->zoomkey.popup->evas);
577         e_icon_fill_inside_set(o2, 1);
578 //        e_icon_scale_up_set(o2, 0);
579         edje_object_part_swallow(o, "e.swallow.content", o2);
580         evas_object_show(o2);
581
582         if (icon)
583           {
584              char buf[PATH_MAX];
585              char *p;
586
587              snprintf(buf, sizeof(buf), "%s/%s", ki->layout.directory, icon);
588              p = strrchr(icon, '.');
589              if (!strcmp(p, ".edj"))
590                e_icon_file_edje_set(o2, buf, "icon");
591              else
592                e_icon_file_set(o2, buf);
593           }
594         selected = 0;
595         if ((ki->layout.state & SHIFT) && (ky->is_shift)) selected = 1;
596         if ((ki->layout.state & CTRL) && (ky->is_ctrl)) selected = 1;
597         if ((ki->layout.state & ALT) && (ky->is_alt)) selected = 1;
598         if ((ki->layout.state & ALTGR) && (ky->is_altgr)) selected = 1;
599         if ((ki->layout.state & CAPSLOCK) && (ky->is_capslock)) selected = 1;
600         if ((ki->layout.state & (SHIFT|CAPSLOCK)) && (ky->is_multi_shift)) 
601           selected = 1;
602         if (selected)
603           edje_object_signal_emit(o, "e,state,selected", "e");
604         if (!selected)
605           edje_object_signal_emit(o, "e,state,unselected", "e");
606         e_layout_pack(ki->zoomkey.sublayout_obj, o);
607         e_layout_child_move(o, ky->x, ky->y);
608         e_layout_child_resize(o, ky->w, ky->h);
609         evas_object_show(o);
610         ky->zoom_obj = o;
611         ky->zoom_icon_obj = o2;
612      }
613
614    edje_object_size_min_calc(ki->zoomkey.base_obj, &vw, &vh);
615    e_zone_useful_geometry_get(ki->win->border->zone, &sx, &sy, &sw, &sh);
616    sh -= ki->win->h;
617    mw = sw;
618    if ((vw > 0) && (mw > vw)) mw = vw;
619    mh = sh;
620    if ((vh > 0) && (mh > vh)) mh = vh;
621
622    e_popup_move_resize(ki->zoomkey.popup, 
623                        sx + ((sw - mw) / 2), sy + ((sh - mh) / 2), mw, mh);
624    evas_object_resize(ki->zoomkey.base_obj,
625                       ki->zoomkey.popup->w, ki->zoomkey.popup->h);
626    evas_object_show(ki->zoomkey.base_obj);
627    e_popup_edje_bg_object_set(ki->zoomkey.popup, ki->zoomkey.base_obj);
628    e_popup_show(ki->zoomkey.popup);
629    e_popup_layer_set(ki->zoomkey.popup, 190);
630 }
631
632 static void
633 _e_kbd_int_zoomkey_update(E_Kbd_Int *ki)
634 {
635    Evas_Coord w, h, ww, hh;
636    E_Kbd_Int_Key *ky;
637
638    evas_object_geometry_get(ki->zoomkey.layout_obj, NULL, NULL, &w, &h);
639    evas_object_geometry_get(ki->layout_obj, NULL, NULL, &ww, &hh);
640    e_layout_virtual_size_set(ki->zoomkey.layout_obj, w, h);
641    e_layout_child_resize(ki->zoomkey.sublayout_obj,
642                          ww * il_kbd_cfg->zoom_level,
643                          hh * il_kbd_cfg->zoom_level);
644    e_layout_child_move(ki->zoomkey.sublayout_obj, 
645                        (w / 2) - (ki->down.cx * il_kbd_cfg->zoom_level),
646                        (h / 2) - (ki->down.cy * il_kbd_cfg->zoom_level));
647    ky = _e_kbd_int_at_coord_get(ki, ki->down.clx, ki->down.cly);
648    if (ky != ki->zoomkey.pressed)
649      {
650         if (ki->zoomkey.pressed)
651           {
652              ki->zoomkey.pressed->pressed = 0;
653              edje_object_signal_emit(ki->zoomkey.pressed->zoom_obj,
654                                      "e,state,released", "e");
655              edje_object_signal_emit(ki->zoomkey.pressed->obj,
656                                      "e,state,released", "e");
657           }
658         ki->zoomkey.pressed = ky;
659         if (ki->zoomkey.pressed)
660           {
661              ki->zoomkey.pressed->pressed = 1;
662              e_layout_child_raise(ki->zoomkey.pressed->zoom_obj);
663              edje_object_signal_emit(ki->zoomkey.pressed->zoom_obj,
664                                      "e,state,pressed", "e");
665              e_layout_child_raise(ki->zoomkey.pressed->obj);
666              e_layout_child_raise(ki->event_obj);
667              edje_object_signal_emit(ki->zoomkey.pressed->obj,
668                                      "e,state,pressed", "e");
669           }
670      }
671 }
672
673 static Eina_Bool
674 _e_kbd_int_cb_hold_timeout(void *data)
675 {
676    E_Kbd_Int *ki;
677
678    ki = data;
679    ki->down.hold_timer = NULL;
680    ki->down.zoom = 1;
681    if (ki->layout.pressed)
682      {
683         ki->layout.pressed->pressed = 0;
684         edje_object_signal_emit(ki->layout.pressed->obj,
685                                 "e,state,released", "e");
686         ki->layout.pressed = NULL;
687      }
688    _e_kbd_int_zoomkey_up(ki);
689    _e_kbd_int_zoomkey_update(ki);
690    return ECORE_CALLBACK_CANCEL;
691 }
692
693 static void
694 _e_kbd_int_cb_mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
695 {
696    Evas_Event_Mouse_Down *ev;
697    E_Kbd_Int *ki;
698    Evas_Coord x, y, w, h;
699    E_Kbd_Int_Key *ky;
700
701    ev = event_info;
702    if (ev->button != 1) return;
703    ki = data;
704    ki->down.x = ev->canvas.x;
705    ki->down.y = ev->canvas.y;
706    ki->down.down = 1;
707    ki->down.stroke = 0;
708
709    evas_object_geometry_get(ki->event_obj, &x, &y, &w, &h);
710    x = ev->canvas.x - x;
711    y = ev->canvas.y - y;
712    ki->down.cx = x;
713    ki->down.cy = y;
714    x = (x * ki->layout.w) / w;
715    y = (y * ki->layout.h) / h;
716
717    ki->down.lx = x;
718    ki->down.ly = y;
719    ki->down.clx = x;
720    ki->down.cly = y;
721
722    if (ki->down.hold_timer) ecore_timer_del(ki->down.hold_timer);
723    ki->down.hold_timer = ecore_timer_add(il_kbd_cfg->hold_timer,
724                                          _e_kbd_int_cb_hold_timeout, ki);
725
726    ky = _e_kbd_int_at_coord_get(ki, x, y);
727    ki->layout.pressed = ky;
728    if (ky)
729      {
730         ky->pressed = 1;
731         e_layout_child_raise(ky->obj);
732         e_layout_child_raise(ki->event_obj);
733         edje_object_signal_emit(ky->obj, "e,state,pressed", "e");
734      }
735 }
736
737 static void
738 _e_kbd_int_cb_mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
739 {
740    Evas_Event_Mouse_Move *ev;
741    E_Kbd_Int *ki;
742    Evas_Coord dx, dy, x, w, y, h;
743
744    ev = event_info;
745    ki = data;
746
747    if (ki->down.zoom)
748      {
749         evas_object_geometry_get(ki->event_obj, &x, &y, &w, &h);
750         x = ev->cur.canvas.x - x;
751         y = ev->cur.canvas.y - y;
752         ki->down.cx = x;
753         ki->down.cy = y;
754         x = (x * ki->layout.w) / w;
755         y = (y * ki->layout.h) / h;
756         ki->down.clx = x;
757         ki->down.cly = y;
758         _e_kbd_int_zoomkey_update(ki);
759         return;
760      }
761    if (ki->down.stroke) return;
762
763    dx = ev->cur.canvas.x - ki->down.x;
764    dy = ev->cur.canvas.y - ki->down.y;
765    evas_object_geometry_get(ki->event_obj, &x, &y, &w, &h);
766    dx = (dx * ki->layout.w) / w;
767    dy = (dy * ki->layout.h) / h;
768    if ((dx > 0) && (dx > (ki->layout.w / il_kbd_cfg->slide_dim)))
769      ki->down.stroke = 1;
770    else if ((dx < 0) && (-dx > (ki->layout.w / il_kbd_cfg->slide_dim)))
771      ki->down.stroke = 1;
772    if ((dy > 0) && (dy > (ki->layout.h / il_kbd_cfg->slide_dim)))
773      ki->down.stroke = 1;
774    else if ((dy < 0) && (-dy > (ki->layout.w / il_kbd_cfg->slide_dim)))
775      ki->down.stroke = 1;
776    if ((ki->down.stroke) && (ki->down.hold_timer))
777      {
778         ecore_timer_del(ki->down.hold_timer);
779         ki->down.hold_timer = NULL;
780      }
781 }
782
783 static void
784 _e_kbd_int_cb_mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
785 {
786    Evas_Event_Mouse_Up *ev;
787    E_Kbd_Int *ki;
788    E_Kbd_Int_Key *ky;
789    int dir = 0;
790
791    ev = event_info;
792    if (ev->button != 1) return;
793    ki = data;
794
795    if (ki->down.zoom)
796      {
797         ky = _e_kbd_int_at_coord_get(ki, ki->down.clx, ki->down.cly);
798         _e_kbd_int_key_press_handle(ki, ky);
799         _e_kbd_int_zoomkey_down(ki);
800         ki->down.zoom = 0;
801      }
802    else if (!ki->down.down)
803      {
804         /* case of mouse up event without mouse down when popup appear */
805         Evas_Coord x, y, w, h;
806         evas_object_geometry_get(ki->event_obj, &x, &y, &w, &h);
807         x = ev->canvas.x - x;
808         y = ev->canvas.y - y;
809         x = (x * ki->layout.w) / w;
810         y = (y * ki->layout.h) / h;
811         ky = _e_kbd_int_at_coord_get(ki, x, y);
812         ki->layout.pressed = ky;
813         _e_kbd_int_key_press_handle(ki, ki->layout.pressed);
814         edje_object_signal_emit(ky->obj,
815                                 "e,state,pressed", "e");
816         edje_object_message_signal_process(ky->obj);
817      }
818    else if (!ki->down.stroke)
819      {
820
821         ky = _e_kbd_int_at_coord_get(ki, ki->down.lx, ki->down.ly);
822         _e_kbd_int_key_press_handle(ki, ky);
823      }
824    else
825      {
826         Evas_Coord dx, dy;
827
828         dx = ev->canvas.x - ki->down.x;
829         dy = ev->canvas.y - ki->down.y;
830         if (dx > 0)
831           {
832              if (dy > 0)
833                {
834                   if (dx > dy) dir = 1; // right
835                   else dir = 2; // down
836                }
837              else
838                {
839                   if (dx > -dy) dir = 1; // right
840                   else dir = 4; // up
841                }
842           }
843         else
844           {
845              if (dy > 0)
846                {
847                   if (-dx > dy) dir = 3; // left
848                   else dir = 2; // down
849                }
850              else
851                {
852                   if (-dx > -dy) dir = 3; // left
853                   else dir = 4; // up
854                }
855           }
856      }
857
858    ky = ki->layout.pressed;
859    if (ky)
860      {
861         ky->pressed = 0;
862         edje_object_signal_emit(ky->obj, "e,state,released", "e");
863         ki->layout.pressed = NULL;
864      }
865    ky = ki->zoomkey.pressed;
866    if (ky)
867      {
868         ky->pressed = 0;
869         edje_object_signal_emit(ky->obj, "e,state,released", "e");
870         ki->zoomkey.pressed = NULL;
871      }
872
873    ki->down.down = 0;
874    ki->down.stroke = 0;
875    if (ki->down.hold_timer)
876      {
877         ecore_timer_del(ki->down.hold_timer);
878         ki->down.hold_timer = NULL;
879      }
880
881    if (dir > 0) _e_kbd_int_stroke_handle(ki, dir);
882 }
883
884 static E_Kbd_Int_Layout *
885 _e_kbd_int_layouts_list_default_get(E_Kbd_Int *ki)
886 {
887    E_Kbd_Int_Layout *kil;
888    Eina_List *l;
889
890    EINA_LIST_FOREACH(ki->layouts, l, kil)
891      if (kil->type == il_kbd_cfg->layout)
892        return kil;
893
894    EINA_LIST_FOREACH(ki->layouts, l, kil)
895      if ((!strcmp(ecore_file_file_get(kil->path), "Default.kbd")))
896        return kil;
897    return NULL;
898 }
899
900 static E_Kbd_Int_Layout *
901 _e_kbd_int_layouts_type_get(E_Kbd_Int *ki, int type)
902 {
903    E_Kbd_Int_Layout *kil;
904    Eina_List *l;
905
906    EINA_LIST_FOREACH(ki->layouts, l, kil)
907      if (kil->type == type) return kil;
908    return NULL;
909 }
910
911 static void
912 _e_kbd_int_layout_free(E_Kbd_Int *ki)
913 {
914    E_Kbd_Int_Key *ky;
915
916    if (ki->layout.directory) free(ki->layout.directory);
917    if (ki->layout.file) eina_stringshare_del(ki->layout.file);
918    ki->layout.directory = NULL;
919    ki->layout.file = NULL;
920    EINA_LIST_FREE(ki->layout.keys, ky)
921      {
922         E_Kbd_Int_Key_State *st;
923
924         EINA_LIST_FREE(ky->states, st)
925           {
926              if (st->label) eina_stringshare_del(st->label);
927              if (st->icon) eina_stringshare_del(st->icon);
928              if (st->out) eina_stringshare_del(st->out);
929              free(st);
930           }
931         if (ky->obj) evas_object_del(ky->obj);
932         if (ky->icon_obj) evas_object_del(ky->icon_obj);
933         free(ky);
934      }
935    if (ki->event_obj) evas_object_del(ki->event_obj);
936    ki->event_obj = NULL;
937 }
938
939 static void
940 _e_kbd_int_layout_parse(E_Kbd_Int *ki, const char *layout)
941 {
942    FILE *f;
943    char buf[PATH_MAX];
944    int isok = 0;
945    E_Kbd_Int_Key *ky = NULL;
946    E_Kbd_Int_Key_State *st = NULL;
947
948    if (!(f = fopen(layout, "r"))) return;
949
950    ki->layout.directory = ecore_file_dir_get(layout);
951    ki->layout.file = eina_stringshare_add(layout);
952
953    /* Make the default direction LTR */
954    ki->layout.direction = E_KBD_INT_DIRECTION_LTR;
955
956    while (fgets(buf, sizeof(buf), f))
957      {
958         int len;
959         char str[PATH_MAX];
960
961         if (!isok)
962           {
963              if (!strcmp(buf, "##KBDCONF-1.0\n")) isok = 1;
964           }
965         if (!isok) break;
966         if (buf[0] == '#') continue;
967         len = strlen(buf);
968         if (len > 0)
969           {
970              if (buf[len - 1] == '\n') buf[len - 1] = 0;
971           }
972         if (sscanf(buf, "%4000s", str) != 1) continue;
973         if (!strcmp(str, "kbd"))
974           {
975              if (sscanf(buf, "%*s %i %i\n", &(ki->layout.w), &(ki->layout.orig_h)) != 2)
976                continue;
977           }
978         if (!strcmp(str, "fuzz"))
979           {
980              sscanf(buf, "%*s %i\n", &(ki->layout.fuzz));
981              continue;
982           }
983         if (!strcmp(str, "direction"))
984           {
985              char direction[4];
986
987              sscanf(buf, "%*s %3s\n", direction);
988
989              /* If rtl mark as rtl, otherwise make it ltr */
990              if (!strcmp(direction, "rtl"))
991                ki->layout.direction = E_KBD_INT_DIRECTION_RTL;
992              else
993                ki->layout.direction = E_KBD_INT_DIRECTION_LTR;
994              continue;
995           }
996         if (!strcmp(str, "key"))
997           {
998              ky = calloc(1, sizeof(E_Kbd_Int_Key));
999              if (!ky) continue;
1000              if (sscanf(buf, "%*s %i %i %i %i\n", &(ky->x), &(ky->orig_y), &(ky->w), &(ky->orig_h)) != 4)
1001                {
1002                   free(ky);
1003                   ky = NULL;
1004                   continue;
1005                }
1006              ki->layout.keys = eina_list_append(ki->layout.keys, ky);
1007           }
1008         if (!ky) continue;
1009         if ((!strcmp(str, "normal")) || (!strcmp(str, "shift")) ||
1010             (!strcmp(str, "capslock")) || (!strcmp(str, "altgr")))
1011           {
1012              char *p;
1013              char label[PATH_MAX];
1014
1015              if (sscanf(buf, "%*s %4000s", label) != 1) continue;
1016              st = calloc(1, sizeof(E_Kbd_Int_Key_State));
1017              if (!st) continue;
1018              ky->states = eina_list_append(ky->states, st);
1019              if (!strcmp(str, "normal")) st->state = NORMAL;
1020              if (!strcmp(str, "shift")) st->state = SHIFT;
1021              if (!strcmp(str, "capslock")) st->state = CAPSLOCK;
1022              if (!strcmp(str, "altgr")) st->state = ALTGR;
1023              p = strrchr(label, '.');
1024              if ((p) && (!strcmp(p, ".png")))
1025                st->icon = eina_stringshare_add(label);
1026              else if ((p) && (!strcmp(p, ".edj")))
1027                st->icon = eina_stringshare_add(label);
1028              else
1029                st->label = eina_stringshare_add(label);
1030              if (sscanf(buf, "%*s %*s %4000s", str) != 1) continue;
1031              st->out = eina_stringshare_add(str);
1032           }
1033         if (!strcmp(str, "is_shift")) ky->is_shift = 1;
1034         if (!strcmp(str, "is_multi_shift")) ky->is_multi_shift = 1;
1035         if (!strcmp(str, "is_ctrl")) ky->is_ctrl = 1;
1036         if (!strcmp(str, "is_alt")) ky->is_alt = 1;
1037         if (!strcmp(str, "is_altgr")) ky->is_altgr = 1;
1038         if (!strcmp(str, "is_capslock")) ky->is_capslock = 1;
1039      }
1040    fclose(f);
1041 }
1042
1043 static void
1044 _e_kbd_int_layout_build(E_Kbd_Int *ki)
1045 {
1046    E_Kbd_Int_Key *ky;
1047    Evas_Object *o, *o2;
1048    Evas_Coord lw, lh;
1049    Eina_List *l;
1050
1051    ki->layout.h = ki->layout.orig_h * il_kbd_cfg->scale_height;
1052
1053    evas_event_freeze(ki->win->evas);
1054    e_layout_virtual_size_set(ki->layout_obj, ki->layout.w, ki->layout.h);
1055    edje_extern_object_aspect_set(ki->layout_obj, EDJE_ASPECT_CONTROL_BOTH, 
1056                                  ki->layout.w, ki->layout.h);
1057    edje_object_part_swallow(ki->base_obj, "e.swallow.content", ki->layout_obj);
1058    evas_object_resize(ki->base_obj, ki->win->w, ki->win->h);
1059    edje_object_part_geometry_get(ki->base_obj, "e.swallow.content", 
1060                                  NULL, NULL, &lw, &lh);
1061    lh = (ki->layout.h * lw) / ki->layout.w;
1062    if (lw > ki->win->w) lw = ki->win->w;
1063    if (lh > ki->win->h) lh = ki->win->h;
1064    edje_extern_object_min_size_set(ki->layout_obj, lw, lh);
1065    edje_extern_object_max_size_set(ki->layout_obj, ki->win->w, ki->win->h);
1066
1067    EINA_LIST_FOREACH(ki->layout.keys, l, ky)
1068      {
1069         E_Kbd_Int_Key_State *st;
1070         const char *label, *icon;
1071
1072         ky->y = ky->orig_y * il_kbd_cfg->scale_height;
1073         ky->h = ky->orig_h * il_kbd_cfg->scale_height;
1074
1075         o = _theme_obj_new(ki->win->evas, ki->themedir,
1076                            "e/modules/kbd/key/default");
1077         ky->obj = o;
1078         label = "";
1079         icon = NULL;
1080         st = _e_kbd_int_key_state_get(ki, ky);
1081         if (st)
1082           {
1083              label = st->label;
1084              icon = st->icon;
1085           }
1086
1087         edje_object_part_text_set(o, "e.text.label", label);
1088
1089         o2 = e_icon_add(ki->win->evas);
1090         e_icon_fill_inside_set(o2, 1);
1091         e_icon_scale_up_set(o2, 0);
1092         ky->icon_obj = o2;
1093         edje_object_part_swallow(o, "e.swallow.content", o2);
1094         evas_object_show(o2);
1095
1096         if (icon)
1097           {
1098              char buf[PATH_MAX];
1099              char *p;
1100
1101              snprintf(buf, sizeof(buf), "%s/%s", ki->layout.directory, icon);
1102              p = strrchr(icon, '.');
1103              if (!strcmp(p, ".edj"))
1104                e_icon_file_edje_set(o2, buf, "icon");
1105              else
1106                e_icon_file_set(o2, buf);
1107           }
1108         e_layout_pack(ki->layout_obj, o);
1109         e_layout_child_move(o, ky->x, ky->y);
1110         e_layout_child_resize(o, ky->w, ky->h);
1111         evas_object_show(o);
1112      }
1113
1114    o = evas_object_rectangle_add(ki->win->evas);
1115    e_layout_pack(ki->layout_obj, o);
1116    e_layout_child_move(o, 0, 0);
1117    e_layout_child_resize(o, ki->layout.w, ki->layout.h);
1118    evas_object_color_set(o, 0, 0, 0, 0);
1119    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, 
1120                                   _e_kbd_int_cb_mouse_down, ki);
1121    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, 
1122                                   _e_kbd_int_cb_mouse_up, ki);
1123    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, 
1124                                   _e_kbd_int_cb_mouse_move, ki);
1125    evas_object_show(o);
1126    ki->event_obj = o;
1127    evas_event_thaw(ki->win->evas);
1128    _e_kbd_int_matchlist_down(ki);
1129 }
1130
1131 static void
1132 _e_kbd_int_layouts_free(E_Kbd_Int *ki)
1133 {
1134    E_Kbd_Int_Layout *kil;
1135
1136    EINA_LIST_FREE(ki->layouts, kil)
1137      {
1138         eina_stringshare_del(kil->path);
1139         eina_stringshare_del(kil->dir);
1140         eina_stringshare_del(kil->icon);
1141         eina_stringshare_del(kil->name);
1142         free(kil);
1143      }
1144 }
1145
1146 static void
1147 _e_kbd_int_layouts_list_update(E_Kbd_Int *ki)
1148 {
1149    Eina_List *files;
1150    Eina_List *l;
1151    char buf[PATH_MAX], *p, *file, *path;
1152    const char *fl;
1153    Eina_List *kbs = NULL, *layouts = NULL;
1154    int ok;
1155    size_t len;
1156
1157    len = e_user_dir_concat_static(buf, "keyboards");
1158    if (len + 2 >= sizeof(buf)) return;
1159
1160    files = ecore_file_ls(buf);
1161
1162    buf[len] = '/';
1163    len++;
1164
1165    EINA_LIST_FREE(files, file)
1166      {
1167         p = strrchr(file, '.');
1168         if ((p) && (!strcmp(p, ".kbd")))
1169           {
1170              if (eina_strlcpy(buf + len, file, sizeof(buf) - len) >= sizeof(buf) - len)
1171                continue;
1172              kbs = eina_list_append(kbs, eina_stringshare_add(buf));
1173           }
1174         free(file);
1175      }
1176
1177    len = snprintf(buf, sizeof(buf), "%s/keyboards", ki->syskbds);
1178    if (len + 2 >= sizeof(buf)) return;
1179
1180    files = ecore_file_ls(buf);
1181
1182    buf[len] = '/';
1183    len++;
1184
1185    EINA_LIST_FREE(files, file)
1186      {
1187         p = strrchr(file, '.');
1188         if ((p) && (!strcmp(p, ".kbd")))
1189           {
1190              ok = 1;
1191              EINA_LIST_FOREACH(kbs, l, fl)
1192                {
1193                   if (!strcmp(file, fl))
1194                     {
1195                        ok = 0;
1196                        break;
1197                     }
1198                }
1199              if (ok)
1200                {
1201                   if (eina_strlcpy(buf + len, file, sizeof(buf) - len) >= sizeof(buf) - len)
1202                     continue;
1203                   kbs = eina_list_append(kbs, eina_stringshare_add(buf));
1204                }
1205           }
1206         free(file);
1207      }
1208    /* Previous loop could break before destroying all items. */
1209    EINA_LIST_FREE(files, file)
1210      free(file);
1211
1212    EINA_LIST_FREE(kbs, path)
1213      {
1214         E_Kbd_Int_Layout *kil;
1215
1216         kil = E_NEW(E_Kbd_Int_Layout, 1);
1217         if (kil)
1218           {
1219              char *s, *p;
1220              FILE *f;
1221
1222              kil->path = path;
1223              s = strdup(ecore_file_file_get(kil->path));
1224              if (s)
1225                {
1226                   p = strrchr(s, '.');
1227                   if (p) *p = 0;
1228                   kil->name = eina_stringshare_add(s);
1229                   free(s);
1230                }
1231              s = ecore_file_dir_get(kil->path);
1232              if (s)
1233                {
1234                   kil->dir = eina_stringshare_add(s);
1235                   free(s);
1236                }
1237              f = fopen(kil->path, "r");
1238              if (f)
1239                {
1240                   int isok = 0;
1241
1242                   while (fgets(buf, sizeof(buf), f))
1243                     {
1244                        int len;
1245                        char str[4096];
1246
1247                        if (!isok)
1248                          {
1249                             if (!strcmp(buf, "##KBDCONF-1.0\n")) isok = 1;
1250                          }
1251                        if (!isok) break;
1252                        if (buf[0] == '#') continue;
1253                        len = strlen(buf);
1254                        if (len > 0)
1255                          {
1256                             if (buf[len - 1] == '\n') buf[len - 1] = 0;
1257                          }
1258                        if (sscanf(buf, "%4000s", str) != 1) continue;
1259                        if (!strcmp(str, "type"))
1260                          {
1261                             sscanf(buf, "%*s %4000s\n", str);
1262                             if (!strcmp(str, "ALPHA"))
1263                               kil->type = E_KBD_INT_TYPE_ALPHA;
1264                             else if (!strcmp(str, "NUMERIC"))
1265                               kil->type = E_KBD_INT_TYPE_NUMERIC;
1266                             else if (!strcmp(str, "PIN"))
1267                               kil->type = E_KBD_INT_TYPE_PIN;
1268                             else if (!strcmp(str, "PHONE_NUMBER"))
1269                               kil->type = E_KBD_INT_TYPE_PHONE_NUMBER;
1270                             else if (!strcmp(str, "HEX"))
1271                               kil->type = E_KBD_INT_TYPE_HEX;
1272                             else if (!strcmp(str, "TERMINAL"))
1273                               kil->type = E_KBD_INT_TYPE_TERMINAL;
1274                             else if (!strcmp(str, "PASSWORD"))
1275                               kil->type = E_KBD_INT_TYPE_PASSWORD;
1276                             else if (!strcmp(str, "IP"))
1277                               kil->type = E_KBD_INT_TYPE_IP;
1278                             else if (!strcmp(str, "HOST"))
1279                               kil->type = E_KBD_INT_TYPE_HOST;
1280                             else if (!strcmp(str, "FILE"))
1281                               kil->type = E_KBD_INT_TYPE_FILE;
1282                             else if (!strcmp(str, "URL"))
1283                               kil->type = E_KBD_INT_TYPE_URL;
1284                             else if (!strcmp(str, "KEYPAD"))
1285                               kil->type = E_KBD_INT_TYPE_KEYPAD;
1286                             else if (!strcmp(str, "J2ME"))
1287                               kil->type = E_KBD_INT_TYPE_J2ME;
1288                             continue;
1289                          }
1290                        if (!strcmp(str, "icon"))
1291                          {
1292                             sscanf(buf, "%*s %4000s\n", str);
1293                             snprintf(buf, sizeof(buf), "%s/%s", kil->dir, str);
1294                             kil->icon = eina_stringshare_add(buf);
1295                             continue;
1296                          }
1297                     }
1298                   fclose(f);
1299                }
1300              layouts = eina_list_append(layouts, kil);
1301           }
1302      }
1303    _e_kbd_int_layouts_free(ki);
1304    ki->layouts = layouts;
1305 }
1306
1307 static void
1308 _e_kbd_int_layout_select(E_Kbd_Int *ki, E_Kbd_Int_Layout *kil)
1309 {
1310    _e_kbd_int_layout_free(ki);
1311    _e_kbd_int_layout_parse(ki, kil->path);
1312    _e_kbd_int_layout_build(ki);
1313    _e_kbd_int_layout_buf_update(ki);
1314    _e_kbd_int_layout_state_update(ki);
1315
1316    if (!kil->icon)
1317      e_icon_file_set(ki->icon_obj, kil->icon);
1318    else
1319      {
1320         const char *p;
1321
1322         p = strrchr(kil->icon, '.');
1323         if (!p)
1324           e_icon_file_set(ki->icon_obj, kil->icon);
1325         else
1326           {
1327              if (!strcmp(p, ".edj"))
1328                e_icon_file_edje_set(ki->icon_obj, kil->icon, "icon");
1329              else
1330                e_icon_file_set(ki->icon_obj, kil->icon);
1331           }
1332      }
1333 }
1334
1335 static void
1336 _e_kbd_int_layout_next(E_Kbd_Int *ki)
1337 {
1338    Eina_List *l, *ln = NULL;
1339    E_Kbd_Int_Layout *kil;
1340
1341    EINA_LIST_FOREACH(ki->layouts, l, kil)
1342      if (!strcmp(kil->path, ki->layout.file))
1343        {
1344           ln = l->next;
1345           break;
1346        }
1347    if (!ln) ln = ki->layouts;
1348    if (!ln) return;
1349    kil = ln->data;
1350    _e_kbd_int_layout_select(ki, kil);
1351 }
1352
1353 static Eina_Bool
1354 _e_kbd_int_cb_client_message(void *data, __UNUSED__ int type, void *event)
1355 {
1356    Ecore_X_Event_Client_Message *ev;
1357    E_Kbd_Int *ki;
1358
1359    ev = event;
1360    ki = data;
1361    if ((ev->win == ki->win->evas_win) && 
1362        (ev->message_type == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE)) 
1363      {
1364         E_Kbd_Int_Layout *kil = NULL;
1365
1366         if ((unsigned int)ev->data.l[0] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_OFF)
1367           {
1368              _e_kbd_int_zoomkey_down(ki);
1369              _e_kbd_int_dictlist_down(ki);
1370              _e_kbd_int_matchlist_down(ki);
1371           }
1372         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_ON)
1373           {
1374              // do nothing - leave kbd as-is
1375           }
1376         else if ((unsigned int)ev->data.l[0] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_ALPHA)
1377           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_ALPHA);
1378         else if ((unsigned int)ev->data.l[0] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_NUMERIC)
1379           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_NUMERIC);
1380         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN)
1381           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_PIN);
1382         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER)
1383           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_PHONE_NUMBER);
1384         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX)
1385           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_HEX);
1386         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL)
1387           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_TERMINAL);
1388         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD)
1389           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_PASSWORD);
1390         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_IP)
1391           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_IP);
1392         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_HOST)
1393           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_HOST);
1394         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_FILE)
1395           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_FILE);
1396         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_URL)
1397           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_URL);
1398         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_KEYPAD)
1399           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_KEYPAD);
1400         else if (ev->data.l[0] == ECORE_X_VIRTUAL_KEYBOARD_STATE_J2ME)
1401           kil = _e_kbd_int_layouts_type_get(ki, E_KBD_INT_TYPE_J2ME);
1402
1403         if (kil) _e_kbd_int_layout_select(ki, kil);
1404      }
1405    return ECORE_CALLBACK_PASS_ON;
1406 }
1407
1408 static void
1409 _e_kbd_int_dictlist_down(E_Kbd_Int *ki)
1410 {
1411    char *str;
1412
1413    if (!ki->dictlist.popup) return;
1414    e_object_del(E_OBJECT(ki->dictlist.popup));
1415    ki->dictlist.popup = NULL;
1416    EINA_LIST_FREE(ki->dictlist.matches, str)
1417      eina_stringshare_del(str);
1418 }
1419
1420 static void
1421 _e_kbd_int_cb_dictlist_item_sel(void *data)
1422 {
1423    E_Kbd_Int *ki;
1424    const char *str;
1425    int i;
1426
1427    ki = data;
1428    i = e_widget_ilist_selected_get(ki->dictlist.ilist_obj);
1429    str = eina_list_nth(ki->dictlist.matches, i);
1430    e_kbd_buf_clear(ki->kbuf);
1431    if (ki->layout.state & (SHIFT | CTRL | ALT | ALTGR))
1432      {
1433         ki->layout.state &= (~(SHIFT | CTRL | ALT | ALTGR));
1434         _e_kbd_int_layout_state_update(ki);
1435      }
1436
1437    eina_stringshare_replace(&il_kbd_cfg->dict, str);
1438    e_kbd_buf_dict_set(ki->kbuf, il_kbd_cfg->dict);
1439    e_config_save_queue();
1440
1441    _e_kbd_int_dictlist_down(ki);
1442 }
1443
1444 static void
1445 _e_kbd_int_dictlist_up(E_Kbd_Int *ki)
1446 {
1447    Evas_Object *o;
1448    Evas_Coord mw, mh, sh;
1449    Eina_List *files, *l;
1450    char buf[PATH_MAX], *p, *file, *pp;
1451    const char *str;
1452    int used;
1453
1454    if (ki->dictlist.popup) return;
1455
1456    ki->dictlist.popup = e_popup_new(ki->win->border->zone, -1, -1, 1, 1);
1457    e_popup_layer_set(ki->dictlist.popup, 190);
1458
1459    o = _theme_obj_new(ki->dictlist.popup->evas, ki->themedir,
1460                       "e/modules/kbd/match/default");
1461    ki->dictlist.base_obj = o;
1462
1463    o = e_widget_ilist_add(ki->dictlist.popup->evas, 
1464                           (32 * e_scale), (32 * e_scale), NULL);
1465    e_widget_ilist_selector_set(o, 1);
1466    e_widget_ilist_freeze(o);
1467    ki->dictlist.ilist_obj = o;
1468
1469    e_user_dir_concat_static(buf, "dicts");
1470    files = ecore_file_ls(buf);
1471
1472    EINA_LIST_FREE(files, file)
1473      {
1474         p = strrchr(file, '.');
1475         if ((p) && (!strcmp(p, ".dic")))
1476           {
1477              const char *match;
1478
1479              used = 0;
1480              EINA_LIST_FOREACH(ki->dictlist.matches, l, match)
1481                if (!strcmp(match, file)) used = 1;
1482
1483              if (used) goto next1;
1484
1485              p = strdup(file);
1486              if (!p) goto next1;
1487
1488              for (pp = p; *pp; pp++)
1489                {
1490                   if (*pp == '_') *pp = ' ';
1491                }
1492              pp = strrchr(p, '.');
1493              *pp = 0;
1494              str = eina_stringshare_add(file);
1495              ki->dictlist.matches = eina_list_append(ki->dictlist.matches, str);
1496              e_widget_ilist_append(o, NULL, p, _e_kbd_int_cb_dictlist_item_sel,
1497                                    ki, NULL);
1498              free(p);
1499           }
1500
1501         next1:
1502         free(file);
1503      }
1504
1505    snprintf(buf, sizeof(buf), "%s/dicts", ki->sysdicts);
1506    files = ecore_file_ls(buf);
1507    EINA_LIST_FREE(files, file)
1508      {
1509         p = strrchr(file, '.');
1510         if ((p) && (!strcmp(p, ".dic")))
1511           {
1512              const char *match;
1513
1514              used = 0;
1515              EINA_LIST_FOREACH(ki->dictlist.matches, l, match)
1516                if (!strcmp(match, file)) used = 1;
1517
1518              if (used) goto next2;
1519
1520              p = strdup(file);
1521              if (!p) goto next2;
1522
1523              for (pp = p; *pp; pp++)
1524                {
1525                   if (*pp == '_') *pp = ' ';
1526                }
1527              pp = strrchr(p, '.');
1528              *pp = 0;
1529              str = eina_stringshare_add(file);
1530              ki->dictlist.matches = eina_list_append(ki->dictlist.matches, str);
1531              e_widget_ilist_append(o, NULL, p, _e_kbd_int_cb_dictlist_item_sel,
1532                                    ki, NULL);
1533              free(p);
1534           }
1535         next2:
1536         free(file);
1537      }
1538    e_widget_ilist_thaw(o);
1539    e_widget_ilist_go(o);
1540
1541    e_widget_ilist_preferred_size_get(o, &mw, &mh);
1542    if (mh < (120 *e_scale)) mh = (120 * e_scale);
1543
1544    edje_extern_object_min_size_set(ki->dictlist.ilist_obj, mw, mh);
1545    edje_object_part_swallow(ki->dictlist.base_obj, "e.swallow.content",
1546                             ki->dictlist.ilist_obj);
1547    edje_object_size_min_calc(ki->dictlist.base_obj, &mw, &mh);
1548
1549    e_zone_useful_geometry_get(ki->win->border->zone, NULL, NULL, NULL, &sh);
1550    mw = ki->win->w;
1551    if (mh > (sh - ki->win->h)) mh = (sh - ki->win->h);
1552    e_popup_move_resize(ki->dictlist.popup, 0, ki->win->y - mh, mw, mh);
1553
1554    evas_object_resize(ki->dictlist.base_obj, 
1555                       ki->dictlist.popup->w, ki->dictlist.popup->h);
1556    evas_object_show(ki->dictlist.base_obj);
1557    e_popup_edje_bg_object_set(ki->dictlist.popup, ki->dictlist.base_obj);
1558    e_popup_show(ki->dictlist.popup);
1559    _e_kbd_int_matchlist_down(ki);
1560 }
1561
1562 static void
1563 _e_kbd_int_matchlist_down(E_Kbd_Int *ki)
1564 {
1565    char *str;
1566
1567    if (!ki->matchlist.popup) return;
1568    e_object_del(E_OBJECT(ki->matchlist.popup));
1569    ki->matchlist.popup = NULL;
1570    EINA_LIST_FREE(ki->matchlist.matches, str)
1571      eina_stringshare_del(str);
1572 }
1573
1574 static void
1575 _e_kbd_int_cb_matchlist_item_sel(void *data)
1576 {
1577    E_Kbd_Int *ki;
1578    const char *str;
1579
1580    ki = data;
1581    str = e_widget_ilist_selected_label_get(ki->matchlist.ilist_obj);
1582    _e_kbd_int_string_send(ki, str);
1583    e_kbd_buf_clear(ki->kbuf);
1584    e_kbd_send_keysym_press("space", 0);
1585    if (ki->layout.state & (SHIFT | CTRL | ALT | ALTGR))
1586      {
1587         ki->layout.state &= (~(SHIFT | CTRL | ALT | ALTGR));
1588         _e_kbd_int_layout_state_update(ki);
1589      }
1590    _e_kbd_int_matches_update(ki);
1591    _e_kbd_int_matchlist_down(ki);
1592 }
1593
1594 static void
1595 _e_kbd_int_matchlist_up(E_Kbd_Int *ki)
1596 {
1597    const Eina_List *l;
1598    Evas_Object *o;
1599    Evas_Coord mw, mh, sh;
1600
1601    if (!e_kbd_buf_string_matches_get(ki->kbuf)) return;
1602    if (ki->matchlist.popup) return;
1603    ki->matchlist.popup = e_popup_new(ki->win->border->zone, -1, -1, 1, 1);
1604    e_popup_layer_set(ki->matchlist.popup, 190);
1605
1606    o = _theme_obj_new(ki->matchlist.popup->evas, ki->themedir,
1607                       "e/modules/kbd/match/default");
1608    ki->matchlist.base_obj = o;
1609
1610    o = e_widget_ilist_add(ki->matchlist.popup->evas, 
1611                           (32 * e_scale), (32 * e_scale), NULL);
1612    e_widget_ilist_selector_set(o, 1);
1613    ki->matchlist.ilist_obj = o;
1614    edje_object_part_swallow(ki->matchlist.base_obj, "e.swallow.content", o);
1615    evas_object_show(o);
1616
1617    for (l = e_kbd_buf_string_matches_get(ki->kbuf); l; l = l->next)
1618      {
1619         const char *str;
1620
1621         if (!l->prev)
1622           {
1623              str = e_kbd_buf_actual_string_get(ki->kbuf);
1624              if (str)
1625                {
1626                   str = eina_stringshare_add(str);
1627                   ki->matchlist.matches = eina_list_append(ki->matchlist.matches, str);
1628                   e_widget_ilist_append(o, NULL, str, 
1629                                         _e_kbd_int_cb_matchlist_item_sel,
1630                                         ki, NULL);
1631                }
1632           }
1633         str = l->data;
1634         str = eina_stringshare_add(str);
1635         ki->matchlist.matches = eina_list_append(ki->matchlist.matches, str);
1636         e_widget_ilist_append(o, NULL, str, _e_kbd_int_cb_matchlist_item_sel,
1637                               ki, NULL);
1638      }
1639    e_widget_ilist_thaw(o);
1640    e_widget_ilist_go(o);
1641
1642    e_widget_ilist_preferred_size_get(o, &mw, &mh);
1643    if (mh < (120 *e_scale)) mh = (120 * e_scale);
1644
1645    edje_extern_object_min_size_set(ki->matchlist.ilist_obj, mw, mh);
1646    edje_object_part_swallow(ki->matchlist.base_obj, "e.swallow.content",
1647                                ki->matchlist.ilist_obj);
1648    edje_object_size_min_calc(ki->matchlist.base_obj, &mw, &mh);
1649
1650    edje_extern_object_min_size_set(ki->matchlist.ilist_obj, 0, 0);
1651    edje_object_part_swallow(ki->matchlist.base_obj, "e.swallow.content",
1652                                ki->matchlist.ilist_obj);
1653    e_zone_useful_geometry_get(ki->win->border->zone, NULL, NULL, NULL, &sh);
1654    mw = ki->win->w;
1655    if (mh > (sh - ki->win->h)) mh = (sh - ki->win->h);
1656    e_popup_move_resize(ki->matchlist.popup,
1657                        ki->win->x, ki->win->y - mh, mw, mh);
1658    evas_object_resize(ki->matchlist.base_obj, 
1659                       ki->matchlist.popup->w, ki->matchlist.popup->h);
1660    evas_object_show(ki->matchlist.base_obj);
1661    e_popup_edje_bg_object_set(ki->matchlist.popup, ki->matchlist.base_obj);
1662    e_popup_show(ki->matchlist.popup);
1663
1664    _e_kbd_int_dictlist_down(ki);
1665 }
1666
1667 static void
1668 _e_kbd_int_cb_matches(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1669 {
1670    E_Kbd_Int *ki;
1671
1672    ki = data;
1673    if (ki->dictlist.popup) _e_kbd_int_dictlist_down(ki);
1674    else if (ki->matchlist.popup) _e_kbd_int_matchlist_down(ki);
1675    else
1676      {
1677         if (!e_kbd_buf_actual_string_get(ki->kbuf))
1678           _e_kbd_int_dictlist_up(ki);
1679         else
1680           _e_kbd_int_matchlist_up(ki);
1681      }
1682 }
1683
1684 static void
1685 _e_kbd_int_cb_dicts(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1686 {
1687    E_Kbd_Int *ki;
1688
1689    ki = data;
1690    if (ki->dictlist.popup) _e_kbd_int_dictlist_down(ki);
1691    else _e_kbd_int_dictlist_up(ki);
1692 }
1693
1694 static void
1695 _e_kbd_int_cb_layouts(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
1696 {
1697    E_Kbd_Int *ki;
1698
1699    ki = data;
1700    _e_kbd_int_layout_next(ki);
1701 }
1702
1703 static void
1704 _e_kbd_int_cb_resize(E_Win *win)
1705 {
1706    E_Kbd_Int *ki;
1707    E_Kbd_Int_Key *ky;
1708    Eina_List *l;
1709    
1710    ki = win->data;
1711    EINA_LIST_FOREACH(ki->layout.keys, l, ky)
1712      {
1713            if (ky->obj) evas_object_del(ky->obj);
1714            if (ky->icon_obj) evas_object_del(ky->icon_obj);
1715      }
1716    if (ki->event_obj) evas_object_del(ki->event_obj);
1717    ki->event_obj = NULL;
1718    
1719    _e_kbd_int_layout_build(ki);
1720    _e_kbd_int_layout_buf_update(ki);
1721    _e_kbd_int_layout_state_update(ki);
1722 }
1723
1724 EAPI E_Kbd_Int *
1725 e_kbd_int_new(const char *themedir, const char *syskbds, const char *sysdicts)
1726 {
1727    E_Kbd_Int *ki;
1728    Evas_Object *o;
1729    Evas_Coord mw, mh;
1730    E_Zone *zone;
1731    E_Kbd_Int_Layout *kil;
1732    Ecore_X_Window_State states[2];
1733
1734    ki = E_NEW(E_Kbd_Int, 1);
1735    if (!ki) return NULL;
1736    if (themedir) ki->themedir = eina_stringshare_add(themedir);
1737    if (syskbds) ki->syskbds = eina_stringshare_add(syskbds);
1738    if (sysdicts) ki->sysdicts = eina_stringshare_add(sysdicts);
1739    zone = e_util_zone_current_get(e_manager_current_get());
1740    ki->win = e_win_new(zone->container);
1741    states[0] = ECORE_X_WINDOW_STATE_SKIP_TASKBAR;
1742    states[1] = ECORE_X_WINDOW_STATE_SKIP_PAGER;
1743    ecore_x_netwm_window_state_set(ki->win->evas_win, states, 2);
1744    ecore_x_icccm_hints_set(ki->win->evas_win, 0, 0, 0, 0, 0, 0, 0);
1745    e_win_no_remember_set(ki->win, 1);
1746
1747    mw = zone->w;
1748    mh = zone->h;
1749
1750    if (mw > mh)
1751      e_win_resize(ki->win, mw, (mh / 2));
1752    else
1753      e_win_resize(ki->win, mw, mh);
1754
1755    e_win_resize_callback_set(ki->win, _e_kbd_int_cb_resize);
1756    e_win_borderless_set(ki->win, 1);
1757    ki->win->data = ki;
1758    e_win_name_class_set(ki->win, "Virtual-Keyboard", "Virtual-Keyboard");
1759    e_win_title_set(ki->win, "Virtual Keyboard");
1760
1761    ki->base_obj = _theme_obj_new(ki->win->evas, ki->themedir,
1762                                  "e/modules/kbd/base/default");
1763    edje_object_signal_callback_add(ki->base_obj, "e,action,do,matches", "",
1764                                    _e_kbd_int_cb_matches, ki);
1765    edje_object_signal_callback_add(ki->base_obj, "e,action,do,layouts", "",
1766                                    _e_kbd_int_cb_layouts, ki);
1767    edje_object_signal_callback_add(ki->base_obj, "e,action,do,dicts", "",
1768                                    _e_kbd_int_cb_dicts, ki);
1769
1770    o = e_layout_add(ki->win->evas);
1771    edje_object_part_swallow(ki->base_obj, "e.swallow.content", o);
1772    evas_object_show(o);
1773    ki->layout_obj = o;
1774
1775    o = e_icon_add(ki->win->evas);
1776    evas_object_pass_events_set(o, 1);
1777    e_icon_fill_inside_set(o, 1);
1778    e_icon_scale_up_set(o, 0);
1779    edje_object_part_swallow(ki->base_obj, "e.swallow.layout", o);
1780    evas_object_show(o);
1781    ki->icon_obj = o;
1782
1783    o = e_box_add(ki->win->evas);   
1784    e_box_orientation_set(o, 1);
1785    e_box_homogenous_set(o, 1);
1786    edje_object_part_swallow(ki->base_obj, "e.swallow.label", o);
1787    evas_object_show(o);
1788    ki->box_obj = o;
1789
1790    if (il_kbd_cfg->dict)
1791      ki->kbuf = e_kbd_buf_new(ki->sysdicts, il_kbd_cfg->dict);
1792    else
1793      ki->kbuf = e_kbd_buf_new(ki->sysdicts, "English_(US).dic");
1794
1795    _e_kbd_int_layouts_list_update(ki);
1796
1797    kil = _e_kbd_int_layouts_list_default_get(ki);
1798    if ((!kil) && (ki->layouts))
1799      kil = ki->layouts->data;
1800
1801    if (kil) _e_kbd_int_layout_select(ki, kil);
1802
1803    edje_object_size_min_calc(ki->base_obj, &mw, &mh);
1804    if (mw < 48) mw = 48;
1805    if (mh < 48) mh = 48;
1806    evas_object_move(ki->base_obj, 0, 0);
1807    evas_object_resize(ki->base_obj, zone->w, mh);
1808    evas_object_show(ki->base_obj);
1809    
1810    e_win_size_min_set(ki->win, mw, mh);
1811    ecore_x_e_virtual_keyboard_set(ki->win->evas_win, 1);
1812
1813    ki->client_message_handler = 
1814      ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, 
1815                              _e_kbd_int_cb_client_message, ki);
1816    ki->kbd_move_hdl = 
1817      ecore_event_handler_add(E_EVENT_BORDER_MOVE, 
1818                              _e_kbd_int_cb_border_move, ki);
1819
1820    e_win_show(ki->win);
1821    ki->win->border->user_skip_winlist = 1;
1822    ki->win->border->lock_focus_in = 1;
1823    ki->win->border->lock_focus_out = 1;
1824
1825    return ki;
1826 }
1827
1828 EAPI void
1829 e_kbd_int_free(E_Kbd_Int *ki)
1830 {
1831    if (ki->themedir) eina_stringshare_del(ki->themedir);
1832    if (ki->syskbds) eina_stringshare_del(ki->syskbds);
1833    if (ki->sysdicts) eina_stringshare_del(ki->sysdicts);
1834    _e_kbd_int_layouts_free(ki);
1835    _e_kbd_int_matches_free(ki);
1836    _e_kbd_int_layout_free(ki);
1837    ecore_event_handler_del(ki->client_message_handler);
1838    ecore_event_handler_del(ki->kbd_move_hdl);
1839    if (ki->down.hold_timer) ecore_timer_del(ki->down.hold_timer);
1840    _e_kbd_int_matchlist_down(ki);
1841    _e_kbd_int_zoomkey_down(ki);
1842    e_kbd_buf_free(ki->kbuf);
1843    e_object_del(E_OBJECT(ki->win));
1844    E_FREE(ki);
1845 }
1846
1847 static Evas_Object *
1848 _theme_obj_new(Evas *e, const char *custom_dir, const char *group)
1849 {
1850    Evas_Object *o;
1851
1852    o = edje_object_add(e);
1853    if (!e_theme_edje_object_set(o, "base/theme/modules/illume", group))
1854      {
1855         if (custom_dir)
1856           {
1857              char buf[PATH_MAX];
1858
1859              snprintf(buf, sizeof(buf), "%s/e-module-illume-keyboard.edj", 
1860                       custom_dir);
1861              edje_object_file_set(o, buf, group);
1862           }
1863      }
1864    return o;
1865 }
1866
1867 static Eina_Bool
1868 _e_kbd_int_cb_border_move(void *data, int type __UNUSED__, void *event) 
1869 {
1870    E_Event_Border_Move *ev;
1871    E_Kbd_Int *ki;
1872
1873    ev = event;
1874    if (!(ki = data)) return ECORE_CALLBACK_PASS_ON;
1875    if (ki->win->border != ev->border) return ECORE_CALLBACK_PASS_ON;
1876    _e_kbd_int_zoomkey_down(ki);
1877    _e_kbd_int_matchlist_down(ki);
1878    _e_kbd_int_dictlist_down(ki);
1879    return ECORE_CALLBACK_PASS_ON;
1880 }