efl

Форк
0
/
efreet_icon_cache_create.c 
1196 строк · 34.2 Кб
1
#ifdef HAVE_CONFIG_H
2
# include <config.h>
3
#endif
4

5
#include <fcntl.h>
6
#include <unistd.h>
7
#include <errno.h>
8
#ifdef HAVE_SYS_RESOURCE_H
9
#include <sys/time.h>
10
#include <sys/resource.h>
11
#endif
12

13
#ifdef _WIN32
14
# include <evil_private.h> /* fcntl */
15
#endif
16

17
#include <Eina.h>
18
#include <Eet.h>
19
#include <Ecore.h>
20
#include <Ecore_File.h>
21

22
#define EFREET_MODULE_LOG_DOM _efreet_icon_cache_log_dom
23
static int _efreet_icon_cache_log_dom = -1;
24

25
#include "Efreet.h"
26
#include "efreet_private.h"
27
#include "efreet_cache_private.h"
28

29
#ifndef O_BINARY
30
# define O_BINARY 0
31
#endif
32

33
static Eina_Array *exts = NULL;
34
static Eina_Array *extra_dirs = NULL;
35
static Eina_Array *strs = NULL;
36
static Eina_Hash *icon_themes = NULL;
37

38
static Eina_Bool
39
cache_directory_modified(Eina_Hash *dirs, const char *dir)
40
{
41
   Efreet_Cache_Directory *dcache;
42
   Efreet_Cache_Check check;
43

44
   if (!dirs) return EINA_TRUE;
45
   if (!efreet_file_cache_fill(dir, &check)) return EINA_FALSE;
46
   dcache = eina_hash_find(dirs, dir);
47
   if (!dcache)
48
     {
49
        dcache = malloc(sizeof (Efreet_Cache_Directory));
50
        if (!dcache) return EINA_TRUE;
51
        dcache->check = check;
52
        eina_hash_add(dirs, dir, dcache);
53
     }
54
   else if (efreet_file_cache_check(&check, &dcache->check))
55
     return EINA_FALSE;
56
   else
57
     dcache->check = check;
58
   return EINA_TRUE;
59
}
60

61
static Eina_Bool
62
cache_extension_lookup(const char *ext)
63
{
64
   unsigned int i;
65

66
   for (i = 0; i < exts->count; ++i)
67
     {
68
        if (!strcmp(exts->data[i], ext)) return EINA_TRUE;
69
     }
70
   return EINA_FALSE;
71
}
72

73
static Eina_Bool
74
cache_fallback_scan_dir(Eina_Hash *icons, Eina_Hash *dirs, const char *dir)
75
{
76
    Eina_Iterator *it;
77
    Eina_File_Direct_Info *entry;
78

79
    if (!cache_directory_modified(dirs, dir)) return EINA_TRUE;
80

81
    it = eina_file_stat_ls(dir);
82
    if (!it) return EINA_TRUE;
83

84
    EINA_ITERATOR_FOREACH(it, entry)
85
    {
86
        Efreet_Cache_Fallback_Icon *icon;
87
        char *name;
88
        char *ext;
89
        unsigned int i;
90
        void *p;
91

92
        if (entry->type == EINA_FILE_DIR)
93
            continue;
94

95
        ext = strrchr(entry->path + entry->name_start, '.');
96
        if (!ext || !cache_extension_lookup(ext))
97
            continue;
98

99
        /* icon with known extension */
100
        name = entry->path + entry->name_start;
101
        *ext = '\0';
102

103
        icon = eina_hash_find(icons, name);
104
        if (!icon)
105
        {
106
            icon = NEW(Efreet_Cache_Fallback_Icon, 1);
107
            icon->theme = NULL;
108
            eina_hash_add(icons, name, icon);
109
        }
110

111
        *ext = '.';
112

113
        for (i = 0; i < icon->icons_count; ++i)
114
            if (!strcmp(icon->icons[i], entry->path))
115
                break;
116

117
        if (i != icon->icons_count)
118
            continue;
119

120
        p = realloc(icon->icons, sizeof (char *) * (icon->icons_count + 1));
121
        if (!p)
122
          {
123
             ERR("Out of memory");
124
             exit(1);
125
          }
126
        icon->icons = p;
127
        icon->icons[icon->icons_count] = eina_stringshare_add(entry->path);
128
        eina_array_push(strs, icon->icons[icon->icons_count++]);
129
    }
130

131
    eina_iterator_free(it);
132

133
    return EINA_TRUE;
134
}
135

136
static Eina_Bool
137
cache_fallback_scan(Eina_Hash *icons, Eina_Hash *dirs)
138
{
139
    unsigned int i;
140
    Eina_List *xdg_dirs, *l;
141
    const char *dir;
142
    char path[PATH_MAX];
143

144
    for (i = 0; i < extra_dirs->count; i++)
145
        cache_fallback_scan_dir(icons, dirs, extra_dirs->data[i]);
146

147
    cache_fallback_scan_dir(icons, dirs, efreet_icon_deprecated_user_dir_get());
148
    cache_fallback_scan_dir(icons, dirs, efreet_icon_user_dir_get());
149

150
    xdg_dirs = efreet_data_dirs_get();
151
    EINA_LIST_FOREACH(xdg_dirs, l, dir)
152
    {
153
        snprintf(path, sizeof(path), "%s/icons", dir);
154
        cache_fallback_scan_dir(icons, dirs, path);
155
    }
156

157
#ifndef STRICT_SPEC
158
    EINA_LIST_FOREACH(xdg_dirs, l, dir)
159
    {
160
        snprintf(path, sizeof(path), "%s/pixmaps", dir);
161
        cache_fallback_scan_dir(icons, dirs, path);
162
    }
163
#endif
164

165
    cache_fallback_scan_dir(icons, dirs, "/usr/local/share/pixmaps");
166
    cache_fallback_scan_dir(icons, dirs, "/usr/share/pixmaps");
167

168
    return EINA_TRUE;
169
}
170

