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