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