171
static Eina_Bool
172
check_fallback_changed(Efreet_Cache_Icon_Theme *theme)
173
{
174
    unsigned int i;
175
    Eina_List *xdg_dirs, *l;
176
    const char *dir;
177
    char path[PATH_MAX];
178

179
    /* Check if the dirs we have cached are changed */
180
    if (theme->dirs)
181
    {
182
        Eina_Iterator *it;
183
        Eina_Bool changed = EINA_FALSE;
184

185
        it = eina_hash_iterator_key_new(theme->dirs);
186
        EINA_ITERATOR_FOREACH(it, dir)
187
        {
188
            changed = !ecore_file_exists(dir);
189
            if (changed) break;
190
            changed = cache_directory_modified(theme->dirs, dir);
191
            if (changed) break;
192
        }
193
        eina_iterator_free(it);
194
        if (changed) return EINA_TRUE;
195
    }
196

197
    /* Check if spec dirs have changed */
198
    for (i = 0; i < extra_dirs->count; i++)
199
        if (cache_directory_modified(theme->dirs, extra_dirs->data[i])) return EINA_TRUE;
200

201
    if (cache_directory_modified(theme->dirs, efreet_icon_deprecated_user_dir_get())) return EINA_TRUE;
202
    if (cache_directory_modified(theme->dirs, efreet_icon_user_dir_get())) return EINA_TRUE;
203

204
    xdg_dirs = efreet_data_dirs_get();
205
    EINA_LIST_FOREACH(xdg_dirs, l, dir)
206
    {
207
        snprintf(path, sizeof(path), "%s/icons", dir);
208
        if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE;
209
    }
210

211
#ifndef STRICT_SPEC
212
    EINA_LIST_FOREACH(xdg_dirs, l, dir)
213
    {
214
        snprintf(path, sizeof(path), "%s/pixmaps", dir);
215
        if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE;
216
    }
217
#endif
218

219
    if (cache_directory_modified(theme->dirs, "/usr/local/share/pixmaps")) return EINA_TRUE;
220
    if (cache_directory_modified(theme->dirs, "/usr/share/pixmaps")) return EINA_TRUE;
221
    return EINA_FALSE;
222
}
223

224
typedef struct
225
{
226
  char *path;
227
  int name_start;
228
} Scanned_Entry;
229

230
static Eina_Hash *already_scanned_path = NULL;
231

232
static void
233
cache_theme_change_verify(Efreet_Cache_Icon_Theme *theme)
234
{
235
   Eina_Bool changed = EINA_FALSE;
236
   Eina_List *l;
237
   Efreet_Icon_Theme_Directory *d;
238
   char buf[PATH_MAX], *tdir, *sep;
239

240
   tdir = strdup(theme->path);
241
   sep = strrchr(tdir, '/');
242
   if (sep) *sep = 0;
243
   EINA_LIST_FOREACH(theme->theme.directories, l, d)
244
     {
245
        snprintf(buf, sizeof(buf), "%s/%s", tdir, d->name);
246
        if (cache_directory_modified(theme->dirs, buf))
247
          {
248
             changed = EINA_TRUE;
249
          }
250
     }
251
   free(tdir);
252
   if (changed) theme->changed = changed;
253
}
254

255
static Eina_Bool
256
cache_scan_path_dir(Efreet_Icon_Theme *theme,
257
                    const char *path,
258
                    Efreet_Icon_Theme_Directory *dir,
259
                    Eina_Hash *icons)
