[WM_ROT] Fixed floating mode window rotation bug that window doesn't send ROTATION_DO...
[platform/core/uifw/e17.git] / src / bin / e_fm_custom.c
1 #include "e.h"
2
3 static Eina_Bool _e_fm2_custom_file_hash_foreach_list(const Eina_Hash *hash, const void *key, void *data, void *fdata);
4 static Eina_List *_e_fm2_custom_hash_key_base_list(Eina_Hash *hash, const char *str);
5 //static Eina_Bool _e_fm2_custom_file_hash_foreach_sub_list(Eina_Hash *hash, const char *key, void *data, void *fdata);
6 //static Eina_List *_e_fm2_custom_hash_key_sub_list(Eina_Hash *hash, const char *str);
7 static Eina_Bool _e_fm2_custom_file_hash_foreach(const Eina_Hash *hash, const void *key, void *data, void *fdata);
8 static Eina_Bool _e_fm2_custom_file_hash_foreach_save(const Eina_Hash *hash, const void *key, void *data, void *fdata);
9 static void _e_fm2_custom_file_info_load(void);
10 static void _e_fm2_custom_file_info_save(void);
11 static void _e_fm2_custom_file_info_free(void);
12 static void _e_fm2_custom_file_cb_defer_save(void *data);
13
14 static E_Powersave_Deferred_Action*_e_fm2_flush_defer = NULL;
15 static Eet_File *_e_fm2_custom_file = NULL;
16 static Eet_Data_Descriptor *_e_fm2_custom_file_edd = NULL;
17 static Eet_Data_Descriptor *_e_fm2_custom_dir_edd = NULL;
18 static Eina_Hash *_e_fm2_custom_hash = NULL;
19 static int _e_fm2_custom_writes = 0;
20 static int _e_fm2_custom_init = 0;
21
22 /* FIXME: this uses a flat path key for custom file info. this is fine as
23  * long as we only expect a limited number of custom info nodes. if we
24  * start to see whole dire trees stored this way things will suck. we need
25  * to use a tree struct to store this so deletes and renmes are sane.
26  */
27
28 /* externally accessible functions */
29 EINTERN int
30 e_fm2_custom_file_init(void)
31 {
32    Eet_Data_Descriptor_Class eddc;
33
34    _e_fm2_custom_init++;
35    if (_e_fm2_custom_init > 1) return _e_fm2_custom_init;
36
37    if (!eet_eina_stream_data_descriptor_class_set(&eddc, sizeof (eddc), "e_fm2_custom_dir", sizeof (E_Fm2_Custom_Dir)))
38      {
39         _e_fm2_custom_init--;
40         return 0;
41      }
42
43    _e_fm2_custom_hash = eina_hash_string_superfast_new(NULL);
44
45    _e_fm2_custom_dir_edd = eet_data_descriptor_stream_new(&eddc);
46 #define DAT(x, y, z) EET_DATA_DESCRIPTOR_ADD_BASIC(_e_fm2_custom_dir_edd, E_Fm2_Custom_Dir, x, y, z)
47    DAT("pos.x", pos.x, EET_T_DOUBLE);
48    DAT("pos.y", pos.y, EET_T_DOUBLE);
49    DAT("prop.icon_size", prop.icon_size, EET_T_SHORT);
50    DAT("prop.view_mode", prop.view_mode, EET_T_CHAR);
51    DAT("prop.order_file", prop.order_file, EET_T_UCHAR);
52    DAT("prop.show_hidden_files", prop.show_hidden_files, EET_T_UCHAR);
53    DAT("prop.in_use", prop.in_use, EET_T_UCHAR);
54 #undef DAT
55
56    eddc.size = sizeof (E_Fm2_Custom_File);
57    eddc.name = "e_fm_custom_file";
58
59    _e_fm2_custom_file_edd = eet_data_descriptor_stream_new(&eddc);
60 #define DAT(x, y, z) EET_DATA_DESCRIPTOR_ADD_BASIC(_e_fm2_custom_file_edd, E_Fm2_Custom_File, x, y, z)
61    DAT("g.x", geom.x, EET_T_INT);
62    DAT("g.y", geom.y, EET_T_INT);
63    DAT("g.w", geom.w, EET_T_INT);
64    DAT("g.h", geom.h, EET_T_INT);
65    DAT("g.rw", geom.res_w, EET_T_INT);
66    DAT("g.rh", geom.res_h, EET_T_INT);
67    DAT("g.s", geom.scale, EET_T_DOUBLE);
68    DAT("g.v", geom.valid, EET_T_UCHAR);
69
70    DAT("i.t", icon.type, EET_T_INT);
71    DAT("i.i", icon.icon, EET_T_STRING);
72    DAT("i.v", icon.valid, EET_T_UCHAR);
73
74    DAT("l", label, EET_T_STRING);
75
76 #undef DAT
77
78    EET_DATA_DESCRIPTOR_ADD_SUB(_e_fm2_custom_file_edd, E_Fm2_Custom_File, "dir",
79                                dir, _e_fm2_custom_dir_edd);
80
81    return 1;
82 }
83
84 EINTERN void
85 e_fm2_custom_file_shutdown(void)
86 {
87    _e_fm2_custom_init--;
88    if (_e_fm2_custom_init != 0) return;
89
90    _e_fm2_custom_file_info_save();
91    _e_fm2_custom_file_info_free();
92    if (_e_fm2_flush_defer) e_powersave_deferred_action_del(_e_fm2_flush_defer);
93    _e_fm2_flush_defer = NULL;
94    eet_data_descriptor_free(_e_fm2_custom_file_edd);
95    _e_fm2_custom_file_edd = NULL;
96    eet_data_descriptor_free(_e_fm2_custom_dir_edd);
97    _e_fm2_custom_dir_edd = NULL;
98 }
99
100 EAPI E_Fm2_Custom_File *
101 e_fm2_custom_file_get(const char *path)
102 {
103    E_Fm2_Custom_File *cf;
104
105    _e_fm2_custom_file_info_load();
106    if (!_e_fm2_custom_file) return NULL;
107    if (_e_fm2_flush_defer) e_fm2_custom_file_flush();
108    cf = eina_hash_find(_e_fm2_custom_hash, path);
109    return cf;
110 }
111
112 static void
113 _e_fm2_custom_dir_del(E_Fm2_Custom_Dir *dir)
114 {
115    free(dir);
116 }
117
118 static void
119 _e_fm2_custom_file_del(E_Fm2_Custom_File *cf)
120 {
121    if (!cf) return;
122
123    eina_stringshare_del(cf->icon.icon);
124    eina_stringshare_del(cf->label);
125    _e_fm2_custom_dir_del(cf->dir);
126    free(cf);
127 }
128
129 static E_Fm2_Custom_Dir *
130 _e_fm2_custom_dir_dup(const E_Fm2_Custom_Dir *dir)
131 {
132    E_Fm2_Custom_Dir *copy;
133
134    if (!dir) return NULL;
135
136    copy = calloc(1, sizeof(*copy));
137    if (!copy) return NULL;
138
139    memcpy(copy, dir, sizeof(*copy));
140    return copy;
141 }
142
143 EAPI E_Fm2_Custom_File *
144 e_fm2_custom_file_dup(const E_Fm2_Custom_File *cf)
145 {
146    E_Fm2_Custom_File *copy;
147
148    if (!cf) return NULL;
149
150    copy = calloc(1, sizeof(*copy));
151    if (!copy) return NULL;
152
153    memcpy(copy, cf, sizeof(*copy));
154    copy->icon.icon = eina_stringshare_add(cf->icon.icon);
155    copy->label = eina_stringshare_add(cf->label);
156    copy->dir = _e_fm2_custom_dir_dup(cf->dir);
157    return copy;
158 }
159
160 EAPI void
161 e_fm2_custom_file_set(const char *path, const E_Fm2_Custom_File *cf)
162 {
163    E_Fm2_Custom_File *cf1;
164    _e_fm2_custom_file_info_load();
165    if (!_e_fm2_custom_file) return;
166    if (_e_fm2_flush_defer) e_fm2_custom_file_flush();
167
168    cf1 = eina_hash_find(_e_fm2_custom_hash, path);
169    if ((cf1 != cf) || ((cf1) && (cf) && (cf1->dir != cf->dir)))
170      {
171         E_Fm2_Custom_File *cf2 = e_fm2_custom_file_dup(cf);
172         if (cf2)
173           {
174              if (cf1)
175                {
176                   eina_hash_modify(_e_fm2_custom_hash, path, cf2);
177                   _e_fm2_custom_file_del(cf1);
178                }
179              else
180                eina_hash_add(_e_fm2_custom_hash, path, cf2);
181           }
182      }
183    _e_fm2_custom_writes = 1;
184 }
185
186 EAPI void
187 e_fm2_custom_file_del(const char *path)
188 {
189    Eina_List *list, *l;
190    E_Fm2_Custom_File *cf2;
191    const void *key;
192
193    _e_fm2_custom_file_info_load();
194    if (!_e_fm2_custom_file) return;
195    if (_e_fm2_flush_defer) e_fm2_custom_file_flush();
196
197    list = _e_fm2_custom_hash_key_base_list(_e_fm2_custom_hash, path);
198    if (list)
199      {
200         EINA_LIST_FOREACH(list, l, key)
201           {
202              cf2 = eina_hash_find(_e_fm2_custom_hash, key);
203              if (cf2)
204                {
205                   eina_hash_del(_e_fm2_custom_hash, key, cf2);
206                   _e_fm2_custom_file_del(cf2);
207                }
208           }
209         eina_list_free(list);
210      }
211    _e_fm2_custom_writes = 1;
212 }
213
214 EAPI void
215 e_fm2_custom_file_rename(const char *path, const char *new_path)
216 {
217    E_Fm2_Custom_File *cf, *cf2;
218    Eina_List *list, *l;
219    const void *key;
220
221    _e_fm2_custom_file_info_load();
222    if (!_e_fm2_custom_file) return;
223    if (_e_fm2_flush_defer) e_fm2_custom_file_flush();
224    cf2 = eina_hash_find(_e_fm2_custom_hash, path);
225    if (cf2)
226      {
227         eina_hash_del(_e_fm2_custom_hash, path, cf2);
228         cf = eina_hash_find(_e_fm2_custom_hash, new_path);
229         if (cf)
230           _e_fm2_custom_file_del(cf);
231         eina_hash_add(_e_fm2_custom_hash, new_path, cf2);
232      }
233    list = _e_fm2_custom_hash_key_base_list(_e_fm2_custom_hash, path);
234    if (list)
235      {
236         EINA_LIST_FOREACH(list, l, key)
237           {
238              cf2 = eina_hash_find(_e_fm2_custom_hash, key);
239              if (cf2)
240                {
241                   char buf[PATH_MAX];
242
243                   strcpy(buf, new_path);
244                   strcat(buf, (char *)key + strlen(path));
245                   eina_hash_del(_e_fm2_custom_hash, key, cf2);
246                   cf = eina_hash_find(_e_fm2_custom_hash, buf);
247                   if (cf)
248                     _e_fm2_custom_file_del(cf);
249                   eina_hash_add(_e_fm2_custom_hash, buf, cf2);
250                }
251           }
252         eina_list_free(list);
253      }
254    _e_fm2_custom_writes = 1;
255 }
256
257 EAPI void
258 e_fm2_custom_file_flush(void)
259 {
260    if (!_e_fm2_custom_file) return;
261
262    if (_e_fm2_flush_defer)
263      e_powersave_deferred_action_del(_e_fm2_flush_defer);
264    _e_fm2_flush_defer =
265      e_powersave_deferred_action_add(_e_fm2_custom_file_cb_defer_save, NULL);
266 }
267
268 /**/
269
270 struct _E_Custom_List
271 {
272    Eina_List  *l;
273    const char *base;
274    int         base_len;
275 };
276
277 static Eina_Bool
278 _e_fm2_custom_file_hash_foreach_list(const Eina_Hash *hash __UNUSED__, const void *key, void *data __UNUSED__, void *fdata)
279 {
280    struct _E_Custom_List *cl;
281
282    cl = fdata;
283    if (!strncmp(cl->base, key, cl->base_len))
284      cl->l = eina_list_append(cl->l, key);
285    return 1;
286 }
287
288 static Eina_List *
289 _e_fm2_custom_hash_key_base_list(Eina_Hash *hash, const char *str)
290 {
291    struct _E_Custom_List cl;
292
293    cl.l = NULL;
294    cl.base = str;
295    cl.base_len = strlen(cl.base);
296    eina_hash_foreach(hash, _e_fm2_custom_file_hash_foreach_list, &cl);
297    return cl.l;
298 }
299
300 /*
301 static Eina_Bool
302 _e_fm2_custom_file_hash_foreach_sub_list(const Eina_Hash *hash, const void *key, void *data, void *fdata)
303 {
304    struct _E_Custom_List *cl;
305
306    cl = fdata;
307    if (!strncmp(cl->base, key, strlen(key)))
308      cl->l = eina_list_append(cl->l, key);
309    return 1;
310 }
311 */
312
313 /*
314 static Eina_List *
315 _e_fm2_custom_hash_key_sub_list(const Eina_Hash *hash, const void *str)
316 {
317    struct _E_Custom_List cl;
318
319    cl.l = NULL;
320    cl.base = str;
321    eina_hash_foreach(hash,
322                      _e_fm2_custom_file_hash_foreach_sub_list, &cl);
323    return cl.l;
324 }
325 */
326
327 static Eina_Bool
328 _e_fm2_custom_file_hash_foreach(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
329 {
330    _e_fm2_custom_file_del(data);
331    return 1;
332 }
333
334 static Eina_Bool
335 _e_fm2_custom_file_hash_foreach_save(const Eina_Hash *hash __UNUSED__, const void *key, void *data, void *fdata)
336 {
337    Eet_File *ef;
338    E_Fm2_Custom_File *cf;
339
340    ef = fdata;
341    cf = data;
342    eet_data_write(ef, _e_fm2_custom_file_edd, key, cf, 1);
343    return 1;
344 }
345
346 static void
347 _e_fm2_custom_file_info_load(void)
348 {
349    char buf[PATH_MAX];
350
351    if (_e_fm2_custom_file) return;
352    _e_fm2_custom_writes = 0;
353    e_user_dir_concat_static(buf, "fileman/custom.cfg");
354    _e_fm2_custom_file = eet_open(buf, EET_FILE_MODE_READ);
355    if (!_e_fm2_custom_file)
356      _e_fm2_custom_file = eet_open(buf, EET_FILE_MODE_WRITE);
357    if (_e_fm2_custom_file)
358      {
359         E_Fm2_Custom_File *cf;
360         char **list;
361         int i, num;
362
363         list = eet_list(_e_fm2_custom_file, "*", &num);
364         if (list)
365           {
366              for (i = 0; i < num; i++)
367                {
368                   cf = eet_data_read(_e_fm2_custom_file,
369                                      _e_fm2_custom_file_edd, list[i]);
370                   if (cf)
371                     eina_hash_add(_e_fm2_custom_hash, list[i], cf);
372                }
373              free(list);
374           }
375      }
376 }
377
378 static void
379 _e_fm2_custom_file_info_save(void)
380 {
381    Eet_File *ef;
382    char buf[PATH_MAX], buf2[PATH_MAX];
383    size_t len;
384    int ret;
385
386    if (!_e_fm2_custom_file) return;
387    if (!_e_fm2_custom_writes) return;
388
389    len = e_user_dir_concat_static(buf, "fileman/custom.cfg.tmp");
390    if (len >= sizeof(buf)) return;
391    ef = eet_open(buf, EET_FILE_MODE_WRITE);
392    if (!ef) return;
393    eina_hash_foreach(_e_fm2_custom_hash,
394                      _e_fm2_custom_file_hash_foreach_save, ef);
395    eet_close(ef);
396
397    memcpy(buf2, buf, len - (sizeof(".tmp") - 1));
398    buf2[len - (sizeof(".tmp") - 1)] = '\0';
399    eet_close(_e_fm2_custom_file);
400    _e_fm2_custom_file = NULL;
401    ret = rename(buf, buf2);
402    if (ret < 0)
403      {
404         /* FIXME: do we want to trap individual errno
405          and provide a short blurp to the user? */
406         perror("rename");
407      }
408 }
409
410 static void
411 _e_fm2_custom_file_info_free(void)
412 {
413    _e_fm2_custom_writes = 0;
414    if (_e_fm2_custom_file)
415      {
416         eet_close(_e_fm2_custom_file);
417         _e_fm2_custom_file = NULL;
418      }
419    if (_e_fm2_custom_hash)
420      {
421         eina_hash_foreach(_e_fm2_custom_hash,
422                           _e_fm2_custom_file_hash_foreach, NULL);
423         eina_hash_free(_e_fm2_custom_hash);
424         _e_fm2_custom_hash = eina_hash_string_superfast_new(NULL);
425      }
426 }
427
428 static void
429 _e_fm2_custom_file_cb_defer_save(void *data __UNUSED__)
430 {
431    _e_fm2_custom_file_info_save();
432    _e_fm2_custom_file_info_free();
433    _e_fm2_flush_defer = NULL;
434 }