Elm glayer: Changed config to enable zoom/rotate finger by default.
[framework/uifw/elementary.git] / src / lib / elm_config.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #ifdef HAVE_EVIL
6 # include <Evil.h>
7 #endif
8
9 #include <Elementary.h>
10 #include "elm_priv.h"
11
12 EAPI int ELM_EVENT_CONFIG_ALL_CHANGED = 0;
13
14 Elm_Config *_elm_config = NULL;
15 char *_elm_profile = NULL;
16 static Eet_Data_Descriptor *_config_edd = NULL;
17 static Eet_Data_Descriptor *_config_font_overlay_edd = NULL;
18
19 static Ecore_Poller *_elm_cache_flush_poller = NULL;
20
21 const char *_elm_engines[] = {
22    "software_x11",
23    "fb",
24    "directfb",
25    "software_16_x11",
26    "software_8_x11",
27    "xrender_x11",
28    "opengl_x11",
29    "software_gdi",
30    "software_16_wince_gdi",
31    "sdl",
32    "software_16_sdl",
33    "opengl_sdl",
34    "buffer",
35    "ews",
36    "opengl_cocoa",
37    "psl1ght",
38    NULL
39 };
40
41 /* whenever you want to add a new text class support into Elementary,
42    declare it both here and in the (default) theme */
43 static const Elm_Text_Class _elm_text_classes[] = {
44    {"button", "Button Labels"},
45    {"label", "Text Labels"},
46    {"entry", "Text Entries"},
47    {"title_bar", "Title Bar"},
48    {"list_item", "List Items"},
49    {"grid_item", "Grid Items"},
50    {"toolbar_item", "Toolbar Items"},
51    {"menu_item", "Menu Items"},
52    {NULL, NULL}
53 };
54
55 static void        _desc_init(void);
56 static void        _desc_shutdown(void);
57 static void        _profile_fetch_from_conf(void);
58 static void        _config_free(void);
59 static void        _config_apply(void);
60 static Elm_Config *_config_user_load(void);
61 static Elm_Config *_config_system_load(void);
62 static void        _config_load(void);
63 static void        _config_update(void);
64 static void        _env_get(void);
65 static size_t      _elm_data_dir_snprintf(char       *dst,
66                                           size_t      size,
67                                           const char *fmt, ...)
68                                           EINA_PRINTF(3, 4);
69 static size_t _elm_user_dir_snprintf(char       *dst,
70                                      size_t      size,
71                                      const char *fmt, ...)
72                                      EINA_PRINTF(3, 4);
73
74 #define ELM_CONFIG_VAL(edd, type, member, dtype) \
75   EET_DATA_DESCRIPTOR_ADD_BASIC(edd, type, #member, member, dtype)
76 #define ELM_CONFIG_LIST(edd, type, member, eddtype) \
77   EET_DATA_DESCRIPTOR_ADD_LIST(edd, type, #member, member, eddtype)
78
79 #ifdef HAVE_ELEMENTARY_X
80 static Ecore_Event_Handler *_prop_change_handler = NULL;
81 static Ecore_Timer *_prop_all_update_timer = NULL;
82 static Ecore_Timer *_prop_change_delay_timer = NULL;
83 static Ecore_X_Window _root_1st = 0;
84 #define ATOM_COUNT 2
85 static Ecore_X_Atom _atom[ATOM_COUNT];
86 static Ecore_X_Atom _atom_config = 0;
87 static const char *_atom_names[ATOM_COUNT] =
88 {
89    "ELM_PROFILE",
90    "ELM_CONFIG"
91 };
92 #define ATOM_E_PROFILE                              0
93 #define ATOM_E_CONFIG                               1
94
95 static Eina_Bool _prop_all_update_cb(void *data __UNUSED__);
96 static Eina_Bool _prop_config_get(void);
97 static void      _prop_config_set(void);
98 static Eina_Bool _prop_change(void *data  __UNUSED__,
99                               int ev_type __UNUSED__,
100                               void       *ev);
101
102 static Eina_Bool
103 _prop_all_update_cb(void *data __UNUSED__)
104 {
105    _prop_config_set();
106    ecore_x_window_prop_string_set(_root_1st, _atom[ATOM_E_PROFILE],
107                                   _elm_profile);
108    _prop_all_update_timer = NULL;
109    return EINA_FALSE;
110 }
111
112 static Eina_Bool
113 _prop_config_get(void)
114 {
115    int size = 0;
116    Ecore_X_Atom atom;
117    char buf[512];
118    unsigned char *data = NULL;
119    Elm_Config *config_data;
120
121    snprintf(buf, sizeof(buf), "ELM_CONFIG_%s", _elm_profile);
122    atom = ecore_x_atom_get(buf);
123    _atom_config = atom;
124    if (!ecore_x_window_prop_property_get(_root_1st,
125                                          atom, _atom[ATOM_E_CONFIG],
126                                          8, &data, &size))
127      {
128         if (!ecore_x_window_prop_property_get(_root_1st,
129                                               _atom[ATOM_E_CONFIG],
130                                               _atom[ATOM_E_CONFIG],
131                                               8, &data, &size))
132           return EINA_FALSE;
133         else
134           _atom_config = _atom[ATOM_E_CONFIG];
135      }
136    else
137      _atom_config = atom;
138    if (size < 1)
139      {
140         free(data);
141         return EINA_FALSE;
142      }
143    config_data = eet_data_descriptor_decode(_config_edd, data, size);
144    free(data);
145    if (!config_data) return EINA_FALSE;
146
147    /* What do we do on version mismatch when someone changes the
148     * config in the rootwindow? */
149    /* Most obvious case, new version and we are still linked to
150     * whatever was there before, we just ignore until user restarts us */
151    if (config_data->config_version > ELM_CONFIG_VERSION)
152      return EINA_TRUE;
153    /* What in the case the version is older? Do we even support those
154     * cases or we only check for equality above? */
155
156    _config_free();
157    _elm_config = config_data;
158    _config_apply();
159    _elm_config_font_overlay_apply();
160    _elm_rescale();
161    _elm_recache();
162    ecore_event_add(ELM_EVENT_CONFIG_ALL_CHANGED, NULL, NULL, NULL);
163    return EINA_TRUE;
164 }
165
166 static void
167 _prop_config_set(void)
168 {
169    unsigned char *config_data = NULL;
170    int size = 0;
171
172    config_data = eet_data_descriptor_encode(_config_edd, _elm_config, &size);
173    if (config_data)
174      {
175         Ecore_X_Atom atom;
176         char buf[512];
177
178         snprintf(buf, sizeof(buf), "ELM_CONFIG_%s", _elm_profile);
179         atom = ecore_x_atom_get(buf);
180         _atom_config = atom;
181
182         ecore_x_window_prop_property_set(_root_1st, _atom_config,
183                                          _atom[ATOM_E_CONFIG], 8,
184                                          config_data, size);
185         free(config_data);
186      }
187 }
188
189 static Eina_Bool
190 _prop_change_delay_cb(void *data __UNUSED__)
191 {
192    char *s;
193
194    s = ecore_x_window_prop_string_get(_root_1st, _atom[ATOM_E_PROFILE]);
195    if (s)
196      {
197         if (_elm_profile) free(_elm_profile);
198         _elm_profile = s;
199      }
200    _prop_config_get();
201    _prop_change_delay_timer = NULL;
202    return EINA_FALSE;
203 }
204
205 static Eina_Bool
206 _prop_change(void *data  __UNUSED__,
207              int ev_type __UNUSED__,
208              void       *ev)
209 {
210    Ecore_X_Event_Window_Property *event = ev;
211
212    if (event->win == _root_1st)
213      {
214         if (event->atom == _atom[ATOM_E_PROFILE])
215           {
216              if (_prop_change_delay_timer) ecore_timer_del(_prop_change_delay_timer);
217              _prop_change_delay_timer = ecore_timer_add(0.1, _prop_change_delay_cb, NULL);
218           }
219         else if (((_atom_config > 0) && (event->atom == _atom_config)) ||
220                  (event->atom == _atom[ATOM_E_CONFIG]))
221           {
222              if (_prop_change_delay_timer) ecore_timer_del(_prop_change_delay_timer);
223              _prop_change_delay_timer = ecore_timer_add(0.1, _prop_change_delay_cb, NULL);
224           }
225      }
226    return ECORE_CALLBACK_PASS_ON;
227 }
228
229 #endif
230
231 static void
232 _desc_init(void)
233 {
234    Eet_Data_Descriptor_Class eddc;
235
236    EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Elm_Config);
237    eddc.func.str_direct_alloc = NULL;
238    eddc.func.str_direct_free = NULL;
239
240    _config_edd = eet_data_descriptor_file_new(&eddc);
241    if (!_config_edd)
242      {
243         printf("EEEK! eet_data_descriptor_file_new() failed\n");
244         return;
245      }
246
247    memset(&eddc, 0, sizeof(eddc)); /* just in case... */
248    EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Elm_Font_Overlay);
249    eddc.func.str_direct_alloc = NULL;
250    eddc.func.str_direct_free = NULL;
251
252    _config_font_overlay_edd = eet_data_descriptor_stream_new(&eddc);
253    if (!_config_font_overlay_edd)
254      {
255         printf("EEEK! eet_data_descriptor_stream_new() failed\n");
256         eet_data_descriptor_free(_config_edd);
257         return;
258      }
259 #define T_INT    EET_T_INT
260 #define T_DOUBLE EET_T_DOUBLE
261 #define T_STRING EET_T_STRING
262 #define T_UCHAR  EET_T_UCHAR
263
264 #define T        Elm_Font_Overlay
265 #define D        _config_font_overlay_edd
266    ELM_CONFIG_VAL(D, T, text_class, EET_T_STRING);
267    ELM_CONFIG_VAL(D, T, font, EET_T_STRING);
268    ELM_CONFIG_VAL(D, T, size, EET_T_INT);
269 #undef T
270 #undef D
271
272 #define T Elm_Config
273 #define D _config_edd
274    ELM_CONFIG_VAL(D, T, config_version, T_INT);
275    ELM_CONFIG_VAL(D, T, engine, T_STRING);
276    ELM_CONFIG_VAL(D, T, vsync, T_UCHAR);
277    ELM_CONFIG_VAL(D, T, thumbscroll_enable, T_UCHAR);
278    ELM_CONFIG_VAL(D, T, thumbscroll_threshold, T_INT);
279    ELM_CONFIG_VAL(D, T, thumbscroll_momentum_threshold, T_DOUBLE);
280    ELM_CONFIG_VAL(D, T, thumbscroll_friction, T_DOUBLE);
281    ELM_CONFIG_VAL(D, T, thumbscroll_bounce_friction, T_DOUBLE);
282    ELM_CONFIG_VAL(D, T, thumbscroll_border_friction, T_DOUBLE);
283    ELM_CONFIG_VAL(D, T, thumbscroll_sensitivity_friction, T_DOUBLE);
284    ELM_CONFIG_VAL(D, T, page_scroll_friction, T_DOUBLE);
285    ELM_CONFIG_VAL(D, T, bring_in_scroll_friction, T_DOUBLE);
286    ELM_CONFIG_VAL(D, T, zoom_friction, T_DOUBLE);
287    ELM_CONFIG_VAL(D, T, thumbscroll_bounce_enable, T_UCHAR);
288    ELM_CONFIG_VAL(D, T, scroll_smooth_amount, T_DOUBLE);
289    ELM_CONFIG_VAL(D, T, scroll_smooth_history_weight, T_DOUBLE);
290    ELM_CONFIG_VAL(D, T, scroll_smooth_future_time, T_DOUBLE);
291    ELM_CONFIG_VAL(D, T, scroll_smooth_time_window, T_DOUBLE);
292    ELM_CONFIG_VAL(D, T, scale, T_DOUBLE);
293    ELM_CONFIG_VAL(D, T, bgpixmap, T_INT);
294    ELM_CONFIG_VAL(D, T, compositing, T_INT);
295    /* EET_DATA_DESCRIPTOR_ADD_LIST(D, T, "font_dirs", font_dirs, sub_edd); */
296    ELM_CONFIG_LIST(D, T, font_overlays, _config_font_overlay_edd);
297    ELM_CONFIG_VAL(D, T, font_hinting, T_INT);
298    ELM_CONFIG_VAL(D, T, cache_flush_poll_interval, T_INT);
299    ELM_CONFIG_VAL(D, T, cache_flush_enable, T_UCHAR);
300    ELM_CONFIG_VAL(D, T, image_cache, T_INT);
301    ELM_CONFIG_VAL(D, T, font_cache, T_INT);
302    ELM_CONFIG_VAL(D, T, edje_cache, T_INT);
303    ELM_CONFIG_VAL(D, T, edje_collection_cache, T_INT);
304    ELM_CONFIG_VAL(D, T, finger_size, T_INT);
305    ELM_CONFIG_VAL(D, T, fps, T_DOUBLE);
306    ELM_CONFIG_VAL(D, T, theme, T_STRING);
307    ELM_CONFIG_VAL(D, T, modules, T_STRING);
308    ELM_CONFIG_VAL(D, T, tooltip_delay, T_DOUBLE);
309    ELM_CONFIG_VAL(D, T, cursor_engine_only, T_UCHAR);
310    ELM_CONFIG_VAL(D, T, focus_highlight_enable, T_UCHAR);
311    ELM_CONFIG_VAL(D, T, focus_highlight_animate, T_UCHAR);
312    ELM_CONFIG_VAL(D, T, toolbar_shrink_mode, T_INT);
313    ELM_CONFIG_VAL(D, T, fileselector_expand_enable, T_UCHAR);
314    ELM_CONFIG_VAL(D, T, inwin_dialogs_enable, T_UCHAR);
315    ELM_CONFIG_VAL(D, T, icon_size, T_INT);
316    ELM_CONFIG_VAL(D, T, longpress_timeout, T_DOUBLE);
317    ELM_CONFIG_VAL(D, T, effect_enable, T_UCHAR);
318    ELM_CONFIG_VAL(D, T, desktop_entry, T_UCHAR);
319    ELM_CONFIG_VAL(D, T, password_show_last, T_UCHAR);
320    ELM_CONFIG_VAL(D, T, password_show_last_timeout, T_DOUBLE);
321    ELM_CONFIG_VAL(D, T, glayer_zoom_finger_enable, T_UCHAR);
322    ELM_CONFIG_VAL(D, T, glayer_zoom_finger_factor, T_DOUBLE);
323    ELM_CONFIG_VAL(D, T, glayer_zoom_wheel_factor, T_DOUBLE);
324    ELM_CONFIG_VAL(D, T, glayer_zoom_distance_tolerance, T_DOUBLE);
325    ELM_CONFIG_VAL(D, T, glayer_rotate_finger_enable, T_UCHAR);
326    ELM_CONFIG_VAL(D, T, glayer_rotate_angular_tolerance, T_DOUBLE);
327    ELM_CONFIG_VAL(D, T, glayer_line_min_length, T_DOUBLE);
328    ELM_CONFIG_VAL(D, T, glayer_line_distance_tolerance, T_DOUBLE);
329    ELM_CONFIG_VAL(D, T, glayer_line_angular_tolerance, T_DOUBLE);
330    ELM_CONFIG_VAL(D, T, glayer_flick_time_limit_ms, T_INT);
331    ELM_CONFIG_VAL(D, T, glayer_long_tap_start_timeout, T_DOUBLE);
332    ELM_CONFIG_VAL(D, T, access_mode, T_INT);
333    ELM_CONFIG_VAL(D, T, glayer_continues_enable, T_UCHAR);
334 #undef T
335 #undef D
336 #undef T_INT
337 #undef T_DOUBLE
338 #undef T_STRING
339 #undef T_UCHAR
340 }
341
342 static void
343 _desc_shutdown(void)
344 {
345    if (_config_edd)
346      {
347         eet_data_descriptor_free(_config_edd);
348         _config_edd = NULL;
349      }
350
351    if (_config_font_overlay_edd)
352      {
353         eet_data_descriptor_free(_config_font_overlay_edd);
354         _config_font_overlay_edd = NULL;
355      }
356 }
357
358 static int
359 _sort_files_cb(const void *f1,
360                const void *f2)
361 {
362    return strcmp(f1, f2);
363 }
364
365 const char *
366 _elm_config_current_profile_get(void)
367 {
368    return _elm_profile;
369 }
370
371 static size_t
372 _elm_data_dir_snprintf(char       *dst,
373                        size_t      size,
374                        const char *fmt,
375                        ...)
376 {
377    size_t data_dir_len, off;
378    va_list ap;
379
380    data_dir_len = eina_strlcpy(dst, _elm_data_dir, size);
381
382    off = data_dir_len + 1;
383    if (off >= size)
384      goto end;
385
386    va_start(ap, fmt);
387    dst[data_dir_len] = '/';
388
389    off = off + vsnprintf(dst + off, size - off, fmt, ap);
390    va_end(ap);
391
392 end:
393    return off;
394 }
395
396 static size_t
397 _elm_user_dir_snprintf(char       *dst,
398                        size_t      size,
399                        const char *fmt,
400                        ...)
401 {
402    const char *home;
403    size_t user_dir_len, off;
404    va_list ap;
405
406 #ifdef _WIN32
407    home = evil_homedir_get();
408 #else
409    home = getenv("HOME");
410 #endif
411    if (!home)
412      home = "/";
413
414    user_dir_len = eina_str_join_len(dst, size, '/', home, strlen(home),
415                                     ".elementary", sizeof(".elementary") - 1);
416
417    off = user_dir_len + 1;
418    if (off >= size)
419      goto end;
420
421    va_start(ap, fmt);
422    dst[user_dir_len] = '/';
423
424    off = off + vsnprintf(dst + off, size - off, fmt, ap);
425    va_end(ap);
426
427 end:
428    return off;
429 }
430
431 const char *
432 _elm_config_profile_dir_get(const char *prof,
433                             Eina_Bool   is_user)
434 {
435    char buf[PATH_MAX];
436
437    if (!is_user)
438      goto not_user;
439
440    _elm_user_dir_snprintf(buf, sizeof(buf), "config/%s", prof);
441
442    if (ecore_file_is_dir(buf))
443      return strdup(buf);
444
445    return NULL;
446
447 not_user:
448    snprintf(buf, sizeof(buf), "%s/config/%s", _elm_data_dir, prof);
449
450    if (ecore_file_is_dir(buf))
451      return strdup(buf);
452
453    return NULL;
454 }
455
456 Eina_List *
457 _elm_config_font_overlays_list(void)
458 {
459    return _elm_config->font_overlays;
460 }
461
462 void
463 _elm_config_font_overlay_set(const char    *text_class,
464                              const char    *font,
465                              Evas_Font_Size size)
466 {
467    Elm_Font_Overlay *efd;
468    Eina_List *l;
469
470    EINA_LIST_FOREACH(_elm_config->font_overlays, l, efd)
471      {
472         if (strcmp(efd->text_class, text_class))
473           continue;
474
475         if (efd->font) eina_stringshare_del(efd->font);
476         efd->font = eina_stringshare_add(font);
477         efd->size = size;
478         _elm_config->font_overlays =
479           eina_list_promote_list(_elm_config->font_overlays, l);
480         return;
481      }
482
483    /* the text class doesn't exist */
484    efd = calloc(1, sizeof(Elm_Font_Overlay));
485    efd->text_class = eina_stringshare_add(text_class);
486    efd->font = eina_stringshare_add(font);
487    efd->size = size;
488
489    _elm_config->font_overlays = eina_list_prepend(_elm_config->font_overlays,
490                                                   efd);
491 }
492
493 void
494 _elm_config_font_overlay_remove(const char *text_class)
495 {
496    Elm_Font_Overlay *efd;
497    Eina_List *l;
498
499    EINA_LIST_FOREACH(_elm_config->font_overlays, l, efd)
500      {
501         if (strcmp(efd->text_class, text_class))
502           continue;
503
504         _elm_config->font_overlays =
505           eina_list_remove_list(_elm_config->font_overlays, l);
506         if (efd->text_class) eina_stringshare_del(efd->text_class);
507         if (efd->font) eina_stringshare_del(efd->font);
508         free(efd);
509
510         return;
511      }
512 }
513
514 void
515 _elm_config_font_overlay_apply(void)
516 {
517    Elm_Font_Overlay *efd;
518    Eina_List *l;
519    int i;
520
521    for (i = 0; _elm_text_classes[i].desc; i++)
522      edje_text_class_del(_elm_text_classes[i].name);
523
524    EINA_LIST_FOREACH(_elm_config->font_overlays, l, efd)
525      edje_text_class_set(efd->text_class, efd->font, efd->size);
526 }
527
528 Eina_List *
529 _elm_config_text_classes_get(void)
530 {
531    Eina_List *ret = NULL;
532    int i;
533
534    for (i = 0; _elm_text_classes[i].desc; i++)
535      {
536         Elm_Text_Class *tc;
537         tc = malloc(sizeof(*tc));
538
539         *tc = _elm_text_classes[i];
540
541         ret = eina_list_append(ret, tc);
542      }
543
544    return ret;
545 }
546
547 void
548 _elm_config_text_classes_free(Eina_List *l)
549 {
550    Elm_Text_Class *tc;
551
552    EINA_LIST_FREE(l, tc)
553      free(tc);
554 }
555
556 Eina_List *
557 _elm_config_profiles_list(void)
558 {
559    const Eina_File_Direct_Info *info;
560    Eina_List *flist = NULL;
561    Eina_Iterator *file_it;
562    char buf[PATH_MAX];
563    const char *dir;
564    size_t len;
565
566    len = _elm_user_dir_snprintf(buf, sizeof(buf), "config");
567
568    file_it = eina_file_direct_ls(buf);
569    if (!file_it)
570      goto sys;
571
572    buf[len] = '/';
573    len++;
574
575    len = sizeof(buf) - len;
576
577    EINA_ITERATOR_FOREACH(file_it, info)
578      {
579         if (info->name_length >= len)
580           continue;
581
582         if (info->type == EINA_FILE_DIR)
583           {
584              flist =
585                eina_list_sorted_insert(flist, _sort_files_cb,
586                                        eina_stringshare_add(info->path +
587                                                             info->name_start));
588           }
589      }
590
591    eina_iterator_free(file_it);
592
593 sys:
594    len = eina_str_join_len(buf, sizeof(buf), '/', _elm_data_dir,
595                            strlen(_elm_data_dir), "config",
596                            sizeof("config") - 1);
597
598    file_it = eina_file_direct_ls(buf);
599    if (!file_it)
600      goto list_free;
601
602    buf[len] = '/';
603    len++;
604
605    len = sizeof(buf) - len;
606    EINA_ITERATOR_FOREACH(file_it, info)
607      {
608         if (info->name_length >= len)
609           continue;
610
611         switch (info->type)
612           {
613            case EINA_FILE_DIR:
614            {
615               const Eina_List *l;
616               const char *tmp;
617
618               EINA_LIST_FOREACH(flist, l, tmp)
619                 if (!strcmp(info->path + info->name_start, tmp))
620                   break;
621
622               if (!l)
623                 flist =
624                   eina_list_sorted_insert(flist, _sort_files_cb,
625                                           eina_stringshare_add(info->path +
626                                                                info->name_start));
627            }
628            break;
629
630            default:
631              continue;
632           }
633      }
634    eina_iterator_free(file_it);
635    return flist;
636
637 list_free:
638    EINA_LIST_FREE(flist, dir)
639      eina_stringshare_del(dir);
640
641    return NULL;
642 }
643
644 static void
645 _profile_fetch_from_conf(void)
646 {
647    char buf[PATH_MAX], *p, *s;
648    Eet_File *ef = NULL;
649    int len = 0;
650
651    _elm_profile = strdup("default");
652
653    // if env var - use profile without question
654    s = getenv("ELM_PROFILE");
655    if (s)
656      {
657         free(_elm_profile);
658         _elm_profile = strdup(s);
659         return;
660      }
661
662    // user profile
663    _elm_user_dir_snprintf(buf, sizeof(buf), "config/profile.cfg");
664    ef = eet_open(buf, EET_FILE_MODE_READ);
665    if (ef)
666      {
667         p = eet_read(ef, "config", &len);
668         if (p)
669           {
670              free(_elm_profile);
671              _elm_profile = malloc(len + 1);
672              memcpy(_elm_profile, p, len);
673              _elm_profile[len] = 0;
674              free(p);
675           }
676         eet_close(ef);
677         if (!p) ef = NULL;
678      }
679    if (ef) return;
680
681    // system profile
682    _elm_data_dir_snprintf(buf, sizeof(buf), "config/profile.cfg");
683    ef = eet_open(buf, EET_FILE_MODE_READ);
684    if (ef)
685      {
686         p = eet_read(ef, "config", &len);
687         if (p)
688           {
689              free(_elm_profile);
690              _elm_profile = malloc(len + 1);
691              memcpy(_elm_profile, p, len);
692              _elm_profile[len] = 0;
693              free(p);
694           }
695         eet_close(ef);
696      }
697 }
698
699 static void
700 _config_free(void)
701 {
702    Elm_Font_Overlay *fo;
703    const char *fontdir;
704
705    if (!_elm_config) return;
706    EINA_LIST_FREE(_elm_config->font_dirs, fontdir)
707      {
708         eina_stringshare_del(fontdir);
709      }
710    if (_elm_config->engine) eina_stringshare_del(_elm_config->engine);
711    EINA_LIST_FREE(_elm_config->font_overlays, fo)
712      {
713         if (fo->text_class) eina_stringshare_del(fo->text_class);
714         if (fo->font) eina_stringshare_del(fo->font);
715         free(fo);
716      }
717    if (_elm_config->theme) eina_stringshare_del(_elm_config->theme);
718    if (_elm_config->modules) eina_stringshare_del(_elm_config->modules);
719    free(_elm_config);
720    _elm_config = NULL;
721 }
722
723 static void
724 _config_apply(void)
725 {
726    _elm_theme_parse(NULL, _elm_config->theme);
727    ecore_animator_frametime_set(1.0 / _elm_config->fps);
728 }
729
730 static void
731 _config_sub_apply(void)
732 {
733    edje_frametime_set(1.0 / _elm_config->fps);
734    edje_scale_set(_elm_config->scale);
735    edje_password_show_last_set(_elm_config->password_show_last);
736    edje_password_show_last_timeout_set(_elm_config->password_show_last_timeout);
737    if (_elm_config->modules) _elm_module_parse(_elm_config->modules);
738 }
739
740 static Eina_Bool
741 _elm_cache_flush_cb(void *data __UNUSED__)
742 {
743    elm_all_flush();
744    return ECORE_CALLBACK_RENEW;
745 }
746
747 /* kind of abusing this call right now -- shared between all of those
748  * properties -- but they are not meant to be called that periodically
749  * anyway */
750 void
751 _elm_recache(void)
752 {
753    Eina_List *l;
754    Evas_Object *win;
755
756    elm_all_flush();
757
758    EINA_LIST_FOREACH(_elm_win_list, l, win)
759      {
760         Evas *e = evas_object_evas_get(win);
761         evas_image_cache_set(e, _elm_config->image_cache * 1024);
762         evas_font_cache_set(e, _elm_config->font_cache * 1024);
763      }
764    edje_file_cache_set(_elm_config->edje_cache);
765    edje_collection_cache_set(_elm_config->edje_collection_cache);
766
767    if (_elm_cache_flush_poller)
768      {
769         ecore_poller_del(_elm_cache_flush_poller);
770         _elm_cache_flush_poller = NULL;
771      }
772    if (_elm_config->cache_flush_enable)
773      {
774         if (_elm_config->cache_flush_poll_interval > 0)
775           {
776              _elm_cache_flush_poller =
777                 ecore_poller_add(ECORE_POLLER_CORE,
778                                  _elm_config->cache_flush_poll_interval,
779                                  _elm_cache_flush_cb, NULL);
780           }
781      }
782 }
783
784 static Elm_Config *
785 _config_user_load(void)
786 {
787    Elm_Config *cfg = NULL;
788    Eet_File *ef;
789    char buf[PATH_MAX];
790
791    _elm_user_dir_snprintf(buf, sizeof(buf), "config/%s/base.cfg",
792                           _elm_profile);
793
794    ef = eet_open(buf, EET_FILE_MODE_READ);
795    if (ef)
796      {
797         cfg = eet_data_read(ef, _config_edd, "config");
798         eet_close(ef);
799      }
800    return cfg;
801 }
802
803 static Elm_Config *
804 _config_system_load(void)
805 {
806    Elm_Config *cfg = NULL;
807    Eet_File *ef;
808    char buf[PATH_MAX];
809
810    _elm_data_dir_snprintf(buf, sizeof(buf), "config/%s/base.cfg",
811                           _elm_profile);
812
813    ef = eet_open(buf, EET_FILE_MODE_READ);
814    if (ef)
815      {
816         cfg = eet_data_read(ef, _config_edd, "config");
817         eet_close(ef);
818      }
819    return cfg;
820 }
821
822 static void
823 _config_load(void)
824 {
825    _elm_config = _config_user_load();
826    if (_elm_config)
827      {
828         if (_elm_config->config_version < ELM_CONFIG_VERSION)
829           _config_update();
830         return;
831      }
832
833    /* no user config, fallback for system. No need to check version for
834     * this one, if it's not the right one, someone screwed up at the time
835     * of installing it */
836    _elm_config = _config_system_load();
837    if (_elm_config) return;
838    /* FIXME: config load could have failed because of a non-existent
839     * profile. Fallback to default before moving on */
840
841    // config load fail - defaults
842    /* XXX: do these make sense? Only if it's valid to install the lib
843     * without the config, but do we want that? */
844    _elm_config = ELM_NEW(Elm_Config);
845    _elm_config->config_version = ELM_CONFIG_VERSION;
846    _elm_config->engine = eina_stringshare_add("software_x11");
847    _elm_config->vsync = 0;
848    _elm_config->thumbscroll_enable = EINA_TRUE;
849    _elm_config->thumbscroll_threshold = 24;
850    _elm_config->thumbscroll_momentum_threshold = 100.0;
851    _elm_config->thumbscroll_friction = 1.0;
852    _elm_config->thumbscroll_bounce_friction = 0.5;
853    _elm_config->thumbscroll_bounce_enable = EINA_TRUE;
854    _elm_config->page_scroll_friction = 0.5;
855    _elm_config->bring_in_scroll_friction = 0.5;
856    _elm_config->zoom_friction = 0.5;
857    _elm_config->thumbscroll_border_friction = 0.5;
858    _elm_config->thumbscroll_sensitivity_friction = 0.25; // magic number! just trial and error shows this makes it behave "nicer" and not run off at high speed all the time
859    _elm_config->scroll_smooth_amount = 1.0;
860    _elm_config->scroll_smooth_history_weight = 0.3;
861    _elm_config->scroll_smooth_future_time = 0.0;
862    _elm_config->scroll_smooth_time_window = 0.2;
863    _elm_config->scale = 1.0;
864    _elm_config->bgpixmap = 0;
865    _elm_config->compositing = 1;
866    _elm_config->font_hinting = 2;
867    _elm_config->cache_flush_poll_interval = 512;
868    _elm_config->cache_flush_enable = EINA_TRUE;
869    _elm_config->font_dirs = NULL;
870    _elm_config->image_cache = 4096;
871    _elm_config->font_cache = 512;
872    _elm_config->edje_cache = 32;
873    _elm_config->edje_collection_cache = 64;
874    _elm_config->finger_size = 40;
875    _elm_config->fps = 60.0;
876    _elm_config->theme = eina_stringshare_add("default");
877    _elm_config->modules = NULL;
878    _elm_config->tooltip_delay = 1.0;
879    _elm_config->cursor_engine_only = EINA_TRUE;
880    _elm_config->focus_highlight_enable = EINA_FALSE;
881    _elm_config->focus_highlight_animate = EINA_TRUE;
882    _elm_config->toolbar_shrink_mode = 2;
883    _elm_config->fileselector_expand_enable = EINA_FALSE;
884    _elm_config->inwin_dialogs_enable = EINA_FALSE;
885    _elm_config->icon_size = 32;
886    _elm_config->longpress_timeout = 1.0;
887    _elm_config->effect_enable = EINA_TRUE;
888    _elm_config->desktop_entry = EINA_FALSE;
889    _elm_config->is_mirrored = EINA_FALSE; /* Read sys value in env_get() */
890    _elm_config->password_show_last = EINA_FALSE;
891    _elm_config->password_show_last_timeout = 2.0;
892    _elm_config->glayer_zoom_finger_enable = EINA_TRUE;
893    _elm_config->glayer_zoom_finger_factor = 1.0;
894    _elm_config->glayer_zoom_wheel_factor = 0.05;
895    _elm_config->glayer_zoom_distance_tolerance = 1.0; /* 1 times elm_finger_size_get() */
896    _elm_config->glayer_rotate_finger_enable = EINA_TRUE;
897    _elm_config->glayer_rotate_angular_tolerance = 2.0; /* 2 DEG */
898    _elm_config->glayer_line_min_length = 1.0;         /* 1 times elm_finger_size_get() */
899    _elm_config->glayer_line_distance_tolerance = 3.0; /* 3 times elm_finger_size_get() */
900    _elm_config->glayer_line_angular_tolerance = 20.0; /* 20 DEG */
901    _elm_config->glayer_flick_time_limit_ms = 120;              /* ms to finish flick */
902    _elm_config->glayer_long_tap_start_timeout = 1.2;   /* 1.2 second to start long-tap */
903    _elm_config->glayer_continues_enable = EINA_TRUE;      /* Continue gestures default */
904 }
905
906 static const char *
907 _elm_config_eet_close_error_get(Eet_File *ef,
908                                 char     *file)
909 {
910    Eet_Error err;
911    const char *erstr = NULL;
912
913    err = eet_close(ef);
914    switch (err)
915      {
916       case EET_ERROR_WRITE_ERROR:
917         erstr = "An error occurred while saving Elementary's "
918                 "settings to disk. The error could not be "
919                 "deterimined. The file where the error occurred was: "
920                 "%s. This file has been deleted to avoid corrupt data.";
921         break;
922
923       case EET_ERROR_WRITE_ERROR_FILE_TOO_BIG:
924         erstr = "Elementary's settings files are too big "
925                 "for the file system they are being saved to. "
926                 "This error is very strange as the files should "
927                 "be extremely small. Please check the settings "
928                 "for your home directory. "
929                 "The file where the error occurred was: %s ."
930                 "This file has been deleted to avoid corrupt data.";
931         break;
932
933       case EET_ERROR_WRITE_ERROR_IO_ERROR:
934         erstr = "An output error occurred when writing the settings "
935                 "files for Elementary. Your disk is having troubles "
936                 "and possibly needs replacement. "
937                 "The file where the error occurred was: %s ."
938                 "This file has been deleted to avoid corrupt data.";
939         break;
940
941       case EET_ERROR_WRITE_ERROR_OUT_OF_SPACE:
942         erstr = "Elementary cannot write its settings file "
943                 "because it ran out of space to write the file. "
944                 "You have either run out of disk space or have "
945                 "gone over your quota limit. "
946                 "The file where the error occurred was: %s ."
947                 "This file has been deleted to avoid corrupt data.";
948         break;
949
950       case EET_ERROR_WRITE_ERROR_FILE_CLOSED:
951         erstr = "Elementary unexpectedly had the settings file "
952                 "it was writing closed on it. This is very unusual. "
953                 "The file where the error occurred was: %s "
954                 "This file has been deleted to avoid corrupt data.";
955         break;
956
957       default:
958         break;
959      }
960    if (erstr)
961      {
962         /* delete any partially-written file */
963          ecore_file_unlink(file);
964          return strdup(erstr);
965      }
966
967    return NULL;
968 }
969
970 static Eina_Bool
971 _elm_config_profile_save(void)
972 {
973    char buf[4096], buf2[4096];
974    int ok = 0, ret;
975    const char *err;
976    Eet_File *ef;
977    size_t len;
978
979    len = _elm_user_dir_snprintf(buf, sizeof(buf), "config/profile.cfg");
980    if (len + 1 >= sizeof(buf))
981      return EINA_FALSE;
982
983    len = _elm_user_dir_snprintf(buf2, sizeof(buf2), "config/profile.cfg.tmp");
984    if (len + 1 >= sizeof(buf2))
985      return EINA_FALSE;
986
987    ef = eet_open(buf2, EET_FILE_MODE_WRITE);
988    if (!ef)
989      return EINA_FALSE;
990
991    ok = eet_write(ef, "config", _elm_profile, strlen(_elm_profile), 0);
992    if (!ok)
993      goto err;
994
995    err = _elm_config_eet_close_error_get(ef, buf2);
996    if (err)
997      {
998         ERR("%s", err);
999         free((void *)err);
1000         goto err;
1001      }
1002
1003    ret = ecore_file_mv(buf2, buf);
1004    if (!ret)
1005      {
1006         ERR("Error saving Elementary's configuration file");
1007         goto err;
1008      }
1009
1010    ecore_file_unlink(buf2);
1011    return EINA_TRUE;
1012
1013 err:
1014    ecore_file_unlink(buf2);
1015    return EINA_FALSE;
1016 }
1017
1018 Eina_Bool
1019 _elm_config_save(void)
1020 {
1021    char buf[4096], buf2[4096];
1022    int ok = 0, ret;
1023    const char *err;
1024    Eet_File *ef;
1025    size_t len;
1026
1027    len = _elm_user_dir_snprintf(buf, sizeof(buf), "config/%s", _elm_profile);
1028    if (len + 1 >= sizeof(buf))
1029      return EINA_FALSE;
1030
1031    ok = ecore_file_mkpath(buf);
1032    if (!ok)
1033      {
1034         ERR("Problem acessing Elementary's user configuration directory: %s",
1035             buf);
1036         return EINA_FALSE;
1037      }
1038
1039    if (!_elm_config_profile_save())
1040      return EINA_FALSE;
1041
1042    buf[len] = '/';
1043    len++;
1044
1045    if (len + sizeof("base.cfg") >= sizeof(buf) - len)
1046      return EINA_FALSE;
1047
1048    memcpy(buf + len, "base.cfg", sizeof("base.cfg"));
1049    len += sizeof("base.cfg") - 1;
1050
1051    if (len + sizeof(".tmp") >= sizeof(buf))
1052      return EINA_FALSE;
1053
1054    memcpy(buf2, buf, len);
1055    memcpy(buf2 + len, ".tmp", sizeof(".tmp"));
1056
1057    ef = eet_open(buf2, EET_FILE_MODE_WRITE);
1058    if (!ef)
1059      return EINA_FALSE;
1060
1061    ok = eet_data_write(ef, _config_edd, "config", _elm_config, 1);
1062    if (!ok)
1063      goto err;
1064
1065    err = _elm_config_eet_close_error_get(ef, buf2);
1066    if (err)
1067      {
1068         ERR("%s", err);
1069         free((void *)err);
1070         goto err;
1071      }
1072
1073    ret = ecore_file_mv(buf2, buf);
1074    if (!ret)
1075      {
1076         ERR("Error saving Elementary's configuration file");
1077         goto err;
1078      }
1079
1080    ecore_file_unlink(buf2);
1081    return EINA_TRUE;
1082
1083 err:
1084    ecore_file_unlink(buf2);
1085    return EINA_FALSE;
1086 }
1087
1088 static void
1089 _config_update(void)
1090 {
1091    Elm_Config *tcfg;
1092
1093    tcfg = _config_system_load();
1094    if (!tcfg)
1095      {
1096         /* weird profile or something? We should probably fill
1097          * with hardcoded defaults, or get from default previx */
1098           return;
1099      }
1100 #define IFCFG(v)   if ((_elm_config->config_version & 0xffff) < (v)) {
1101 #define IFCFGELSE } else {
1102 #define IFCFGEND  }
1103 #define COPYVAL(x) do {_elm_config->x = tcfg->x; } while(0)
1104 #define COPYPTR(x) do {_elm_config->x = tcfg->x; tcfg->x = NULL; } while(0)
1105 #define COPYSTR(x) COPYPTR(x)
1106
1107      /* we also need to update for property changes in the root window
1108       * if needed, but that will be dependent on new properties added
1109       * with each version */
1110
1111      IFCFG(0x0003);
1112      COPYVAL(longpress_timeout);
1113      IFCFGEND;
1114
1115 #undef COPYSTR
1116 #undef COPYPTR
1117 #undef COPYVAL
1118 #undef IFCFGEND
1119 #undef IFCFGELSE
1120 #undef IFCFG
1121
1122      /* after updating user config, we must save */
1123 }
1124
1125 static void
1126 _env_get(void)
1127 {
1128    char *s;
1129    double friction;
1130
1131    s = getenv("ELM_ENGINE");
1132    if (s)
1133      {
1134         if ((!strcasecmp(s, "x11")) ||
1135             (!strcasecmp(s, "x")) ||
1136             (!strcasecmp(s, "software-x11")) ||
1137             (!strcasecmp(s, "software_x11")))
1138           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_X11);
1139         else if ((!strcasecmp(s, "opengl")) ||
1140                  (!strcasecmp(s, "gl")) ||
1141                  (!strcasecmp(s, "opengl-x11")) ||
1142                  (!strcasecmp(s, "opengl_x11")))
1143           eina_stringshare_replace(&_elm_config->engine, ELM_OPENGL_X11);
1144         else if ((!strcasecmp(s, "x11-8")) ||
1145                  (!strcasecmp(s, "x8")) ||
1146                  (!strcasecmp(s, "software-8-x11")) ||
1147                  (!strcasecmp(s, "software_8_x11")))
1148           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_8_X11);
1149         else if ((!strcasecmp(s, "x11-16")) ||
1150                  (!strcasecmp(s, "x16")) ||
1151                  (!strcasecmp(s, "software-16-x11")) ||
1152                  (!strcasecmp(s, "software_16_x11")))
1153           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_16_X11);
1154 /*
1155         else if ((!strcasecmp(s, "xrender")) ||
1156                  (!strcasecmp(s, "xr")) ||
1157                  (!strcasecmp(s, "xrender-x11")) ||
1158                  (!strcasecmp(s, "xrender_x11")))
1159           eina_stringshare_replace(&_elm_config->engine, ELM_XRENDER_X11);
1160  */
1161         else if ((!strcasecmp(s, "fb")) ||
1162                  (!strcasecmp(s, "software-fb")) ||
1163                  (!strcasecmp(s, "software_fb")))
1164           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_FB);
1165         else if ((!strcasecmp(s, "directfb")) ||
1166                  (!strcasecmp(s, "dfb")))
1167           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_DIRECTFB);
1168         else if ((!strcasecmp(s, "psl1ght")))
1169           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_PSL1GHT);
1170         else if ((!strcasecmp(s, "sdl")) ||
1171                  (!strcasecmp(s, "software-sdl")) ||
1172                  (!strcasecmp(s, "software_sdl")))
1173           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_SDL);
1174         else if ((!strcasecmp(s, "sdl-16")) ||
1175                  (!strcasecmp(s, "software-16-sdl")) ||
1176                  (!strcasecmp(s, "software_16_sdl")))
1177           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_16_SDL);
1178         else if ((!strcasecmp(s, "opengl-sdl")) ||
1179                  (!strcasecmp(s, "opengl_sdl")) ||
1180                  (!strcasecmp(s, "gl-sdl")) ||
1181                  (!strcasecmp(s, "gl_sdl")))
1182           eina_stringshare_replace(&_elm_config->engine, ELM_OPENGL_SDL);
1183         else if ((!strcasecmp(s, "opengl-cocoa")) ||
1184                  (!strcasecmp(s, "opengl_cocoa")) ||
1185                  (!strcasecmp(s, "gl-cocoa")) ||
1186                  (!strcasecmp(s, "gl_cocoa")))
1187           eina_stringshare_replace(&_elm_config->engine, ELM_OPENGL_COCOA);
1188         else if ((!strcasecmp(s, "gdi")) ||
1189                  (!strcasecmp(s, "software-gdi")) ||
1190                  (!strcasecmp(s, "software_gdi")))
1191           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_WIN32);
1192         else if ((!strcasecmp(s, "wince-gdi")) ||
1193                  (!strcasecmp(s, "software-16-wince-gdi")) ||
1194                  (!strcasecmp(s, "software_16_wince_gdi")))
1195           eina_stringshare_replace(&_elm_config->engine, ELM_SOFTWARE_16_WINCE);
1196         else if (!strcasecmp(s, "buffer"))
1197           eina_stringshare_replace(&_elm_config->engine, ELM_BUFFER);
1198         else if ((!strncmp(s, "shot:", 5)))
1199           eina_stringshare_replace(&_elm_config->engine, s);
1200         else if ((!strcasecmp(s, "ews")))
1201           eina_stringshare_replace(&_elm_config->engine, ELM_EWS);
1202      }
1203
1204    s = getenv("ELM_VSYNC");
1205    if (s) _elm_config->vsync = !!atoi(s);
1206
1207    s = getenv("ELM_THUMBSCROLL_ENABLE");
1208    if (s) _elm_config->thumbscroll_enable = !!atoi(s);
1209    s = getenv("ELM_THUMBSCROLL_THRESHOLD");
1210    if (s) _elm_config->thumbscroll_threshold = atoi(s);
1211    // FIXME: floatformat locale issues here 1.0 vs 1,0 - should just be 1.0
1212    s = getenv("ELM_THUMBSCROLL_MOMENTUM_THRESHOLD");
1213    if (s) _elm_config->thumbscroll_momentum_threshold = atof(s);
1214    s = getenv("ELM_THUMBSCROLL_FRICTION");
1215    if (s) _elm_config->thumbscroll_friction = atof(s);
1216    s = getenv("ELM_THUMBSCROLL_BOUNCE_ENABLE");
1217    if (s) _elm_config->thumbscroll_bounce_enable = !!atoi(s);
1218    s = getenv("ELM_THUMBSCROLL_BOUNCE_FRICTION");
1219    if (s) _elm_config->thumbscroll_bounce_friction = atof(s);
1220    s = getenv("ELM_PAGE_SCROLL_FRICTION");
1221    if (s) _elm_config->page_scroll_friction = atof(s);
1222    s = getenv("ELM_BRING_IN_SCROLL_FRICTION");
1223    if (s) _elm_config->bring_in_scroll_friction = atof(s);
1224    s = getenv("ELM_ZOOM_FRICTION");
1225    if (s) _elm_config->zoom_friction = atof(s);
1226    s = getenv("ELM_THUMBSCROLL_BORDER_FRICTION");
1227    if (s)
1228      {
1229         friction = atof(s);
1230         if (friction < 0.0)
1231           friction = 0.0;
1232
1233         if (friction > 1.0)
1234           friction = 1.0;
1235
1236         _elm_config->thumbscroll_border_friction = friction;
1237      }
1238    s = getenv("ELM_THUMBSCROLL_SENSITIVITY_FRICTION");
1239    if (s)
1240      {
1241         friction = atof(s);
1242         if (friction < 0.1)
1243           friction = 0.1;
1244
1245         if (friction > 1.0)
1246           friction = 1.0;
1247
1248         _elm_config->thumbscroll_sensitivity_friction = friction;
1249      }
1250    s = getenv("ELM_SCROLL_SMOOTH_AMOUNT");
1251    if (s) _elm_config->scroll_smooth_amount = atof(s);
1252    s = getenv("ELM_SCROLL_SMOOTH_HISTORY_WEIGHT");
1253    if (s) _elm_config->scroll_smooth_history_weight = atof(s);
1254    s = getenv("ELM_SCROLL_SMOOTH_FUTURE_TIME");
1255    if (s) _elm_config->scroll_smooth_future_time = atof(s);
1256    s = getenv("ELM_SCROLL_SMOOTH_TIME_WINDOW");
1257    if (s) _elm_config->scroll_smooth_time_window = atof(s);
1258    s = getenv("ELM_THEME");
1259    if (s) eina_stringshare_replace(&_elm_config->theme, s);
1260
1261    s = getenv("ELM_FONT_HINTING");
1262    if (s)
1263      {
1264         if      (!strcasecmp(s, "none")) _elm_config->font_hinting = 0;
1265         else if (!strcasecmp(s, "auto"))
1266           _elm_config->font_hinting = 1;
1267         else if (!strcasecmp(s, "bytecode"))
1268           _elm_config->font_hinting = 2;
1269      }
1270
1271    s = getenv("ELM_FONT_PATH");
1272    if (s)
1273      {
1274         const char *p, *pp;
1275         char *buf2;
1276
1277         EINA_LIST_FREE(_elm_config->font_dirs, p)
1278           {
1279              eina_stringshare_del(p);
1280           }
1281
1282         buf2 = alloca(strlen(s) + 1);
1283         p = s;
1284         pp = p;
1285         for (;; )
1286           {
1287              if ((*p == ':') || (*p == 0))
1288                {
1289                   int len;
1290
1291                   len = p - pp;
1292                   strncpy(buf2, pp, len);
1293                   buf2[len] = 0;
1294                   _elm_config->font_dirs =
1295                     eina_list_append(_elm_config->font_dirs,
1296                                      eina_stringshare_add(buf2));
1297                   if (*p == 0) break;
1298                   p++;
1299                   pp = p;
1300                }
1301              else
1302                {
1303                   if (*p == 0) break;
1304                   p++;
1305                }
1306           }
1307      }
1308
1309    s = getenv("ELM_IMAGE_CACHE");
1310    if (s) _elm_config->image_cache = atoi(s);
1311
1312    s = getenv("ELM_FONT_CACHE");
1313    if (s) _elm_config->font_cache = atoi(s);
1314
1315    s = getenv("ELM_SCALE");
1316    if (s) _elm_config->scale = atof(s);
1317
1318    s = getenv("ELM_FINGER_SIZE");
1319    if (s) _elm_config->finger_size = atoi(s);
1320
1321    s = getenv("ELM_PASSWORD_SHOW_LAST");
1322    if (s) _elm_config->password_show_last = !!atoi(s);
1323
1324    s = getenv("ELM_PASSWORD_SHOW_LAST_TIMEOUT");
1325    if (s)
1326      {
1327         double pw_show_last_timeout = atof(s);
1328         if (pw_show_last_timeout >= 0.0)
1329           _elm_config->password_show_last_timeout = pw_show_last_timeout;
1330      }
1331
1332    s = getenv("ELM_FPS");
1333    if (s) _elm_config->fps = atof(s);
1334    if (_elm_config->fps < 1.0) _elm_config->fps = 1.0;
1335
1336    s = getenv("ELM_MODULES");
1337    if (s) eina_stringshare_replace(&_elm_config->modules, s);
1338
1339    /* Get RTL orientation from system */
1340    setlocale(LC_ALL, "");
1341    bindtextdomain(PACKAGE, LOCALE_DIR);
1342    _elm_config->is_mirrored = !strcmp(E_("default:LTR"), "default:RTL");
1343
1344    s = getenv("ELM_TOOLTIP_DELAY");
1345    if (s)
1346      {
1347         double delay = atof(s);
1348         if (delay >= 0.0)
1349           _elm_config->tooltip_delay = delay;
1350      }
1351
1352    s = getenv("ELM_CURSOR_ENGINE_ONLY");
1353    if (s) _elm_config->cursor_engine_only = !!atoi(s);
1354
1355    s = getenv("ELM_FOCUS_HIGHLIGHT_ENABLE");
1356    if (s) _elm_config->focus_highlight_enable = !!atoi(s);
1357
1358    s = getenv("ELM_FOCUS_HIGHLIGHT_ANIMATE");
1359    if (s) _elm_config->focus_highlight_animate = !!atoi(s);
1360
1361    s = getenv("ELM_TOOLBAR_SHRINK_MODE");
1362    if (s) _elm_config->toolbar_shrink_mode = atoi(s);
1363
1364    s = getenv("ELM_FILESELECTOR_EXPAND_ENABLE");
1365    if (s) _elm_config->fileselector_expand_enable = !!atoi(s);
1366
1367    s = getenv("ELM_INWIN_DIALOGS_ENABLE");
1368    if (s) _elm_config->inwin_dialogs_enable = !!atoi(s);
1369
1370    s = getenv("ELM_ICON_SIZE");
1371    if (s) _elm_config->icon_size = atoi(s);
1372
1373    s = getenv("ELM_LONGPRESS_TIMEOUT");
1374    if (s) _elm_config->longpress_timeout = atof(s);
1375    if (_elm_config->longpress_timeout < 0.0)
1376      _elm_config->longpress_timeout = 0.0;
1377
1378    s = getenv("ELM_EFFECT_ENABLE");
1379    if (s) _elm_config->effect_enable = !!atoi(s);
1380
1381    s = getenv("ELM_DESKTOP_ENTRY");
1382    if (s) _elm_config->desktop_entry = !!atoi(s);
1383    s = getenv("ELM_ACCESS_MODE");
1384    if (s) _elm_config->access_mode = ELM_ACCESS_MODE_ON;
1385 }
1386
1387 EAPI Eina_Bool
1388 elm_mirrored_get(void)
1389 {
1390    return _elm_config->is_mirrored;
1391 }
1392
1393 EAPI void
1394 elm_mirrored_set(Eina_Bool mirrored)
1395 {
1396    _elm_config->is_mirrored = mirrored;
1397    _elm_rescale();
1398 }
1399
1400 static void
1401 _translation_init()
1402 {
1403 #ifdef ENABLE_NLS
1404    const char *cur_dom = textdomain(NULL);
1405    const char *trans_comment = gettext("");
1406    const char *msg_locale = setlocale(LC_MESSAGES, NULL);
1407
1408    /* Same concept as what glib does:
1409     * We shouldn't translate if there are no translations for the
1410     * application in the current locale + domain. (Unless locale is
1411     * en_/C where translating only parts of the interface make some
1412     * sense).
1413     */
1414    _elm_config->translate = !(strcmp (cur_dom, "messages") &&
1415          !*trans_comment && strncmp (msg_locale, "en_", 3) &&
1416          strcmp (msg_locale, "C"));
1417 #endif
1418 }
1419
1420 void
1421 _elm_config_init(void)
1422 {
1423    if (!ELM_EVENT_CONFIG_ALL_CHANGED)
1424       ELM_EVENT_CONFIG_ALL_CHANGED = ecore_event_type_new();
1425    _desc_init();
1426    _profile_fetch_from_conf();
1427    _config_load();
1428    _translation_init();
1429    _env_get();
1430    _config_apply();
1431    _elm_config_font_overlay_apply();
1432    _elm_recache();
1433 }
1434
1435 void
1436 _elm_config_sub_shutdown(void)
1437 {
1438 #define ENGINE_COMPARE(name) (!strcmp(_elm_config->engine, name))
1439    if (ENGINE_COMPARE(ELM_SOFTWARE_X11) ||
1440        ENGINE_COMPARE(ELM_SOFTWARE_16_X11) ||
1441        ENGINE_COMPARE(ELM_XRENDER_X11) ||
1442        ENGINE_COMPARE(ELM_OPENGL_X11) ||
1443        ENGINE_COMPARE(ELM_OPENGL_COCOA))
1444 #undef ENGINE_COMPARE
1445      {
1446 #ifdef HAVE_ELEMENTARY_X
1447         ecore_x_disconnect();
1448 #endif
1449      }
1450 }
1451
1452 void
1453 _elm_config_sub_init(void)
1454 {
1455 #define ENGINE_COMPARE(name) (!strcmp(_elm_config->engine, name))
1456    if (ENGINE_COMPARE(ELM_SOFTWARE_X11) ||
1457        ENGINE_COMPARE(ELM_SOFTWARE_16_X11) ||
1458        ENGINE_COMPARE(ELM_XRENDER_X11) ||
1459        ENGINE_COMPARE(ELM_OPENGL_X11) ||
1460        ENGINE_COMPARE(ELM_OPENGL_COCOA))
1461 #undef ENGINE_COMPARE
1462      {
1463 #ifdef HAVE_ELEMENTARY_X
1464         if (!ecore_x_init(NULL))
1465           {
1466              ERR("Cannot connect to X11 display. check $DISPLAY variable");
1467              exit(1);
1468           }
1469         _root_1st = ecore_x_window_root_first_get();
1470
1471         if (!ecore_x_screen_is_composited(0))
1472           _elm_config->compositing = 0;
1473
1474         ecore_x_atoms_get(_atom_names, ATOM_COUNT, _atom);
1475         ecore_x_event_mask_set(_root_1st,
1476                                ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
1477         _prop_change_handler = ecore_event_handler_add
1478             (ECORE_X_EVENT_WINDOW_PROPERTY, _prop_change, NULL);
1479         if (!getenv("ELM_PROFILE"))
1480           {
1481              char *s;
1482
1483              s = ecore_x_window_prop_string_get(_root_1st,
1484                                                 _atom[ATOM_E_PROFILE]);
1485              if (s)
1486                {
1487                   int changed = 0;
1488
1489                   if (_elm_profile)
1490                     {
1491                        if (strcmp(_elm_profile, s)) changed = 1;
1492                        free(_elm_profile);
1493                     }
1494                   _elm_profile = s;
1495                   if (changed) _prop_config_get();
1496                }
1497           }
1498 #endif
1499      }
1500    _config_sub_apply();
1501 }
1502
1503 void
1504 _elm_config_reload(void)
1505 {
1506    _config_free();
1507    _config_load();
1508    _config_apply();
1509    _elm_config_font_overlay_apply();
1510    _elm_rescale();
1511    _elm_recache();
1512 }
1513
1514 void
1515 _elm_config_engine_set(const char *engine)
1516 {
1517    if (_elm_config->engine && strcmp(_elm_config->engine, engine))
1518      eina_stringshare_del(_elm_config->engine);
1519
1520    _elm_config->engine = eina_stringshare_add(engine);
1521 }
1522
1523 void
1524 _elm_config_all_update(void)
1525 {
1526 #ifdef HAVE_ELEMENTARY_X
1527    if (_prop_all_update_timer) ecore_timer_del(_prop_all_update_timer);
1528    _prop_all_update_timer = ecore_timer_add(0.1, _prop_all_update_cb, NULL);
1529    _prop_config_set();
1530    ecore_x_window_prop_string_set(_root_1st, _atom[ATOM_E_PROFILE],
1531                                   _elm_profile);
1532 #endif
1533 }
1534
1535 void
1536 _elm_config_profile_set(const char *profile)
1537 {
1538    Eina_Bool changed = EINA_FALSE;
1539
1540    if (_elm_profile)
1541      {
1542         if (strcmp(_elm_profile, profile))
1543           changed = 1;
1544         free(_elm_profile);
1545      }
1546
1547    _elm_profile = strdup(profile);
1548
1549    if (changed)
1550      {
1551         _config_free();
1552         _config_load();
1553         _config_apply();
1554         _elm_config_font_overlay_apply();
1555         _elm_rescale();
1556         _elm_recache();
1557      }
1558 }
1559
1560 void
1561 _elm_config_shutdown(void)
1562 {
1563 #ifdef HAVE_ELEMENTARY_X
1564    if (_prop_all_update_timer)
1565      {
1566         ecore_timer_del(_prop_all_update_timer);
1567         _prop_all_update_cb(NULL);
1568      }
1569    _prop_all_update_timer = NULL;
1570    if (_prop_change_delay_timer) ecore_timer_del(_prop_change_delay_timer);
1571    _prop_change_delay_timer = NULL;
1572 #endif
1573
1574 #define ENGINE_COMPARE(name) (!strcmp(_elm_config->engine, name))
1575    if (ENGINE_COMPARE(ELM_SOFTWARE_X11) ||
1576        ENGINE_COMPARE(ELM_SOFTWARE_16_X11) ||
1577        ENGINE_COMPARE(ELM_XRENDER_X11) ||
1578        ENGINE_COMPARE(ELM_OPENGL_X11))
1579 #undef ENGINE_COMPARE
1580      {
1581 #ifdef HAVE_ELEMENTARY_X
1582         ecore_event_handler_del(_prop_change_handler);
1583         _prop_change_handler = NULL;
1584 #endif
1585      }
1586    _config_free();
1587    if (_elm_profile)
1588      {
1589         free(_elm_profile);
1590         _elm_profile = NULL;
1591      }
1592    _desc_shutdown();
1593 }
1594