260
{
261
    Eina_Iterator *it;
262
    char buf[PATH_MAX];
263
    Eina_File_Direct_Info *entry;
264
    Eina_List *dirs = NULL;
265
    Eina_List *l;
266
    char *ext;
267
    Scanned_Entry *scentry;
268

269
    snprintf(buf, sizeof(buf), "%s/%s", path, dir->name);
270
    // we wont ever free this - no point
271
    if (!already_scanned_path)
272
      already_scanned_path = eina_hash_string_superfast_new(NULL);
273
    dirs = eina_hash_find(already_scanned_path, buf);
274
    if ((intptr_t)dirs == (intptr_t)(-1L)) return EINA_TRUE;
275
    else if (!dirs)
276
    {
277
       it = eina_file_stat_ls(buf);
278
       if (!it)
279
         {
280
            eina_hash_add(already_scanned_path, buf, (void *)(intptr_t)(-1L));
281
            return EINA_TRUE;
282
         }
283

284
       EINA_ITERATOR_FOREACH(it, entry)
285
         {
286
            if (entry->type == EINA_FILE_DIR) continue;
287
            ext = strrchr(entry->path + entry->name_start, '.');
288
            if (!ext || !cache_extension_lookup(ext)) continue;
289
            scentry = malloc(sizeof(Scanned_Entry));
290
            if (!scentry)
291
              {
292
                 ERR("Out of memory");
293
                 exit(1);
294
              }
295
            scentry->name_start = entry->name_start;
296
            scentry->path = strdup(entry->path);
297
            if (!scentry->path)
298
              {
299
                 ERR("Out of memory");
300
                 exit(1);
301
              }
302
            dirs = eina_list_append(dirs, scentry);
303
         }
304
       eina_iterator_free(it);
305
       if (dirs)
306
         eina_hash_add(already_scanned_path, buf, dirs);
307
       else
308
         eina_hash_add(already_scanned_path, buf, (void *)(intptr_t)(-1L));
309
    }
310

311
   EINA_LIST_FOREACH(dirs, l, scentry)
312
    {
313
        Efreet_Cache_Icon *icon;
314
        char *name;
315
        const char **tmp;
316
        unsigned int i;
317

318
        ext = strrchr(scentry->path + scentry->name_start, '.');
319
        if (!ext) continue;
320
        /* icon with known extension */
321
        name = scentry->path + scentry->name_start;
322
        *ext = '\0';
323

324
        icon = eina_hash_find(icons, name);
325
        if (!icon)
326
        {
327
            icon = NEW(Efreet_Cache_Icon, 1);
328
            icon->theme = eina_stringshare_add(theme->name.internal);
329
            eina_array_push(strs, icon->theme);
330
            eina_hash_add(icons, name, icon);
331
        }
332

333
        /* find if we have the same icon in another type */
334
        for (i = 0; i < icon->icons_count; ++i)
335
        {
336
            if ((icon->icons[i]->type == dir->type) &&
337
                (icon->icons[i]->normal == dir->size.normal) &&
338
                (icon->icons[i]->max == dir->size.max) &&
339
                (icon->icons[i]->min == dir->size.min))
340
                break;
341
        }
342

343
        *ext = '.';
344

345
        if (i != icon->icons_count)
346
        {
347
            unsigned int j;
348

349
            /* check if the path already exist */
350
            for (j = 0; j < icon->icons[i]->paths_count; ++j)
351
                if (!strcmp(icon->icons[i]->paths[j], scentry->path))
352
                    break;
353

354
            if (j != icon->icons[i]->paths_count)
355
                continue;
356

357
            /* If we are inherited, check if we already have extension */
358
            if (strcmp(icon->theme, theme->name.internal))
359
            {
360
                const char *ext2;
361
                int has_ext = 0;
362
                for (j = 0; j < icon->icons[i]->paths_count; ++j)
363
                {
364
                    ext2 = strrchr(icon->icons[i]->paths[j], '.');
365
                    if (ext2)
366
                    {
367
                        ext2++;
368
                        has_ext = !strcmp((ext + 1), ext2);
369
                        if (has_ext) break;
370
                    }
371
                }
372
                if (has_ext)
373
                    continue;
374
            }
375
        }
376
        /* no icon match so add a new one */
377
        /* only allow to add new icon for main theme
378
         * if we allow inherited theme to add new icons,
379
         * we will get weird effects when icon scales
380
         */
381
        else if (!strcmp(icon->theme, theme->name.internal))
382
        {
383
            Efreet_Cache_Icon_Element **tmp2;
384

385
            tmp2 = realloc(icon->icons,
386
                          sizeof(Efreet_Cache_Icon_Element *) * (++icon->icons_count));
387
            if (!tmp2)
388
            {
389
               ERR("Out of memory");
390
               exit(1);
391
            }
392
            icon->icons = tmp2;
393
            icon->icons[i] = NEW(Efreet_Cache_Icon_Element, 1);
394
            icon->icons[i]->type = dir->type;
395
            icon->icons[i]->normal = dir->size.normal;
396
            icon->icons[i]->min = dir->size.min;
397
            icon->icons[i]->max = dir->size.max;
398
            icon->icons[i]->paths = NULL;
399
            icon->icons[i]->paths_count = 0;
400
        }
401
        else
402
        {
403
            continue;
404
        }
405

406
        /* and finally store the path */
407
        tmp = realloc(icon->icons[i]->paths,
408
                      sizeof(char *) * (icon->icons[i]->paths_count + 1));
409
        if (!tmp)
410
        {
411
           ERR("Out of memory");
412
           exit(1);
413
        }
414
        icon->icons[i]->paths = tmp;
415
        icon->icons[i]->paths[icon->icons[i]->paths_count] = eina_stringshare_add(scentry->path);
416
        eina_array_push(strs, icon->icons[i]->paths[icon->icons[i]->paths_count++]);
417
    }
418
    return EINA_TRUE;
419
}
420

421
static Eina_Bool
422
cache_scan_path(Efreet_Icon_Theme *theme, Eina_Hash *icons, const char *path)
423
{
424
    Eina_List *l;
425
    Efreet_Icon_Theme_Directory *dir;
426

427
    EINA_LIST_FOREACH(theme->directories, l, dir)
428
     {
429
        if (!cache_scan_path_dir(theme, path, dir, icons)) return EINA_FALSE;
430
     }
431

432
    return EINA_TRUE;
433
}
434

435
static Eina_Bool
436
cache_scan(Efreet_Icon_Theme *theme, Eina_Hash *themes, Eina_Hash *icons)
437
{
438
    Eina_List *l;
439
    const char *path;
440
    const char *name;
441

442
    if (!theme) return EINA_TRUE;
443
    if (eina_hash_find(themes, theme->name.internal)) return EINA_TRUE;
444
    eina_hash_direct_add(themes, theme->name.internal, theme);
445

446
    /* scan theme */
447
    EINA_LIST_FOREACH(theme->paths, l, path)
448
        if (!cache_scan_path(theme, icons, path)) return EINA_FALSE;
449

450
    /* scan inherits */
451
    if (theme->inherits)
452
    {
453
        EINA_LIST_FOREACH(theme->inherits, l, name)
454
        {
455
            Efreet_Icon_Theme *inherit;
456

457
            inherit = eina_hash_find(icon_themes, name);
458
            if (!inherit)
459
                INF("Theme `%s` not found for `%s`.",
460
                    name, theme->name.internal);
461
            if (!cache_scan(inherit, themes, icons)) return EINA_FALSE;
462
        }
463
    }
464
    else if (strcmp(theme->name.internal, "hicolor"))
465
    {
466
        theme = eina_hash_find(icon_themes, "hicolor");
467
        if (!cache_scan(theme, themes, icons)) return EINA_FALSE;
468
    }
469

470
    return EINA_TRUE;
471
}
472

