04223d9d0b69f3c5aaf460b14c9bfb635d9528a5
[framework/uifw/evas.git] / src / lib / file / evas_module.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <string.h>
6
7 #include <evas_common.h>
8 #include <evas_private.h>
9 #include <evas_module.h>
10
11
12 static Eina_Hash *evas_modules[4] = {
13   NULL,
14   NULL,
15   NULL,
16   NULL
17 };
18
19 static Eina_List *eina_evas_modules = NULL;
20 static Eina_List *evas_module_paths = NULL;
21 static Eina_Array *evas_engines = NULL;
22
23 static Eina_List *
24 _evas_module_append(Eina_List *list, char *path)
25 {
26    if (path)
27      {
28         if (evas_file_path_exists(path))
29           list = eina_list_append(list, path);
30         else
31           free(path);
32      }
33    return list;
34 }
35
36 /* this will alloc a list of paths to search for the modules */
37 /* by now these are:  */
38 /* 1. ~/.evas/modules/ */
39 /* 2. $(EVAS_MODULE_DIR)/evas/modules/ */
40 /* 3. dladdr/evas/modules/ */
41 /* 4. PREFIX/evas/modules/ */
42 void
43 evas_module_paths_init(void)
44 {
45    char *path;
46
47    /* 1. ~/.evas/modules/ */
48    path = eina_module_environment_path_get("HOME", "/.evas/modules");
49    evas_module_paths = _evas_module_append(evas_module_paths, path);
50
51    /* 2. $(EVAS_MODULE_DIR)/evas/modules/ */
52    path = eina_module_environment_path_get("EVAS_MODULES_DIR", "/evas/modules");
53    if (eina_list_search_unsorted(evas_module_paths, (Eina_Compare_Cb) strcmp, path))
54      free(path);
55    else
56      evas_module_paths = _evas_module_append(evas_module_paths, path);
57
58    /* 3. libevas.so/../evas/modules/ */
59    path = eina_module_symbol_path_get(evas_module_paths_init, "/evas/modules");
60    if (eina_list_search_unsorted(evas_module_paths, (Eina_Compare_Cb) strcmp, path))
61      free(path);
62    else
63      evas_module_paths = _evas_module_append(evas_module_paths, path);
64
65    /* 4. PREFIX/evas/modules/ */
66 #ifndef _MSC_VER
67    path = PACKAGE_LIB_DIR "/evas/modules";
68    if (!eina_list_search_unsorted(evas_module_paths, (Eina_Compare_Cb) strcmp, path))
69      {
70         path = strdup(path);
71         if (path)
72           evas_module_paths = _evas_module_append(evas_module_paths, path);
73      }
74 #endif
75 }
76
77 #define EVAS_EINA_STATIC_MODULE_DEFINE(Tn, Name)        \
78   Eina_Bool evas_##Tn##_##Name##_init(void);            \
79   void evas_##Tn##_##Name##_shutdown(void);
80
81 #define EVAS_EINA_STATIC_MODULE_USE(Tn, Name)   \
82   { evas_##Tn##_##Name##_init, evas_##Tn##_##Name##_shutdown }
83
84 EVAS_EINA_STATIC_MODULE_DEFINE(engine, buffer);
85 EVAS_EINA_STATIC_MODULE_DEFINE(engine, direct3d);
86 EVAS_EINA_STATIC_MODULE_DEFINE(engine, directfb);
87 EVAS_EINA_STATIC_MODULE_DEFINE(engine, fb);
88 EVAS_EINA_STATIC_MODULE_DEFINE(engine, gl_x11);
89 EVAS_EINA_STATIC_MODULE_DEFINE(engine, gl_sdl);
90 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16);
91 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16_ddraw);
92 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16_sdl);
93 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16_wince);
94 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_16_x11);
95 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_8);
96 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_8_x11);
97 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_ddraw);
98 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_gdi);
99 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_generic);
100 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_sdl);
101 EVAS_EINA_STATIC_MODULE_DEFINE(engine, software_x11);
102 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, bmp);
103 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, edb);
104 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, eet);
105 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, generic);
106 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, gif);
107 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, ico);
108 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jpeg);
109 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, pmaps);
110 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, png);
111 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, psd);
112 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, svg);
113 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, tga);
114 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, tiff);
115 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, wbmp);
116 EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, xpm);
117 EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, edb);
118 EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, eet);
119 EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, jpeg);
120 EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, png);
121 EVAS_EINA_STATIC_MODULE_DEFINE(image_saver, tiff);
122
123 static const struct {
124    Eina_Bool (*init)(void);
125    void (*shutdown)(void);
126 } evas_static_module[] = {
127 #ifdef EVAS_STATIC_BUILD_BUFFER
128   EVAS_EINA_STATIC_MODULE_USE(engine, buffer),
129 #endif
130 #ifdef EVAS_STATIC_BUILD_DIRECT3D
131   EVAS_EINA_STATIC_MODULE_USE(engine, direct3d),
132 #endif
133 #ifdef EVAS_STATIC_BUILD_DIRECTFB
134   EVAS_EINA_STATIC_MODULE_USE(engine, directfb),
135 #endif
136 #ifdef EVAS_STATIC_BUILD_FB
137   EVAS_EINA_STATIC_MODULE_USE(engine, fb),
138 #endif
139 #ifdef EVAS_STATIC_BUILD_GL_X11
140   EVAS_EINA_STATIC_MODULE_USE(engine, gl_x11),
141 #endif
142 #ifdef EVAS_STATIC_BUILD_GL_SDL
143   EVAS_EINA_STATIC_MODULE_USE(engine, gl_sdl),
144 #endif
145 #ifdef EVAS_STATIC_BUILD_SOFTWARE_16
146   EVAS_EINA_STATIC_MODULE_USE(engine, software_16),
147 #endif
148 #ifdef EVAS_STATIC_BUILD_SOFTWARE_16_DDRAW
149   EVAS_EINA_STATIC_MODULE_USE(engine, software_16_ddraw),
150 #endif
151 #ifdef EVAS_STATIC_BUILD_SOFTWARE_16_SDL
152   EVAS_EINA_STATIC_MODULE_USE(engine, software_16_sdl),
153 #endif
154 #ifdef EVAS_STATIC_BUILD_SOFTWARE_16_WINCE
155   EVAS_EINA_STATIC_MODULE_USE(engine, software_16_wince),
156 #endif
157 #ifdef EVAS_STATIC_BUILD_SOFTWARE_16_X11
158   EVAS_EINA_STATIC_MODULE_USE(engine, software_16_x11),
159 #endif
160 #ifdef EVAS_STATIC_BUILD_SOFTWARE_16_DDRAW
161   EVAS_EINA_STATIC_MODULE_USE(engine, software_ddraw),
162 #endif
163 #ifdef EVAS_STATIC_BUILD_SOFTWARE_16_GDI
164   EVAS_EINA_STATIC_MODULE_USE(engine, software_gdi),
165 #endif
166 #ifdef EVAS_STATIC_BUILD_SOFTWARE_8
167   EVAS_EINA_STATIC_MODULE_USE(engine, software_8),
168 #endif
169 #ifdef EVAS_STATIC_BUILD_SOFTWARE_8_X11
170   EVAS_EINA_STATIC_MODULE_USE(engine, software_8_x11),
171 #endif
172 #ifdef EVAS_STATIC_BUILD_SOFTWARE_GENERIC
173   EVAS_EINA_STATIC_MODULE_USE(engine, software_generic),
174 #endif
175 #ifdef EVAS_STATIC_BUILD_SOFTWARE_SDL
176   EVAS_EINA_STATIC_MODULE_USE(engine, software_sdl),
177 #endif
178 #ifdef EVAS_STATIC_BUILD_SOFTWARE_X11
179   EVAS_EINA_STATIC_MODULE_USE(engine, software_x11),
180 #endif
181 #ifdef EVAS_STATIC_BUILD_BMP
182   EVAS_EINA_STATIC_MODULE_USE(image_loader, bmp),
183 #endif
184 #ifdef EVAS_STATIC_BUILD_EDB
185   EVAS_EINA_STATIC_MODULE_USE(image_loader, edb),
186 #endif
187 #ifdef EVAS_STATIC_BUILD_EET
188   EVAS_EINA_STATIC_MODULE_USE(image_loader, eet),
189 #endif
190 #ifdef EVAS_STATIC_BUILD_GENERIC
191   EVAS_EINA_STATIC_MODULE_USE(image_loader, generic),
192 #endif
193 #ifdef EVAS_STATIC_BUILD_GIF
194   EVAS_EINA_STATIC_MODULE_USE(image_loader, gif),
195 #endif
196 #ifdef EVAS_STATIC_BUILD_ICO
197   EVAS_EINA_STATIC_MODULE_USE(image_loader, ico),
198 #endif
199 #ifdef EVAS_STATIC_BUILD_JPEG
200   EVAS_EINA_STATIC_MODULE_USE(image_loader, jpeg),
201 #endif
202 #ifdef EVAS_STATIC_BUILD_PMAPS
203   EVAS_EINA_STATIC_MODULE_USE(image_loader, pmaps),
204 #endif
205 #ifdef EVAS_STATIC_BUILD_PNG
206   EVAS_EINA_STATIC_MODULE_USE(image_loader, png),
207 #endif
208 #ifdef EVAS_STATIC_BUILD_PSD
209   EVAS_EINA_STATIC_MODULE_USE(image_loader, psd),
210 #endif
211 #ifdef EVAS_STATIC_BUILD_SVG
212   EVAS_EINA_STATIC_MODULE_USE(image_loader, svg),
213 #endif
214 #ifdef EVAS_STATIC_BUILD_TGA
215   EVAS_EINA_STATIC_MODULE_USE(image_loader, tga),
216 #endif
217 #ifdef EVAS_STATIC_BUILD_TIFF
218   EVAS_EINA_STATIC_MODULE_USE(image_loader, tiff),
219 #endif
220 #ifdef EVAS_STATIC_BUILD_WBMP
221   EVAS_EINA_STATIC_MODULE_USE(image_loader, wbmp),
222 #endif
223 #ifdef EVAS_STATIC_BUILD_XPM
224   EVAS_EINA_STATIC_MODULE_USE(image_loader, xpm),
225 #endif
226 #ifdef EVAS_STATIC_BUILD_EDB
227   EVAS_EINA_STATIC_MODULE_USE(image_saver, edb),
228 #endif
229 #ifdef EVAS_STATIC_BUILD_EET
230   EVAS_EINA_STATIC_MODULE_USE(image_saver, eet),
231 #endif
232 #if defined (EVAS_BUILD_SAVER_JPEG) && defined (EVAS_STATIC_BUILD_JPEG)
233   EVAS_EINA_STATIC_MODULE_USE(image_saver, jpeg),
234 #endif
235 #ifdef EVAS_STATIC_BUILD_PNG
236   EVAS_EINA_STATIC_MODULE_USE(image_saver, png),
237 #endif
238 #ifdef EVAS_STATIC_BUILD_TIFF
239   EVAS_EINA_STATIC_MODULE_USE(image_saver, tiff),
240 #endif
241   { NULL, NULL }
242 };
243
244 /* this will alloc an Evas_Module struct for each module
245  * it finds on the paths */
246 void
247 evas_module_init(void)
248 {
249    int i;
250
251    evas_module_paths_init();
252
253    evas_modules[EVAS_MODULE_TYPE_ENGINE] = eina_hash_string_small_new(/* FIXME: Add a function to cleanup stuff. */ NULL);
254    evas_modules[EVAS_MODULE_TYPE_IMAGE_LOADER] = eina_hash_string_small_new(/* FIXME: Add a function to cleanup stuff. */ NULL);
255    evas_modules[EVAS_MODULE_TYPE_IMAGE_SAVER] = eina_hash_string_small_new(/* FIXME: Add a function to cleanup stuff. */ NULL);
256    evas_modules[EVAS_MODULE_TYPE_OBJECT] = eina_hash_string_small_new(/* FIXME: Add a function to cleanup stuff. */ NULL);
257
258    evas_engines = eina_array_new(4);
259
260    for (i = 0; evas_static_module[i].init; ++i)
261      evas_static_module[i].init();
262 }
263
264 Eina_Bool
265 evas_module_register(const Evas_Module_Api *module, Evas_Module_Type type)
266 {
267    Evas_Module *em;
268
269    if ((unsigned int)type > 3) return EINA_FALSE;
270    if (!module) return EINA_FALSE;
271    if (module->version != EVAS_MODULE_API_VERSION) return EINA_FALSE;
272
273    em = eina_hash_find(evas_modules[type], module->name);
274    if (em) return EINA_FALSE;
275
276    em = calloc(1, sizeof (Evas_Module));
277    if (!em) return EINA_FALSE;
278
279    em->definition = module;
280
281    if (type == EVAS_MODULE_TYPE_ENGINE)
282      {
283         eina_array_push(evas_engines, em);
284         em->id_engine = eina_array_count_get(evas_engines);
285      }
286
287    eina_hash_direct_add(evas_modules[type], module->name, em);
288
289    return EINA_TRUE;
290 }
291
292 Eina_Bool
293 evas_module_unregister(const Evas_Module_Api *module, Evas_Module_Type type)
294 {
295    Evas_Module *em;
296
297    if ((unsigned int)type > 3) return EINA_FALSE;
298    if (!module) return EINA_FALSE;
299
300    em = eina_hash_find(evas_modules[type], module->name);
301    if (!em || em->definition != module) return EINA_FALSE;
302
303    if (type == EVAS_MODULE_TYPE_ENGINE)
304      eina_array_data_set(evas_engines, em->id_engine, NULL);
305
306    eina_hash_del(evas_modules[type], module->name, em);
307    free(em);
308
309    return EINA_TRUE;
310 }
311
312 #if defined(__CEGCC__) || defined(__MINGW32CE__)
313 # define EVAS_MODULE_NAME_IMAGE_SAVER "saver_%s.dll"
314 # define EVAS_MODULE_NAME_IMAGE_LOADER "loader_%s.dll"
315 # define EVAS_MODULE_NAME_ENGINE "engine_%s.dll"
316 # define EVAS_MODULE_NAME_OBJECT "object_%s.dll"
317 #elif _WIN32
318 # define EVAS_MODULE_NAME_IMAGE_SAVER "module.dll"
319 # define EVAS_MODULE_NAME_IMAGE_LOADER "module.dll"
320 # define EVAS_MODULE_NAME_ENGINE "module.dll"
321 # define EVAS_MODULE_NAME_OBJECT "module.dll"
322 #else
323 # define EVAS_MODULE_NAME_IMAGE_SAVER "module.so"
324 # define EVAS_MODULE_NAME_IMAGE_LOADER "module.so"
325 # define EVAS_MODULE_NAME_ENGINE "module.so"
326 # define EVAS_MODULE_NAME_OBJECT "module.so"
327 #endif
328
329 Evas_Module *
330 evas_module_find_type(Evas_Module_Type type, const char *name)
331 {
332    const char *path;
333    const char *format = NULL;
334    char buffer[4096];
335    Evas_Module *em;
336    Eina_Module *en;
337    Eina_List *l;
338
339    if ((unsigned int)type > 3) return NULL;
340
341    em = eina_hash_find(evas_modules[type], name);
342    if (em) return em;
343
344    EINA_LIST_FOREACH(evas_module_paths, l, path)
345      {
346         switch (type)
347           {
348            case EVAS_MODULE_TYPE_ENGINE: format = "%s/engines/%s/%s/" EVAS_MODULE_NAME_ENGINE; break;
349            case EVAS_MODULE_TYPE_IMAGE_LOADER: format = "%s/loaders/%s/%s/" EVAS_MODULE_NAME_IMAGE_LOADER; break;
350            case EVAS_MODULE_TYPE_IMAGE_SAVER: format = "%s/savers/%s/%s/" EVAS_MODULE_NAME_IMAGE_SAVER; break;
351            case EVAS_MODULE_TYPE_OBJECT: format = "%s/object/%s/%s/" EVAS_MODULE_NAME_OBJECT; break;
352           }
353
354         snprintf(buffer, sizeof (buffer), format, path, name, MODULE_ARCH, name);
355         if (!evas_file_path_is_file(buffer)) continue;
356
357         en = eina_module_new(buffer);
358         if (!en) continue;
359
360         if (!eina_module_load(en))
361           {
362              eina_module_free(en);
363              continue;
364           }
365
366         em = eina_hash_find(evas_modules[type], name);
367         if (em)
368           {
369              eina_evas_modules = eina_list_append(eina_evas_modules, en);
370              return em;
371           }
372
373         eina_module_free(en);
374      }
375
376    return NULL;
377 }
378
379 Evas_Module *
380 evas_module_engine_get(int render_method)
381 {
382    if ((render_method <= 0) ||
383        ((unsigned int)render_method > eina_array_count_get(evas_engines)))
384      return NULL;
385    return eina_array_data_get(evas_engines, render_method - 1);
386 }
387
388 void
389 evas_module_foreach_image_loader(Eina_Hash_Foreach cb, const void *fdata)
390 {
391    eina_hash_foreach(evas_modules[EVAS_MODULE_TYPE_IMAGE_LOADER], cb, fdata);
392 }
393
394 int
395 evas_module_load(Evas_Module *em)
396 {
397    if (em->loaded) return 1;
398    if (!em->definition) return 0;
399
400    if (!em->definition->func.open(em)) return 0;
401    em->loaded = 1;
402
403 #ifdef BUILD_ASYNC_PRELOAD
404    LKI(em->lock);
405 #endif
406    return 1;
407 }
408
409 void
410 evas_module_unload(Evas_Module *em)
411 {
412    if (!em->loaded)
413      return;
414    if (!em->definition)
415      return ;
416
417 // for now lets not unload modules - they may still be in use.   
418 //   em->definition->func.close(em);
419 //   em->loaded = 0;
420
421 #ifdef BUILD_ASYNC_PRELOAD
422    LKD(em->lock);
423 #endif
424 }
425
426 void
427 evas_module_ref(Evas_Module *em)
428 {
429 #ifdef BUILD_ASYNC_PRELOAD
430    LKL(em->lock);
431 #endif
432    em->ref++;
433 #ifdef BUILD_ASYNC_PRELOAD
434    LKU(em->lock);
435 #endif
436 }
437
438 void
439 evas_module_unref(Evas_Module *em)
440 {
441 #ifdef BUILD_ASYNC_PRELOAD
442    LKL(em->lock);
443 #endif
444    em->ref--;
445 #ifdef BUILD_ASYNC_PRELOAD
446    LKU(em->lock);
447 #endif
448 }
449
450 static int use_count = 0;
451
452 void
453 evas_module_use(Evas_Module *em)
454 {
455    em->last_used = use_count;
456 }
457
458 void
459 evas_module_clean(void)
460 {
461    static int call_count = 0;
462 /*    int ago; */
463    int noclean = -1;
464 /*    Eina_List *l; */
465 /*    Evas_Module *em; */
466
467    /* only clean modules every 256 calls */
468    call_count++;
469    if (call_count <= 256) return;
470    call_count = 0;
471
472    if (noclean == -1)
473      {
474         if (getenv("EVAS_NOCLEAN"))
475           noclean = 1;
476         else 
477           noclean = 0;
478      }
479    if (noclean == 1) return;
480
481    /* disable module cleaning for now - may cause instability with some modules */
482    return;
483
484    /* FIXME: Don't know what it is supposed to do. */
485 /*    /\* incriment use counter = 28bits *\/ */
486 /*    use_count++; */
487 /*    if (use_count > 0x0fffffff) use_count = 0; */
488
489 /*    /\* printf("CLEAN!\n"); *\/ */
490 /*    /\* go through all modules *\/ */
491 /*    EINA_LIST_FOREACH(evas_modules, l, em) */
492 /*      { */
493 /*         /\* printf("M %s %i %i\n", em->name, em->ref, em->loaded); *\/ */
494 /*      /\* if the module is refernced - skip *\/ */
495 /*      if ((em->ref > 0) || (!em->loaded)) continue; */
496 /*      /\* how many clean cycles ago was this module last used *\/ */
497 /*      ago = use_count - em->last_used; */
498 /*      if (em->last_used > use_count) ago += 0x10000000; */
499 /*      /\* if it was used last more than N clean cycles ago - unload *\/ */
500 /*      if (ago > 5) */
501 /*        { */
502 /*             /\* printf("  UNLOAD %s\n", em->name); *\/ */
503 /*           evas_module_unload(em); */
504 /*        } */
505 /*      } */
506 }
507
508 /* will dlclose all the modules loaded and free all the structs */
509 void
510 evas_module_shutdown(void)
511 {
512    Eina_Module *en;
513    char *path;
514    int i;
515
516    for (i = 0; evas_static_module[i].shutdown; ++i)
517      evas_static_module[i].shutdown();
518
519    EINA_LIST_FREE(eina_evas_modules, en)
520      eina_module_free(en);
521
522    eina_hash_free(evas_modules[EVAS_MODULE_TYPE_ENGINE]);
523    evas_modules[EVAS_MODULE_TYPE_ENGINE] = NULL;
524    eina_hash_free(evas_modules[EVAS_MODULE_TYPE_IMAGE_LOADER]);
525    evas_modules[EVAS_MODULE_TYPE_IMAGE_LOADER] = NULL;
526    eina_hash_free(evas_modules[EVAS_MODULE_TYPE_IMAGE_SAVER]);
527    evas_modules[EVAS_MODULE_TYPE_IMAGE_SAVER] = NULL;
528    eina_hash_free(evas_modules[EVAS_MODULE_TYPE_OBJECT]);
529    evas_modules[EVAS_MODULE_TYPE_OBJECT] = NULL;
530
531    EINA_LIST_FREE(evas_module_paths, path)
532      free(path);
533
534    eina_array_free(evas_engines);
535    evas_engines = NULL;
536 }
537
538 EAPI int
539 _evas_module_engine_inherit(Evas_Func *funcs, char *name)
540 {
541    Evas_Module *em;
542
543    em = evas_module_find_type(EVAS_MODULE_TYPE_ENGINE, name);
544    if (em)
545      {
546         if (evas_module_load(em))
547           {
548              /* FIXME: no way to unref */
549              evas_module_ref(em);
550              evas_module_use(em);
551              *funcs = *((Evas_Func *)(em->functions));
552              return 1;
553           }
554      }
555    return 0;
556 }