1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * New system driver.
12 *
13 * By Elias Pschernig.
14 *
15 * Modified by Trent Gamblin.
16 */
17
18 /* Title: System routines
19 */
20
21 #include "allegro5/allegro.h"
22 #include "allegro5/internal/aintern.h"
23 #ifdef ALLEGRO_CFG_SHADER_GLSL
24 #include "allegro5/allegro_opengl.h"
25 #include "allegro5/internal/aintern_opengl.h"
26 #endif
27 #include ALLEGRO_INTERNAL_HEADER
28 #include "allegro5/internal/aintern_bitmap.h"
29 #include "allegro5/internal/aintern_debug.h"
30 #include "allegro5/internal/aintern_dtor.h"
31 #include "allegro5/internal/aintern_exitfunc.h"
32 #include "allegro5/internal/aintern_pixels.h"
33 #include "allegro5/internal/aintern_system.h"
34 #include "allegro5/internal/aintern_thread.h"
35 #include "allegro5/internal/aintern_timer.h"
36 #include "allegro5/internal/aintern_tls.h"
37 #include "allegro5/internal/aintern_vector.h"
38
39 ALLEGRO_DEBUG_CHANNEL("system")
40
41 static ALLEGRO_SYSTEM *active_sysdrv = NULL;
42 static ALLEGRO_CONFIG *sys_config = NULL;
43
44 _AL_VECTOR _al_system_interfaces;
45 static _AL_VECTOR _user_system_interfaces = _AL_VECTOR_INITIALIZER(ALLEGRO_SYSTEM_INTERFACE *);
46
47 _AL_DTOR_LIST *_al_dtor_list = NULL;
48
49 static bool atexit_virgin = true;
50
51 static char _al_app_name[256] = "";
52 static char _al_org_name[256] = "";
53
54
55
find_system(_AL_VECTOR * vector)56 static ALLEGRO_SYSTEM *find_system(_AL_VECTOR *vector)
57 {
58 ALLEGRO_SYSTEM_INTERFACE **sptr;
59 ALLEGRO_SYSTEM_INTERFACE *sys_interface;
60 ALLEGRO_SYSTEM *system;
61 unsigned int i;
62
63 for (i = 0; i < vector->_size; i++) {
64 sptr = _al_vector_ref(vector, i);
65 sys_interface = *sptr;
66 if ((system = sys_interface->initialize(0)) != NULL)
67 return system;
68 }
69
70 return NULL;
71 }
72
73
74
shutdown_system_driver(void)75 static void shutdown_system_driver(void)
76 {
77 if (active_sysdrv) {
78 if (active_sysdrv->user_exe_path)
79 al_destroy_path(active_sysdrv->user_exe_path);
80 if (active_sysdrv->vt && active_sysdrv->vt->shutdown_system)
81 active_sysdrv->vt->shutdown_system();
82 active_sysdrv = NULL;
83
84 while (!_al_vector_is_empty(&_al_system_interfaces))
85 _al_vector_delete_at(&_al_system_interfaces, _al_vector_size(&_al_system_interfaces)-1);
86 _al_vector_free(&_al_system_interfaces);
87 _al_vector_init(&_al_system_interfaces, sizeof(ALLEGRO_SYSTEM_INTERFACE *));
88 }
89 al_destroy_config(sys_config);
90 sys_config = NULL;
91 }
92
93
94
95 /* al_get_standard_path() does not work before the system driver is
96 * initialised. Before that, we need to call the underlying functions
97 * directly.
98 */
early_get_exename_path(void)99 static ALLEGRO_PATH *early_get_exename_path(void)
100 {
101 #if defined(ALLEGRO_WINDOWS)
102 return _al_win_get_path(ALLEGRO_EXENAME_PATH);
103 #elif defined(ALLEGRO_MACOSX)
104 return _al_osx_get_path(ALLEGRO_EXENAME_PATH);
105 #elif defined(ALLEGRO_IPHONE)
106 return _al_iphone_get_path(ALLEGRO_EXENAME_PATH);
107 #elif defined(ALLEGRO_UNIX)
108 return _al_unix_get_path(ALLEGRO_EXENAME_PATH);
109 #elif defined(ALLEGRO_ANDROID)
110 return _al_android_get_path(ALLEGRO_EXENAME_PATH);
111 #elif defined(ALLEGRO_SDL)
112 char* p = SDL_GetBasePath();
113 ALLEGRO_PATH *path = al_create_path_for_directory(p);
114 SDL_free(p);
115 return path;
116 #else
117 #error early_get_exename_path not implemented
118 #endif
119 }
120
121
122
read_allegro_cfg(void)123 static void read_allegro_cfg(void)
124 {
125 /* We assume that the stdio file interface is in effect. */
126
127 ALLEGRO_PATH *path;
128 ALLEGRO_CONFIG *temp;
129
130 if (!sys_config)
131 sys_config = al_create_config();
132
133 #if defined(ALLEGRO_UNIX) && !defined(ALLEGRO_IPHONE)
134 temp = al_load_config_file("/etc/allegro5rc");
135 if (temp) {
136 al_merge_config_into(sys_config, temp);
137 al_destroy_config(temp);
138 }
139
140 path = _al_unix_get_path(ALLEGRO_USER_HOME_PATH);
141 if (path) {
142 al_set_path_filename(path, "allegro5rc");
143 temp = al_load_config_file(al_path_cstr(path, '/'));
144 if (temp) {
145 al_merge_config_into(sys_config, temp);
146 al_destroy_config(temp);
147 }
148 al_set_path_filename(path, ".allegro5rc");
149 temp = al_load_config_file(al_path_cstr(path, '/'));
150 if (temp) {
151 al_merge_config_into(sys_config, temp);
152 al_destroy_config(temp);
153 }
154 al_destroy_path(path);
155 }
156 #endif
157
158 path = early_get_exename_path();
159 if (path) {
160 al_set_path_filename(path, "allegro5.cfg");
161 temp = al_load_config_file(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP));
162 if (temp) {
163 al_merge_config_into(sys_config, temp);
164 al_destroy_config(temp);
165 }
166 al_destroy_path(path);
167 }
168 /* Reconfigure logging in case something changed. */
169 _al_configure_logging();
170 }
171
172
173
174 /*
175 * Can a binary with version a use a library with version b?
176 *
177 * Let a = xa.ya.za.*
178 * Let b = xb.yb.zb.*
179 *
180 * When a has the unstable bit, a is compatible with b if xa.ya.za = xb.yb.zb.
181 * Otherwise, a is compatible with b if xa.ya = xb.yb and zb >= za.
182 *
183 * Otherwise a and b are incompatible.
184 */
compatible_versions(int a,int b)185 static bool compatible_versions(int a, int b)
186 {
187 int a_unstable = a & _ALLEGRO_UNSTABLE_BIT_SET;
188
189 int a_major = (a & 0x7f000000) >> 24;
190 int a_sub = (a & 0x00ff0000) >> 16;
191 int a_wip = (a & 0x0000ff00) >> 8;
192
193 int b_major = (b & 0x7f000000) >> 24;
194 int b_sub = (b & 0x00ff0000) >> 16;
195 int b_wip = (b & 0x0000ff00) >> 8;
196
197 if (a_major != b_major) {
198 return false;
199 }
200 if (a_unstable && a_wip != b_wip) {
201 return false;
202 }
203 if (a_sub != b_sub) {
204 return false;
205 }
206 if (a_wip > b_wip) {
207 return false;
208 }
209 return true;
210 }
211
212
213
214 /* Function: al_install_system
215 */
al_install_system(int version,int (* atexit_ptr)(void (*)(void)))216 bool al_install_system(int version, int (*atexit_ptr)(void (*)(void)))
217 {
218 ALLEGRO_SYSTEM bootstrap;
219 ALLEGRO_SYSTEM *real_system;
220 int library_version = al_get_allegro_version();
221
222 if (active_sysdrv) {
223 return true;
224 }
225
226 /* Note: We cannot call logging functions yet.
227 * TODO: Maybe we want to do the check after the "bootstrap" system
228 * is available at least?
229 */
230 if (!compatible_versions(version, library_version))
231 return false;
232
233 _al_tls_init_once();
234 _al_reinitialize_tls_values();
235
236 _al_vector_init(&_al_system_interfaces, sizeof(ALLEGRO_SYSTEM_INTERFACE *));
237
238 /* Set up a bootstrap system so the calls expecting it don't freak out */
239 memset(&bootstrap, 0, sizeof(bootstrap));
240 active_sysdrv = &bootstrap;
241 read_allegro_cfg();
242
243 #ifdef ALLEGRO_BCC32
244 /* This supresses exceptions on floating point divide by zero */
245 _control87(MCW_EM, MCW_EM);
246 #endif
247
248 /* Register builtin system drivers */
249 _al_register_system_interfaces();
250
251 /* Check for a user-defined system driver first */
252 real_system = find_system(&_user_system_interfaces);
253
254 /* If a user-defined driver is not found, look for a builtin one */
255 if (real_system == NULL) {
256 real_system = find_system(&_al_system_interfaces);
257 }
258
259 if (real_system == NULL) {
260 active_sysdrv = NULL;
261 return false;
262 }
263
264 active_sysdrv = real_system;
265 active_sysdrv->mouse_wheel_precision = 1;
266
267 const char *min_bitmap_size = al_get_config_value(
268 al_get_system_config(), "graphics", "min_bitmap_size");
269 active_sysdrv->min_bitmap_size = min_bitmap_size ? atoi(min_bitmap_size) : 16;
270
271 ALLEGRO_INFO("Allegro version: %s\n", ALLEGRO_VERSION_STR);
272
273 if (strcmp(al_get_app_name(), "") == 0) {
274 al_set_app_name(NULL);
275 }
276
277 _al_add_exit_func(shutdown_system_driver, "shutdown_system_driver");
278
279 _al_dtor_list = _al_init_destructors();
280
281 _al_init_events();
282
283 _al_init_iio_table();
284
285 _al_init_convert_bitmap_list();
286
287 _al_init_timers();
288
289 #ifdef ALLEGRO_CFG_SHADER_GLSL
290 _al_glsl_init_shaders();
291 #endif
292
293 if (active_sysdrv->vt->heartbeat_init)
294 active_sysdrv->vt->heartbeat_init();
295
296 if (atexit_ptr && atexit_virgin) {
297 #ifndef ALLEGRO_ANDROID
298 atexit_ptr(al_uninstall_system);
299 #endif
300 atexit_virgin = false;
301 }
302
303 /* Clear errnos set while searching for config files. */
304 al_set_errno(0);
305
306 active_sysdrv->installed = true;
307
308 _al_srand(time(NULL));
309
310 return true;
311 }
312
313 /* Function: al_uninstall_system
314 */
al_uninstall_system(void)315 void al_uninstall_system(void)
316 {
317 /* Note: al_uninstall_system may get called multiple times without an
318 * al_install_system in between. For example if the user manually
319 * calls it at the end of the program it is called right again
320 * because it's installed as an atexit function by al_init.
321 */
322
323 _al_run_destructors(_al_dtor_list);
324 _al_run_exit_funcs();
325 _al_shutdown_destructors(_al_dtor_list);
326 _al_dtor_list = NULL;
327
328 #ifdef ALLEGRO_CFG_SHADER_GLSL
329 _al_glsl_shutdown_shaders();
330 #endif
331
332 _al_shutdown_logging();
333
334 /* shutdown_system_driver is registered as an exit func so we don't need
335 * to do any more here.
336 */
337
338 ASSERT(active_sysdrv == NULL);
339 }
340
341
342
343 /* Function: al_is_system_installed
344 */
al_is_system_installed(void)345 bool al_is_system_installed(void)
346 {
347 return (active_sysdrv && active_sysdrv->installed) ? true : false;
348 }
349
350
351 /* Hidden function: al_get_system_driver
352 * This was exported and documented in 5.0rc1 but probably shouldn't have been
353 * as ALLEGRO_SYSTEM is not documented.
354 */
al_get_system_driver(void)355 ALLEGRO_SYSTEM *al_get_system_driver(void)
356 {
357 return active_sysdrv;
358 }
359
360 /* Function: al_get_system_id
361 */
al_get_system_id(void)362 ALLEGRO_SYSTEM_ID al_get_system_id(void)
363 {
364 ASSERT(active_sysdrv);
365 return active_sysdrv->vt->id;
366 }
367
368 /* Function: al_get_system_config
369 */
al_get_system_config(void)370 ALLEGRO_CONFIG *al_get_system_config(void)
371 {
372 if (!sys_config)
373 sys_config = al_create_config();
374 return sys_config;
375 }
376
377
378 /* Function: al_get_standard_path
379 */
al_get_standard_path(int id)380 ALLEGRO_PATH *al_get_standard_path(int id)
381 {
382 ASSERT(active_sysdrv);
383 ASSERT(active_sysdrv->vt);
384 ASSERT(active_sysdrv->vt->get_path);
385
386 if (id == ALLEGRO_EXENAME_PATH && active_sysdrv->user_exe_path)
387 return al_clone_path(active_sysdrv->user_exe_path);
388
389 if (id == ALLEGRO_RESOURCES_PATH && active_sysdrv->user_exe_path) {
390 ALLEGRO_PATH *exe_dir = al_clone_path(active_sysdrv->user_exe_path);
391 al_set_path_filename(exe_dir, NULL);
392 return exe_dir;
393 }
394
395 if (active_sysdrv->vt->get_path)
396 return active_sysdrv->vt->get_path(id);
397
398 return NULL;
399 }
400
401
402 /* Function: al_set_exe_name
403 */
al_set_exe_name(char const * path)404 void al_set_exe_name(char const *path)
405 {
406 ASSERT(active_sysdrv);
407 if (active_sysdrv->user_exe_path) {
408 al_destroy_path(active_sysdrv->user_exe_path);
409 }
410 active_sysdrv->user_exe_path = al_create_path(path);
411 }
412
413
414 /* Function: al_set_org_name
415 */
al_set_org_name(const char * org_name)416 void al_set_org_name(const char *org_name)
417 {
418 if (!org_name)
419 org_name = "";
420
421 _al_sane_strncpy(_al_org_name, org_name, sizeof(_al_org_name));
422 }
423
424
425 /* Function: al_set_app_name
426 */
al_set_app_name(const char * app_name)427 void al_set_app_name(const char *app_name)
428 {
429 if (app_name) {
430 _al_sane_strncpy(_al_app_name, app_name, sizeof(_al_app_name));
431 }
432 else {
433 ALLEGRO_PATH *path;
434 path = al_get_standard_path(ALLEGRO_EXENAME_PATH);
435 _al_sane_strncpy(_al_app_name, al_get_path_filename(path), sizeof(_al_app_name));
436 al_destroy_path(path);
437 }
438 }
439
440
441 /* Function: al_get_org_name
442 */
al_get_org_name(void)443 const char *al_get_org_name(void)
444 {
445 return _al_org_name;
446 }
447
448
449 /* Function: al_get_app_name
450 */
al_get_app_name(void)451 const char *al_get_app_name(void)
452 {
453 return _al_app_name;
454 }
455
456
457 /* Function: al_inhibit_screensaver
458 */
al_inhibit_screensaver(bool inhibit)459 bool al_inhibit_screensaver(bool inhibit)
460 {
461 ASSERT(active_sysdrv);
462
463 if (active_sysdrv->vt->inhibit_screensaver)
464 return active_sysdrv->vt->inhibit_screensaver(inhibit);
465 else
466 return false;
467 }
468
469
_al_open_library(const char * filename)470 void *_al_open_library(const char *filename)
471 {
472 ASSERT(active_sysdrv);
473
474 if (active_sysdrv->vt->open_library)
475 return active_sysdrv->vt->open_library(filename);
476 else
477 return NULL;
478 }
479
480
_al_import_symbol(void * library,const char * symbol)481 void *_al_import_symbol(void *library, const char *symbol)
482 {
483 ASSERT(active_sysdrv);
484
485 if (active_sysdrv->vt->import_symbol)
486 return active_sysdrv->vt->import_symbol(library, symbol);
487 else
488 return NULL;
489 }
490
491
_al_close_library(void * library)492 void _al_close_library(void *library)
493 {
494 ASSERT(active_sysdrv);
495
496 if (active_sysdrv->vt->close_library)
497 active_sysdrv->vt->close_library(library);
498 }
499
500
501 /* Function: al_get_time
502 */
al_get_time(void)503 double al_get_time(void)
504 {
505 ASSERT(active_sysdrv);
506
507 if (active_sysdrv->vt->get_time)
508 return active_sysdrv->vt->get_time();
509 return 0.0;
510 }
511
512
513 /* Function: al_rest
514 */
al_rest(double seconds)515 void al_rest(double seconds)
516 {
517 ASSERT(active_sysdrv);
518
519 if (active_sysdrv->vt->rest)
520 active_sysdrv->vt->rest(seconds);
521 }
522
523
524 /* Function: al_init_timeout
525 */
al_init_timeout(ALLEGRO_TIMEOUT * timeout,double seconds)526 void al_init_timeout(ALLEGRO_TIMEOUT *timeout, double seconds)
527 {
528 ASSERT(active_sysdrv);
529
530 if (active_sysdrv->vt->init_timeout)
531 active_sysdrv->vt->init_timeout(timeout, seconds);
532 }
533
534 /* vim: set sts=3 sw=3 et: */
535