473
static Eina_Bool
474
check_changed(Efreet_Cache_Icon_Theme *theme)
475
{
476
    Eina_List *l;
477
    const char *name;
478

479
    if (!theme) return EINA_FALSE;
480

481
    if (theme->changed) return EINA_TRUE;
482
    if (theme->theme.inherits)
483
    {
484
        EINA_LIST_FOREACH(theme->theme.inherits, l, name)
485
        {
486
            Efreet_Cache_Icon_Theme *inherit;
487

488
            inherit = eina_hash_find(icon_themes, name);
489
            if (!inherit)
490
                INF("Theme `%s` not found for `%s`.",
491
                        name, theme->theme.name.internal);
492
            if (check_changed(inherit)) return EINA_TRUE;
493
        }
494
    }
495
    else if (strcmp(theme->theme.name.internal, "hicolor"))
496
    {
497
        theme = eina_hash_find(icon_themes, "hicolor");
498
        if (check_changed(theme)) return EINA_TRUE;
499
    }
500
    return EINA_FALSE;
501
}
502

503
static Efreet_Icon_Theme_Directory *
504
icon_theme_directory_new(Efreet_Ini *ini, const char *name)
505
{
506
    Efreet_Icon_Theme_Directory *dir;
507
    int val;
508
    const char *tmp;
509

510
    if (!ini) return NULL;
511

512
    dir = NEW(Efreet_Icon_Theme_Directory, 1);
513
    if (!dir) return NULL;
514
    dir->name = eina_stringshare_add(name);
515
    eina_array_push(strs, dir->name);
516

517
    efreet_ini_section_set(ini, name);
518

519
    tmp = efreet_ini_string_get(ini, "Context");
520
    if (tmp)
521
    {
522
        if (!strcasecmp(tmp, "Actions"))
523
            dir->context = EFREET_ICON_THEME_CONTEXT_ACTIONS;
524

525
        else if (!strcasecmp(tmp, "Devices"))
526
            dir->context = EFREET_ICON_THEME_CONTEXT_DEVICES;
527

528
        else if (!strcasecmp(tmp, "FileSystems"))
529
            dir->context = EFREET_ICON_THEME_CONTEXT_FILESYSTEMS;
530

531
        else if (!strcasecmp(tmp, "MimeTypes"))
532
            dir->context = EFREET_ICON_THEME_CONTEXT_MIMETYPES;
533
    }
534

535
    /* Threshold is fallback  */
536
    dir->type = EFREET_ICON_SIZE_TYPE_THRESHOLD;
537

538
    tmp = efreet_ini_string_get(ini, "Type");
539
    if (tmp)
540
    {
541
        if (!strcasecmp(tmp, "Fixed"))
542
            dir->type = EFREET_ICON_SIZE_TYPE_FIXED;
543

544
        else if (!strcasecmp(tmp, "Scalable"))
545
            dir->type = EFREET_ICON_SIZE_TYPE_SCALABLE;
546
    }
547

548
    dir->size.normal = efreet_ini_int_get(ini, "Size");
549

550
    if (dir->type == EFREET_ICON_SIZE_TYPE_THRESHOLD)
551
    {
552
        val = efreet_ini_int_get(ini, "Threshold");
553
        if (val < 0) val = 2;
554
        dir->size.max = dir->size.normal + val;
555
        dir->size.min = dir->size.normal - val;
556
    }
557
    else if (dir->type == EFREET_ICON_SIZE_TYPE_SCALABLE)
558
    {
559
        val = efreet_ini_int_get(ini, "MinSize");
560
        if (val < 0) dir->size.min = dir->size.normal;
561
        else dir->size.min = val;
562

563
        val = efreet_ini_int_get(ini, "MaxSize");
564
        if (val < 0) dir->size.max = dir->size.normal;
565
        else dir->size.max = val;
566
    }
567

568
    return dir;
569
}
570

