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