Add a task to copy configuration files to user's HOME dir from data dir for multi...
[platform/core/uifw/e17.git] / src / modules / illume-keyboard / e_kbd_buf.c
1 #include "e.h"
2 #include "e_kbd_buf.h"
3 #include "e_kbd_dict.h"
4
5 static E_Kbd_Buf_Layout *
6 _e_kbd_buf_new(void)
7 {
8    E_Kbd_Buf_Layout *kbl;
9    
10    kbl = E_NEW(E_Kbd_Buf_Layout, 1);
11    kbl->ref =1;
12    return kbl;
13 }
14
15 static void
16 _e_kbd_buf_layout_ref(E_Kbd_Buf_Layout *kbl)
17 {
18    kbl->ref++;
19 }
20
21 static void
22 _e_kbd_buf_layout_unref(E_Kbd_Buf_Layout *kbl)
23 {
24    kbl->ref--;
25    if (kbl->ref > 0) return;
26    while (kbl->keys)
27      {
28         E_Kbd_Buf_Key *ky;
29         
30         ky = kbl->keys->data;
31         if (ky->key) eina_stringshare_del(ky->key);
32         if (ky->key_shift) eina_stringshare_del(ky->key_shift);
33         if (ky->key_capslock) eina_stringshare_del(ky->key_capslock);
34         free(ky);
35         kbl->keys = eina_list_remove_list(kbl->keys, kbl->keys);
36      }
37    free(kbl);
38 }
39
40 static void
41 _e_kbd_buf_string_matches_clear(E_Kbd_Buf *kb)
42 {
43    while (kb->string_matches)
44      {
45         if (kb->string_matches->data)
46           eina_stringshare_del(kb->string_matches->data);
47         kb->string_matches = eina_list_remove_list(kb->string_matches, kb->string_matches);
48      }
49 }
50
51 static void
52 _e_kbd_buf_actual_string_clear(E_Kbd_Buf *kb)
53 {
54    if (kb->actual_string) eina_stringshare_del(kb->actual_string);
55    kb->actual_string = NULL;
56 }
57
58 static E_Kbd_Buf_Key *
59 _e_kbd_buf_at_coord_get(E_Kbd_Buf *kb __UNUSED__, E_Kbd_Buf_Layout *kbl, int x, int y)
60 {
61    Eina_List *l;
62    
63    for (l = kbl->keys; l; l = l->next)
64      {
65         E_Kbd_Buf_Key *ky;
66         
67         ky = l->data;
68         if (ky->key)
69           {
70              if ((x >= ky->x) && (y >= ky->y) &&
71                  (x < (ky->x + ky->w)) && (y < (ky->y + ky->h)))
72                return ky;
73           }
74      }
75    return NULL;
76 }
77
78 static E_Kbd_Buf_Key *
79 _e_kbd_buf_closest_get(E_Kbd_Buf *kb __UNUSED__, E_Kbd_Buf_Layout *kbl, int x, int y)
80 {
81    Eina_List *l;
82    E_Kbd_Buf_Key *ky_closest = NULL;
83    int dist_closest = 0x7fffffff;
84    
85    for (l = kbl->keys; l; l = l->next)
86      {
87         E_Kbd_Buf_Key *ky;
88         int dist, dx, dy;
89         
90         ky = l->data;
91         if (ky->key)
92           {
93              dx = x - (ky->x + (ky->w / 2));
94              dy = y - (ky->y + (ky->h / 2));
95              dist = (dx * dx) + (dy * dy);
96              if (dist < dist_closest)
97                {
98                   ky_closest = ky;
99                   dist_closest = dist;
100                }
101           }
102      }
103    return ky_closest;
104 }
105
106 static const char *
107 _e_kbd_buf_keystroke_key_string_get(E_Kbd_Buf *kb __UNUSED__, E_Kbd_Buf_Keystroke *ks, E_Kbd_Buf_Key *ky)
108 {
109    const char *str = NULL;
110    
111    if ((ky) && (ky->key))
112      {
113         if (ks->shift)
114           {
115              if (ky->key_shift) str = ky->key_shift;
116              else str = ky->key;
117           }
118         else if (ks->capslock)
119           {
120              if (ky->key_capslock) str = ky->key_capslock;
121              else str = ky->key;
122           }
123         else str = ky->key;
124      }
125    return str;
126 }
127
128 static const char *
129 _e_kbd_buf_keystroke_string_get(E_Kbd_Buf *kb, E_Kbd_Buf_Keystroke *ks)
130 {
131    const char *str = NULL;
132    
133    if (ks->key) str = ks->key;
134    else
135      {
136         E_Kbd_Buf_Key *ky;
137         
138         ky = _e_kbd_buf_at_coord_get(kb, ks->layout, ks->x, ks->y);
139         if (!ky) ky = _e_kbd_buf_closest_get(kb, ks->layout, ks->x, ks->y);
140         str = _e_kbd_buf_keystroke_key_string_get(kb, ks, ky);
141      }
142    return str;
143 }
144
145 static void
146 _e_kbd_buf_actual_string_update(E_Kbd_Buf *kb)
147 {
148    Eina_List *l;
149    char *actual = NULL;
150    int actual_len = 0;
151    unsigned int actual_size = 0;
152    E_Kbd_Buf_Keystroke *ks;
153    
154    _e_kbd_buf_actual_string_clear(kb);
155    EINA_LIST_FOREACH(kb->keystrokes, l, ks)
156      {
157         const char *str;
158         
159         str = _e_kbd_buf_keystroke_string_get(kb, ks);
160         if (!str) continue;
161         if (!actual) actual_size += 64, actual = malloc(actual_size);
162         else if ((actual_len + strlen(str) + 1) > actual_size)
163           {
164              actual_size += 64;
165              actual = realloc(actual, actual_size);
166           }
167         strcpy(actual + actual_len, str);
168         actual_len += strlen(str);
169      }
170    kb->actual_string = eina_stringshare_add(actual);
171    free(actual);
172 }
173
174 static const char *
175 _e_kbd_buf_matches_find(Eina_List *matches, const char *s)
176 {
177    Eina_List *l;
178    
179    for (l = matches; l; l = l->next)
180      {
181         if (!strcmp(l->data, s)) return s;
182      }
183    return NULL;
184 }
185
186 static void
187 _e_kbd_buf_matches_update(E_Kbd_Buf *kb)
188 {
189    const char *word;
190    int pri, i;
191    E_Kbd_Dict *dicts[3];
192
193    _e_kbd_buf_string_matches_clear(kb);
194    dicts[0] = kb->dict.personal;
195    dicts[1] = kb->dict.sys;
196    dicts[2] = kb->dict.data;
197    for (i = 0; i < 3; i++)
198      {
199         if (!dicts[i]) continue;
200         e_kbd_dict_matches_lookup(dicts[i]);
201         e_kbd_dict_matches_first(dicts[i]);
202         for (;;)
203           {
204              word = e_kbd_dict_matches_match_get(dicts[i], &pri);
205              if (!word) break;
206              if (!_e_kbd_buf_matches_find(kb->string_matches, word))
207                kb->string_matches = eina_list_append(kb->string_matches,
208                                                      eina_stringshare_add(word));
209              e_kbd_dict_matches_next(dicts[i]);
210           }
211      }
212 }
213
214 static Eina_Bool
215 _e_kbd_buf_cb_data_dict_reload(void *data)
216 {
217    E_Kbd_Buf *kb;
218    char buf[PATH_MAX];
219
220    kb = data;
221    kb->dict.data_reload_delay = NULL;
222    e_kbd_buf_clear(kb);
223    if (kb->dict.data) e_kbd_dict_free(kb->dict.data);
224    e_user_dir_concat_static(buf, "dicts-dynamic/data.dic");
225    kb->dict.data = e_kbd_dict_new(buf);
226    return ECORE_CALLBACK_CANCEL;
227 }
228
229 static void
230 _e_kbd_buf_cb_data_dict_change(void *data, Ecore_File_Monitor *em __UNUSED__, Ecore_File_Event event __UNUSED__, const char *path __UNUSED__)
231 {
232    E_Kbd_Buf *kb;
233    
234    kb = data;
235    if (kb->dict.data_reload_delay) ecore_timer_del(kb->dict.data_reload_delay);
236    kb->dict.data_reload_delay = ecore_timer_add(2.0, _e_kbd_buf_cb_data_dict_reload, kb);
237 }
238     
239 EAPI E_Kbd_Buf *
240 e_kbd_buf_new(const char *sysdicts, const char *dict)
241 {
242    E_Kbd_Buf *kb;
243    char buf[PATH_MAX];
244
245    kb = E_NEW(E_Kbd_Buf, 1);
246    if (!kb) return NULL;
247    kb->sysdicts = eina_stringshare_add(sysdicts);
248
249    e_user_dir_concat_static(buf, "dicts");
250    if (!ecore_file_exists(buf)) ecore_file_mkpath(buf);
251
252    e_user_dir_snprintf(buf, sizeof(buf), "dicts/%s", dict);
253    kb->dict.sys = e_kbd_dict_new(buf);
254    if (!kb->dict.sys)
255      {
256         snprintf(buf, sizeof(buf), "%s/dicts/%s", kb->sysdicts, dict);
257         kb->dict.sys = e_kbd_dict_new(buf);
258      }
259
260    e_user_dir_concat_static(buf, "dicts-dynamic");
261    if (!ecore_file_exists(buf)) ecore_file_mkpath(buf);
262
263    e_user_dir_concat_static(buf, "dicts-dynamic/personal.dic");
264    kb->dict.personal = e_kbd_dict_new(buf);
265    if (!kb->dict.personal)
266      {
267         FILE *f;
268         
269         f = fopen(buf, "w");
270         if (f)
271           {
272              fprintf(f, "\n");
273              fclose(f);
274           }
275         kb->dict.personal = e_kbd_dict_new(buf);
276      }
277    e_user_dir_concat_static(buf, "dicts-dynamic/data.dic");
278    kb->dict.data = e_kbd_dict_new(buf);
279    kb->dict.data_monitor = 
280      ecore_file_monitor_add(buf, _e_kbd_buf_cb_data_dict_change, kb);
281    return kb;
282 }
283
284 EAPI void
285 e_kbd_buf_free(E_Kbd_Buf *kb)
286 {
287    e_kbd_buf_clear(kb);
288    e_kbd_buf_layout_clear(kb);
289    e_kbd_buf_lookup_cancel(kb);
290    eina_stringshare_del(kb->sysdicts);
291    if (kb->dict.sys) e_kbd_dict_free(kb->dict.sys);
292    if (kb->dict.personal) e_kbd_dict_free(kb->dict.personal);
293    if (kb->dict.data) e_kbd_dict_free(kb->dict.data);
294    if (kb->dict.data_monitor) ecore_file_monitor_del(kb->dict.data_monitor);
295    if (kb->dict.data_reload_delay) ecore_timer_del(kb->dict.data_reload_delay);
296    free(kb);
297 }
298
299 EAPI void
300 e_kbd_buf_dict_set(E_Kbd_Buf *kb, const char *dict)
301 {
302    char buf[PATH_MAX];
303
304    e_kbd_buf_clear(kb);
305
306    if (kb->dict.sys) e_kbd_dict_free(kb->dict.sys);
307
308    e_user_dir_concat_static(buf, "dicts");
309    if (!ecore_file_exists(buf)) ecore_file_mkpath(buf);
310
311    e_user_dir_snprintf(buf, sizeof(buf), "dicts/%s", dict);
312    kb->dict.sys = e_kbd_dict_new(buf);
313    if (!kb->dict.sys)
314      {
315         snprintf(buf, sizeof(buf), "%s/dicts/%s", kb->sysdicts, dict);
316         kb->dict.sys = e_kbd_dict_new(buf);
317      }
318 }
319
320 EAPI void
321 e_kbd_buf_clear(E_Kbd_Buf *kb)
322 {
323    e_kbd_buf_lookup_cancel(kb);
324    while (kb->keystrokes)
325      {
326         E_Kbd_Buf_Keystroke *ks;
327         
328         ks = kb->keystrokes->data;
329         if (ks->key) eina_stringshare_del(ks->key);
330         _e_kbd_buf_layout_unref(ks->layout);
331         free(ks);
332         kb->keystrokes = eina_list_remove_list(kb->keystrokes, kb->keystrokes);
333      }
334    _e_kbd_buf_string_matches_clear(kb);
335    if (kb->dict.sys) e_kbd_dict_word_letter_clear(kb->dict.sys);
336    if (kb->dict.personal) e_kbd_dict_word_letter_clear(kb->dict.personal);
337    if (kb->dict.data) e_kbd_dict_word_letter_clear(kb->dict.data);
338    _e_kbd_buf_actual_string_clear(kb);
339 }
340
341 EAPI void
342 e_kbd_buf_layout_clear(E_Kbd_Buf *kb)
343 {
344    if (kb->layout)
345      {
346         _e_kbd_buf_layout_unref(kb->layout);
347         kb->layout = NULL;
348      }
349 }
350
351 EAPI void
352 e_kbd_buf_layout_size_set(E_Kbd_Buf *kb, int w, int h)
353 {
354    if (!kb->layout) kb->layout = _e_kbd_buf_new();
355    if (!kb->layout) return;
356    kb->layout->w = w;
357    kb->layout->h = h;
358 }
359
360 EAPI void
361 e_kbd_buf_layout_fuzz_set(E_Kbd_Buf *kb, int fuzz)
362 {
363    if (!kb->layout) kb->layout = _e_kbd_buf_new();
364    if (!kb->layout) return;
365    kb->layout->fuzz = fuzz;
366 }
367
368 EAPI void
369 e_kbd_buf_layout_key_add(E_Kbd_Buf *kb, const char *key,  const char *key_shift, const char *key_capslock, int x, int y, int w, int h)
370 {
371    E_Kbd_Buf_Key *ky;
372
373    if (!key) return;
374    if (!kb->layout) kb->layout = _e_kbd_buf_new();
375    if (!kb->layout) return;
376    ky = E_NEW(E_Kbd_Buf_Key, 1);
377    if (!ky) return;
378    ky->key = eina_stringshare_add(key);
379    if (key_shift) ky->key_shift = eina_stringshare_add(key_shift);
380    if (key_capslock) ky->key_capslock = eina_stringshare_add(key_capslock);
381    ky->x = x;
382    ky->y = y;
383    ky->w = w;
384    ky->h = h;
385    kb->layout->keys = eina_list_append(kb->layout->keys, ky);
386 }
387
388 static void
389 _e_kbd_buf_keystroke_add(E_Kbd_Buf *kb, E_Kbd_Buf_Keystroke *ks)
390 {
391    const char *str;
392
393    str = _e_kbd_buf_keystroke_string_get(kb, ks);
394    if (str)
395      {
396         if (kb->dict.sys) e_kbd_dict_word_letter_add(kb->dict.sys, str, 0);
397         if (kb->dict.personal) e_kbd_dict_word_letter_add(kb->dict.personal, str, 0);
398         if (kb->dict.data) e_kbd_dict_word_letter_add(kb->dict.data, str, 0);
399      }
400 }
401
402 EAPI void
403 e_kbd_buf_pressed_key_add(E_Kbd_Buf *kb, const char *key, int shift, int capslock)
404 {
405    E_Kbd_Buf_Keystroke *ks;
406
407    e_kbd_buf_lookup_cancel(kb);
408    if (!key) return;
409    if (!kb->layout) kb->layout = _e_kbd_buf_new();
410    if (!kb->layout) return;
411    ks = E_NEW(E_Kbd_Buf_Keystroke, 1);
412    if (!ks) return;
413    ks->key = eina_stringshare_add(key);
414    if (shift) ks->shift = 1;
415    if (capslock) ks->capslock = 1;
416    ks->layout = kb->layout;
417    _e_kbd_buf_layout_ref(ks->layout);
418    kb->keystrokes = eina_list_append(kb->keystrokes, ks);
419    
420    if (kb->dict.sys) e_kbd_dict_word_letter_advance(kb->dict.sys);
421    if (kb->dict.personal) e_kbd_dict_word_letter_advance(kb->dict.personal);
422    if (kb->dict.data) e_kbd_dict_word_letter_advance(kb->dict.data);
423    _e_kbd_buf_keystroke_add(kb, ks);
424    
425    _e_kbd_buf_actual_string_update(kb);
426    _e_kbd_buf_matches_update(kb);
427 }
428
429 static void
430 _e_kbd_buf_keystroke_point_add(E_Kbd_Buf *kb, E_Kbd_Buf_Keystroke *ks)
431 {
432    Eina_List *l;
433    
434    for (l = ks->layout->keys; l; l = l->next)
435      {
436         E_Kbd_Buf_Key *ky;
437         const char *str;
438         int px, py, dx, dy, d;
439
440         ky = l->data;
441         px = ky->x + (ky->w / 2);
442         py = ky->y + (ky->h / 2);
443         dx = ks->x - px;
444         dy = ks->y - py;
445         d = sqrt((dx * dx) + (dy * dy));
446         if (d <= ks->layout->fuzz)
447           {
448              str = _e_kbd_buf_keystroke_key_string_get(kb, ks, ky);
449              if (str)
450                {
451                   if (kb->dict.sys) e_kbd_dict_word_letter_add(kb->dict.sys, str, d);
452                   if (kb->dict.personal) e_kbd_dict_word_letter_add(kb->dict.personal, str, d);
453                   if (kb->dict.data) e_kbd_dict_word_letter_add(kb->dict.data, str, d);
454                }
455           }
456      }
457 }
458
459 EAPI void
460 e_kbd_buf_pressed_point_add(E_Kbd_Buf *kb, int x, int y, int shift, int capslock)
461 {
462    E_Kbd_Buf_Keystroke *ks;
463    
464    e_kbd_buf_lookup_cancel(kb);
465    if (!kb->layout) kb->layout = _e_kbd_buf_new();
466    if (!kb->layout) return;
467    ks = E_NEW(E_Kbd_Buf_Keystroke, 1);
468    if (!ks) return;
469    ks->x = x;
470    ks->y = y;
471    if (shift) ks->shift = 1;
472    if (capslock) ks->capslock = 1;
473    ks->layout = kb->layout;
474    _e_kbd_buf_layout_ref(ks->layout);
475    kb->keystrokes = eina_list_append(kb->keystrokes, ks);
476    
477    if (kb->dict.sys) e_kbd_dict_word_letter_advance(kb->dict.sys);
478    if (kb->dict.personal) e_kbd_dict_word_letter_advance(kb->dict.personal);
479    if (kb->dict.data) e_kbd_dict_word_letter_advance(kb->dict.data);
480    
481    _e_kbd_buf_keystroke_point_add(kb, ks);
482    
483    _e_kbd_buf_actual_string_update(kb);
484    _e_kbd_buf_matches_update(kb);
485 }
486
487 EAPI const char *
488 e_kbd_buf_actual_string_get(E_Kbd_Buf *kb)
489 {
490    return kb->actual_string;
491 }
492
493 EAPI const Eina_List *
494 e_kbd_buf_string_matches_get(E_Kbd_Buf *kb)
495 {
496    return kb->string_matches;
497 }
498
499 EAPI void
500 e_kbd_buf_backspace(E_Kbd_Buf *kb)
501 {
502    Eina_List *l;
503    
504    l = eina_list_last(kb->keystrokes);
505    if (l)
506      {
507         E_Kbd_Buf_Keystroke *ks;
508         
509         ks = l->data;
510         if (ks->key) eina_stringshare_del(ks->key);
511         _e_kbd_buf_layout_unref(ks->layout);
512         free(ks);
513         kb->keystrokes = eina_list_remove_list(kb->keystrokes, l);
514         if (kb->dict.sys) e_kbd_dict_word_letter_delete(kb->dict.sys);
515         if (kb->dict.personal) e_kbd_dict_word_letter_delete(kb->dict.personal);
516         if (kb->dict.data) e_kbd_dict_word_letter_delete(kb->dict.data);
517         _e_kbd_buf_actual_string_update(kb);
518         _e_kbd_buf_matches_update(kb);
519      }
520 }
521
522 EAPI void
523 e_kbd_buf_word_use(E_Kbd_Buf *kb, const char *word)
524 {
525    if (kb->dict.personal)
526      e_kbd_dict_word_usage_adjust(kb->dict.personal, word, 1);
527 }
528
529 // FIXME: just faking delayed lookup with timer
530 static Eina_Bool
531 _e_kbd_buf_cb_faket(void *data)
532 {
533    E_Kbd_Buf *kb;
534    
535    kb = data;
536    kb->lookup.faket = NULL;
537    kb->lookup.func((void *)kb->lookup.data);
538    kb->lookup.func = NULL;
539    kb->lookup.data = NULL;
540    return ECORE_CALLBACK_CANCEL;
541 }
542
543 EAPI void
544 e_kbd_buf_lookup(E_Kbd_Buf *kb, void (*func) (void *data), const void *data)
545 {
546    e_kbd_buf_lookup_cancel(kb);
547    
548    kb->lookup.func = func;
549    kb->lookup.data = data;
550
551    // FIXME: just faking delayed lookup with timer
552    kb->lookup.faket = ecore_timer_add(0.1, _e_kbd_buf_cb_faket, kb);
553 }
554
555 EAPI void
556 e_kbd_buf_lookup_cancel(E_Kbd_Buf *kb)
557 {
558    // FIXME: just faking delayed lookup with timer
559    if (!kb->lookup.faket) return;
560    ecore_timer_del(kb->lookup.faket);
561    kb->lookup.faket = NULL;
562    
563    kb->lookup.func = NULL;
564    kb->lookup.data = NULL;
565 }