571
static Eina_Bool
572
icon_theme_index_read(Efreet_Cache_Icon_Theme *theme, const char *path)
573
{
574
    Efreet_Ini *ini;
575
    Efreet_Icon_Theme_Directory *dir;
576
    const char *tmp;
577
    Efreet_Cache_Check check;
578

579
    if (!theme || !path) return EINA_FALSE;
580

581
    if (!efreet_file_cache_fill(path, &check)) return EINA_FALSE;
582
    if (theme->path && !strcmp(theme->path, path) &&
583
        efreet_file_cache_check(&check, &(theme->check)))
584
    {
585
        /* no change */
586
        theme->valid = 1;
587
        return EINA_TRUE;
588
    }
589
    if (!theme->path || strcmp(theme->path, path))
590
    {
591
        theme->path = eina_stringshare_add(path);
592
        eina_array_push(strs, theme->path);
593
    }
594
    theme->check = check;
595
    theme->changed = 1;
596

597
    ini = efreet_ini_new(path);
598
    if (!ini) return EINA_FALSE;
599
    if (!ini->data)
600
    {
601
        efreet_ini_free(ini);
602
        return EINA_FALSE;
603
    }
604

605
    efreet_ini_section_set(ini, "Icon Theme");
606
    tmp = efreet_ini_localestring_get(ini, "Name");
607
    if (tmp)
608
    {
609
        theme->theme.name.name = eina_stringshare_add(tmp);
610
        eina_array_push(strs, theme->theme.name.name);
611
    }
612

613
    tmp = efreet_ini_localestring_get(ini, "Comment");
614
    if (tmp)
615
    {
616
        theme->theme.comment = eina_stringshare_add(tmp);
617
        eina_array_push(strs, theme->theme.comment);
618
    }
619

620
    tmp = efreet_ini_string_get(ini, "Example");
621
    if (tmp)
622
    {
623
        theme->theme.example_icon = eina_stringshare_add(tmp);
624
        eina_array_push(strs, theme->theme.example_icon);
625
    }
626

627
    theme->hidden = efreet_ini_boolean_get(ini, "Hidden");
628

629
    theme->valid = 1;
630

631
    /* Check the inheritance. If there is none we inherit from the hicolor theme */
632
    tmp = efreet_ini_string_get(ini, "Inherits");
633
    if (tmp)
634
    {
635
        char *t, *s, *p;
636
        const char *i;
637
        size_t len;
638

639
        len = strlen(tmp) + 1;
640
        t = alloca(len);
641
        memcpy(t, tmp, len);
642
        s = t;
643
        p = strchr(s, ',');
644

645
        while (p)
646
        {
647
            *p = '\0';
648

649
            i = eina_stringshare_add(s);
650
            theme->theme.inherits = eina_list_append(theme->theme.inherits, i);
651
            eina_array_push(strs, i);
652
            s = ++p;
653
            p = strchr(s, ',');
654
        }
655
        i = eina_stringshare_add(s);
656
        theme->theme.inherits = eina_list_append(theme->theme.inherits, i);
657
        eina_array_push(strs, i);
658
    }
659

660
    /* make sure this one is done last as setting the directory will change
661
     * the ini section ... */
662
    tmp = efreet_ini_string_get(ini, "Directories");
663
    if (tmp)
664
    {
665
        char *t, *s, *p;
666
        size_t len;
667

668
        len = strlen(tmp) + 1;
669
        t = alloca(len);
670
        memcpy(t, tmp, len);
671
        s = t;
672
        p = s;
673

674
        while ((p) && (*s))
675
        {
676
            p = strchr(s, ',');
677

678
            if (p) *p = '\0';
679

680
            dir = icon_theme_directory_new(ini, s);
681
            if (!dir) goto error;
682
            theme->theme.directories = eina_list_append(theme->theme.directories, dir);
683

684
            if (p) s = ++p;
685
        }
686
    }
687

688
error:
689
    efreet_ini_free(ini);
690

691
    return EINA_TRUE;
692
}
693

694
static Eina_Bool
695
cache_theme_scan(const char *dir)
696
{
697
    Eina_Iterator *it;
698
    Eina_File_Direct_Info *entry;
699

700
    it = eina_file_stat_ls(dir);
701
    if (!it) return EINA_TRUE;
702

703
    EINA_ITERATOR_FOREACH(it, entry)
704
    {
705
        char buf[PATH_MAX];
706
        Efreet_Cache_Icon_Theme *theme;
707
        const char *name;
708
        const char *path;
709
        Efreet_Cache_Check check;
710
        Efreet_Cache_Directory *d;
711

712
        if (!efreet_file_cache_fill(entry->path, &check)) continue;
713

714
        if ((entry->type != EINA_FILE_DIR) &&
715
            (entry->type != EINA_FILE_LNK))
716
            continue;
717

718
        if ((entry->type == EINA_FILE_LNK) &&
719
            (!ecore_file_is_dir(entry->path)))
720
            continue;
721

722
        name = entry->path + entry->name_start;
723
        theme = eina_hash_find(icon_themes, name);
724

725
        if (!theme)
726
        {
727
            theme = NEW(Efreet_Cache_Icon_Theme, 1);
728
            theme->theme.name.internal = eina_stringshare_add(name);
729
            eina_array_push(strs, theme->theme.name.internal);
730
            eina_hash_direct_add(icon_themes,
731
                          (void *)theme->theme.name.internal, theme);
732
            theme->changed = 1;
733
        }
734

735
       d = NULL;
736
       if (theme->dirs)
737
         d = eina_hash_find(theme->dirs, entry->path);
738
       if (!d)
739
         {
740
            if (!theme->dirs)
741
              theme->dirs = eina_hash_string_superfast_new(NULL);
742
            theme->changed = 1;
743
            d = NEW(Efreet_Cache_Directory, 1);
744
            d->check = check;
745
            eina_hash_add(theme->dirs, entry->path, d);
746
         }
747
       else
748
         {
749
            if (!efreet_file_cache_check(&check, &(d->check)))
750
              {
751
                 d->check = check;
752
                 theme->changed = 1;
753
              }
754
        }
755

756
        /* TODO: We need to handle change in order of included paths */
757
        if (!eina_list_search_unsorted(theme->theme.paths, EINA_COMPARE_CB(strcmp), entry->path))
758
        {
759
            path = eina_stringshare_add(entry->path);
760
            theme->theme.paths = eina_list_append(theme->theme.paths, path);
761
            eina_array_push(strs, path);
762
            theme->changed = 1;
763
        }
764

765
        /* we're already valid so no reason to check for an index.theme file */
766
        if (theme->valid) continue;
767

768
        /* if the index.theme file exists we parse it into the theme */
769
        memcpy(buf, entry->path, entry->path_length);
770
        memcpy(buf + entry->path_length, "/index.theme", sizeof("/index.theme"));
771
        if (ecore_file_exists(buf))
772
        {
773
            if (!icon_theme_index_read(theme, buf))
774
                theme->valid = 0;
775
        }
776
    }
777
    eina_iterator_free(it);
778
    return EINA_TRUE;
779
}
780

781
static int
782
cache_lock_file(void)
783
{
784
    char file[PATH_MAX];
785
    struct flock fl;
786
    int lockfd;
787

788
    snprintf(file, sizeof(file), "%s/efreet/icon_data.lock", efreet_cache_home_get());
789
    lockfd = open(file, O_CREAT | O_BINARY | O_RDWR, S_IRUSR | S_IWUSR);
790
    if (lockfd < 0) return -1;
791
    efreet_fsetowner(lockfd);
792

793
    memset(&fl, 0, sizeof(struct flock));
794
    fl.l_type = F_WRLCK;
795
    fl.l_whence = SEEK_SET;
796
    if (fcntl(lockfd, F_SETLK, &fl) < 0)
797
    {
798
        WRN("LOCKED! You may want to delete %s if this persists", file);
799
        close(lockfd);
800
        return -1;
801
    }
802

803
    return lockfd;
804
}
805

806
static void
807
icon_theme_free(Efreet_Cache_Icon_Theme *theme)
808
{
809
    void *data;
810

811
    eina_list_free(theme->theme.paths);
812
    eina_list_free(theme->theme.inherits);
813
    EINA_LIST_FREE(theme->theme.directories, data) free(data);
814
    if (theme->dirs) efreet_hash_free(theme->dirs, free);
815
    free(theme);
816
}
817

818
int
819
main(int argc, char **argv)
820
{
821
    /* TODO:
822
     * - Add file monitor on files, so that we catch changes on files
823
     *   during whilst this program runs.
824
     * - Maybe linger for a while to reduce number of cache re-creates.
825
     */
826
    Eina_Iterator *it;
827
    Efreet_Cache_Version *icon_version;
828
    Efreet_Cache_Version *theme_version;
829
    Efreet_Cache_Icon_Theme *theme;
830
    Eet_Data_Descriptor *theme_edd;
831
    Eet_Data_Descriptor *icon_edd;
832
    Eet_Data_Descriptor *fallback_edd;
833
    Eet_File *icon_ef;
834
    Eet_File *theme_ef;
835
    Eina_List *xdg_dirs = NULL;
836
    Eina_List *l = NULL;
837
    char file[PATH_MAX];
838
    const char *path;
839
    char *dir = NULL;
840
    Eina_Bool changed = EINA_FALSE;
841
    Eina_Bool flush = EINA_FALSE;
842
    int lockfd = -1;
843
    char **keys;
844
    int num, i;
845

846
    /* init external subsystems */
847
    if (!eina_init()) return -1;
848
    _efreet_icon_cache_log_dom =
849
        eina_log_domain_register("efreet_icon_cache", EFREET_DEFAULT_LOG_COLOR);
850
    if (_efreet_icon_cache_log_dom < 0)
851
    {
852
        EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_icon_cache.");
853
        return -1;
854
    }
855

856
    eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_ERR);
857

858
    exts = eina_array_new(10);
859
    extra_dirs = eina_array_new(10);
860

861
    for (i = 1; i < argc; i++)
862
    {
863
        if (!strcmp(argv[i], "-v"))
864
            eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_DBG);
865
        else if ((!strcmp(argv[i], "-h")) ||
866
                 (!strcmp(argv[i], "-help")) ||
867
                 (!strcmp(argv[i], "--h")) ||
868
                 (!strcmp(argv[i], "--help")))
869
        {
870
            printf("Options:\n");
871
            printf("  -v              Verbose mode\n");
872
            printf("  -e .ext1 .ext2  Extensions\n");
873
            printf("  -d dir1 dir2    Extra dirs\n");
874
            printf("  -f              Flush\n");
875
            exit(0);
876
        }
877
        else if (!strcmp(argv[i], "-e"))
878
        {
879
            while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-'))
880
                eina_array_push(exts, argv[++i]);
881
        }
882
        else if (!strcmp(argv[i], "-d"))
883
        {
884
            while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-'))
885
                eina_array_push(extra_dirs, argv[++i]);
886
        }
887
        else if (!strcmp(argv[i], "-f"))
888
            flush = EINA_TRUE;
889
    }
890

891
#ifdef HAVE_SYS_RESOURCE_H
892
    setpriority(PRIO_PROCESS, 0, 19);
893
#elif _WIN32
894
    SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
895
#endif
896

897
    if (!eet_init()) return -1;
898
    if (!ecore_init()) return -1;
899

900
    efreet_cache_update = 0;
901
    /* finish efreet init */
902
    if (!efreet_init()) goto on_error;
903

904
    strs = eina_array_new(32);
905

906
    /* create homedir */
907
    snprintf(file, sizeof(file), "%s/efreet", efreet_cache_home_get());
908
    if (!ecore_file_exists(file))
909
    {
910
        if (!ecore_file_mkpath(file)) return -1;
911
        efreet_setowner(file);
912
    }
913

914
    /* lock process, so that we only run one copy of this program */
915
    lockfd = cache_lock_file();
916
    if (lockfd == -1) goto on_error;
917

918
    /* Need to init edd's, so they are like we want, not like userspace wants */
919
    icon_edd = efreet_icon_edd();
920
    fallback_edd = efreet_icon_fallback_edd();
921
    theme_edd = efreet_icon_theme_edd(EINA_TRUE);
922

923
    icon_themes = eina_hash_string_superfast_new(EINA_FREE_CB(icon_theme_free));
924

925
    INF("opening theme cache");
926
    /* open theme file */
927
    theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE);
928
    if (!theme_ef) goto on_error_efreet;
929
    theme_version = eet_data_read(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION);
930
    if (theme_version &&
931
        ((theme_version->major != EFREET_ICON_CACHE_MAJOR) ||
932
         (theme_version->minor != EFREET_ICON_CACHE_MINOR)))
933
    {
934
        // delete old cache
935
        eet_close(theme_ef);
936
        if (unlink(efreet_icon_theme_cache_file()) < 0)
937
        {
938
            if (errno != ENOENT) goto on_error_efreet;
939
        }
940
        theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE);
941
        if (!theme_ef) goto on_error_efreet;
942
    }
943
    if (!theme_version)
944
        theme_version = NEW(Efreet_Cache_Version, 1);
945

946
    theme_version->major = EFREET_ICON_CACHE_MAJOR;
947
    theme_version->minor = EFREET_ICON_CACHE_MINOR;
948

949
    if (flush)
950
        changed = EINA_TRUE;
951

952
    if (exts->count == 0)
953
    {
954
        ERR("Need to pass extensions to icon cache create process");
955
        goto on_error_efreet;
956
    }
957

958
    keys = eet_list(theme_ef, "*", &num);
959
    if (keys)
960
    {
961
        for (i = 0; i < num; i++)
962
        {
963
            if (!strncmp(keys[i], "__efreet", 8)) continue;
964
            theme = eet_data_read(theme_ef, theme_edd, keys[i]);
965
            if (theme)
966
            {
967
                theme->valid = 0;
968
                eina_hash_direct_add(icon_themes, theme->theme.name.internal, theme);
969
            }
970
        }
971
        free(keys);
972
    }
973

974
    INF("scan for themes");
975
    /* scan themes */
976
    cache_theme_scan(efreet_icon_deprecated_user_dir_get());
977
    cache_theme_scan(efreet_icon_user_dir_get());
978

979
    xdg_dirs = efreet_data_dirs_get();
980
    EINA_LIST_FOREACH(xdg_dirs, l, dir)
981
    {
982
        snprintf(file, sizeof(file), "%s/icons", dir);
983
        cache_theme_scan(file);
984
    }
985

986
#ifndef STRICT_SPEC
987
    EINA_LIST_FOREACH(xdg_dirs, l, dir)
988
    {
989
        snprintf(file, sizeof(file), "%s/pixmaps", dir);
990
        cache_theme_scan(file);
991
    }
992
#endif
993

994
    cache_theme_scan("/usr/local/share/pixmaps");
995
    cache_theme_scan("/usr/share/pixmaps");
996

997
    /* scan icons */
998
    it = eina_hash_iterator_data_new(icon_themes);
999
    EINA_ITERATOR_FOREACH(it, theme)
1000
    {
1001
        if (!theme->valid) continue;
1002
#ifndef STRICT_SPEC
1003
        if (!theme->theme.name.name) continue;
1004
#endif
1005
        INF("scan theme %s", theme->theme.name.name);
1006
        cache_theme_change_verify(theme);
1007
        theme->changed = check_changed(theme);
1008
        if (flush)
1009
            theme->changed = EINA_TRUE;
1010

1011
        INF("open icon file");
1012
        /* open icon file */
1013
        icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE);
1014
        if (!icon_ef) goto on_error_efreet;
1015
        icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION);
1016
        if ((theme->changed) || (!icon_version) ||
1017
            ((icon_version->major != EFREET_ICON_CACHE_MAJOR) ||
1018
             (icon_version->minor != EFREET_ICON_CACHE_MINOR)))
1019
        {
1020
            // delete old cache
1021
            eet_close(icon_ef);
1022
            if (unlink(efreet_icon_cache_file(theme->theme.name.internal)) < 0)
1023
            {
1024
                if (errno != ENOENT) goto on_error_efreet;
1025
            }
1026
            icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE);
1027
            if (!icon_ef) goto on_error_efreet;
1028
            theme->changed = EINA_TRUE;
1029
        }
1030

1031
        if (theme->changed)
1032
            changed = EINA_TRUE;
1033

1034
        if (!icon_version)
1035
            icon_version = NEW(Efreet_Cache_Version, 1);
1036

1037
        icon_version->major = EFREET_ICON_CACHE_MAJOR;
1038
        icon_version->minor = EFREET_ICON_CACHE_MINOR;
1039

1040
        if (theme->changed)
1041
        {
1042
            Eina_Hash *themes;
1043
            Eina_Hash *icons;
1044

1045
            themes = eina_hash_string_superfast_new(NULL);
1046
            icons = eina_hash_string_superfast_new(NULL);
1047

1048
            INF("scan icons\n");
1049
            if (cache_scan(&(theme->theme), themes, icons))
1050
            {
1051
                Eina_Iterator *icons_it;
1052
                Eina_Hash_Tuple *tuple;
1053

1054
                INF("generated: '%s' %i (%i)",
1055
                    theme->theme.name.internal,
1056
                    theme->changed,
1057
                    eina_hash_population(icons));
1058

1059
                icons_it = eina_hash_iterator_tuple_new(icons);
1060
                EINA_ITERATOR_FOREACH(icons_it, tuple)
1061
                    eet_data_write(icon_ef, icon_edd, tuple->key, tuple->data, EET_COMPRESSION_SUPERFAST);
1062
                eina_iterator_free(icons_it);
1063

1064
                INF("theme change: %s %lld", theme->theme.name.internal, theme->check.mtime);
1065
                eet_data_write(theme_ef, theme_edd, theme->theme.name.internal, theme, EET_COMPRESSION_SUPERFAST);
1066
            }
1067
            eina_hash_free(themes);
1068
            eina_hash_free(icons);
1069
            changed = EINA_TRUE;
1070
        }
1071

1072
        eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, EET_COMPRESSION_SUPERFAST);
1073
        eet_close(icon_ef);
1074
        efreet_setowner(efreet_icon_cache_file(theme->theme.name.internal));
1075
        free(icon_version);
1076
    }
1077
    eina_iterator_free(it);
1078

1079
    INF("scan fallback icons");
1080
    theme = eet_data_read(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK);
1081
    if (!theme)
1082
    {
1083
        theme = NEW(Efreet_Cache_Icon_Theme, 1);
1084
        theme->changed = EINA_TRUE;
1085
    }
1086
    if (flush)
1087
        theme->changed = EINA_TRUE;
1088

1089
    INF("open fallback file");
1090
    /* open icon file */
1091
    icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE);
1092
    if (!icon_ef) goto on_error_efreet;
1093
    icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION);
1094
    if (theme->changed || (icon_version &&
1095
        ((icon_version->major != EFREET_ICON_CACHE_MAJOR) ||
1096
         (icon_version->minor != EFREET_ICON_CACHE_MINOR))))
1097
    {
1098
        // delete old cache
1099
        eet_close(icon_ef);
1100
        if (unlink(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK)) < 0)
1101
        {
1102
            if (errno != ENOENT) goto on_error_efreet;
1103
        }
1104
        icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE);
1105
        if (!icon_ef) goto on_error_efreet;
1106
        theme->changed = EINA_TRUE;
1107
    }
1108
    if (!theme->changed)
1109
        theme->changed = check_fallback_changed(theme);
1110
    if (theme->changed && theme->dirs)
1111
    {
1112
        efreet_hash_free(theme->dirs, free);
1113
        theme->dirs = NULL;
1114
    }
1115
    if (!theme->dirs)
1116
        theme->dirs = eina_hash_string_superfast_new(NULL);
1117

1118
    if (theme->changed)
1119
        changed = EINA_TRUE;
1120

1121
    if (!icon_version)
1122
        icon_version = NEW(Efreet_Cache_Version, 1);
1123

1124
    icon_version->major = EFREET_ICON_CACHE_MAJOR;
1125
    icon_version->minor = EFREET_ICON_CACHE_MINOR;
1126

1127
    if (theme->changed)
1128
    {
1129
        Eina_Hash *icons;
1130

1131
        icons = eina_hash_string_superfast_new(NULL);
1132

1133
        INF("scan fallback icons");
1134
        /* Save fallback in the right part */
1135
        if (cache_fallback_scan(icons, theme->dirs))
1136
        {
1137
            Eina_Iterator *icons_it;
1138
            Eina_Hash_Tuple *tuple;
1139

1140
            INF("generated: fallback %i (%i)", theme->changed, eina_hash_population(icons));
1141

1142
            icons_it = eina_hash_iterator_tuple_new(icons);
1143
            EINA_ITERATOR_FOREACH(icons_it, tuple)
1144
                eet_data_write(icon_ef, fallback_edd, tuple->key, tuple->data, EET_COMPRESSION_SUPERFAST);
1145
            eina_iterator_free(icons_it);
1146
        }
1147
        eina_hash_free(icons);
1148

1149
        eet_data_write(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK, theme, EET_COMPRESSION_SUPERFAST);
1150
    }
1151

1152
    icon_theme_free(theme);
1153

1154
    eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, EET_COMPRESSION_SUPERFAST);
1155
    eet_close(icon_ef);
1156
    efreet_setowner(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK));
1157
    free(icon_version);
1158

1159
    eina_hash_free(icon_themes);
1160

1161
    /* save data */
1162
    eet_data_write(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION, theme_version, EET_COMPRESSION_SUPERFAST);
1163

1164
    eet_close(theme_ef);
1165
    theme_ef = NULL;
1166
    efreet_setowner(efreet_icon_theme_cache_file());
1167
    free(theme_version);
1168

1169
    {
1170
        char c = 'n';
1171

1172
        if (changed) c = 'c';
1173
        printf("%c\n", c);
1174
    }
1175

1176
    INF("done");
1177
on_error_efreet:
1178
    efreet_shutdown();
1179
    if (theme_ef) eet_close(theme_ef);
1180

1181
on_error:
1182
    if (lockfd >= 0) close(lockfd);
1183

1184
    while ((path = eina_array_pop(strs)))
1185
        eina_stringshare_del(path);
1186
    eina_array_free(strs);
1187
    eina_array_free(exts);
1188
    eina_array_free(extra_dirs);
1189

1190
    ecore_shutdown();
1191
    eet_shutdown();
1192
    eina_log_domain_unregister(_efreet_icon_cache_log_dom);
1193
    eina_shutdown();
1194

1195
    return 0;
1196
}
1197

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.