Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
499 lines (391 sloc) 11.8 KB
/* ______ ___ ___
* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
* \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
* \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
* \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
* \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
* /\____/
* \_/__/
*
* New system driver.
*
* By Elias Pschernig.
*
* Modified by Trent Gamblin.
*/
/* Title: System routines
*/
#include "allegro5/allegro.h"
#include "allegro5/internal/aintern.h"
#ifdef ALLEGRO_CFG_SHADER_GLSL
#include "allegro5/allegro_opengl.h"
#include "allegro5/internal/aintern_opengl.h"
#endif
#include ALLEGRO_INTERNAL_HEADER
#include "allegro5/internal/aintern_bitmap.h"
#include "allegro5/internal/aintern_debug.h"
#include "allegro5/internal/aintern_dtor.h"
#include "allegro5/internal/aintern_exitfunc.h"
#include "allegro5/internal/aintern_pixels.h"
#include "allegro5/internal/aintern_system.h"
#include "allegro5/internal/aintern_thread.h"
#include "allegro5/internal/aintern_timer.h"
#include "allegro5/internal/aintern_tls.h"
#include "allegro5/internal/aintern_vector.h"
ALLEGRO_DEBUG_CHANNEL("system")
static ALLEGRO_SYSTEM *active_sysdrv = NULL;
static ALLEGRO_CONFIG *sys_config = NULL;
_AL_VECTOR _al_system_interfaces;
static _AL_VECTOR _user_system_interfaces = _AL_VECTOR_INITIALIZER(ALLEGRO_SYSTEM_INTERFACE *);
_AL_DTOR_LIST *_al_dtor_list = NULL;
static bool atexit_virgin = true;
static char _al_app_name[256] = "";
static char _al_org_name[256] = "";
static ALLEGRO_SYSTEM *find_system(_AL_VECTOR *vector)
{
ALLEGRO_SYSTEM_INTERFACE **sptr;
ALLEGRO_SYSTEM_INTERFACE *sys_interface;
ALLEGRO_SYSTEM *system;
unsigned int i;
for (i = 0; i < vector->_size; i++) {
sptr = _al_vector_ref(vector, i);
sys_interface = *sptr;
if ((system = sys_interface->initialize(0)) != NULL)
return system;
}
return NULL;
}
static void shutdown_system_driver(void)
{
if (active_sysdrv) {
if (active_sysdrv->user_exe_path)
al_destroy_path(active_sysdrv->user_exe_path);
if (active_sysdrv->vt && active_sysdrv->vt->shutdown_system)
active_sysdrv->vt->shutdown_system();
active_sysdrv = NULL;
while (!_al_vector_is_empty(&_al_system_interfaces))
_al_vector_delete_at(&_al_system_interfaces, _al_vector_size(&_al_system_interfaces)-1);
_al_vector_free(&_al_system_interfaces);
_al_vector_init(&_al_system_interfaces, sizeof(ALLEGRO_SYSTEM_INTERFACE *));
}
al_destroy_config(sys_config);
sys_config = NULL;
}
/* al_get_standard_path() does not work before the system driver is
* initialised. Before that, we need to call the underlying functions
* directly.
*/
static ALLEGRO_PATH *early_get_exename_path(void)
{
#if defined(ALLEGRO_WINDOWS)
return _al_win_get_path(ALLEGRO_EXENAME_PATH);
#elif defined(ALLEGRO_MACOSX)
return _al_osx_get_path(ALLEGRO_EXENAME_PATH);
#elif defined(ALLEGRO_IPHONE)
return _al_iphone_get_path(ALLEGRO_EXENAME_PATH);
#elif defined(ALLEGRO_UNIX)
return _al_unix_get_path(ALLEGRO_EXENAME_PATH);
#elif defined(ALLEGRO_ANDROID)
return _al_android_get_path(ALLEGRO_EXENAME_PATH);
#elif defined(ALLEGRO_SDL)
char* p = SDL_GetBasePath();
ALLEGRO_PATH *path = al_create_path_for_directory(p);
SDL_free(p);
return path;
#else
#error early_get_exename_path not implemented
#endif
}
static void read_allegro_cfg(void)
{
/* We assume that the stdio file interface is in effect. */
ALLEGRO_PATH *path;
ALLEGRO_CONFIG *temp;
if (!sys_config)
sys_config = al_create_config();
#if defined(ALLEGRO_UNIX) && !defined(ALLEGRO_IPHONE)
temp = al_load_config_file("/etc/allegro5rc");
if (temp) {
al_merge_config_into(sys_config, temp);
al_destroy_config(temp);
}
path = _al_unix_get_path(ALLEGRO_USER_HOME_PATH);
if (path) {
al_set_path_filename(path, "allegro5rc");
temp = al_load_config_file(al_path_cstr(path, '/'));
if (temp) {
al_merge_config_into(sys_config, temp);
al_destroy_config(temp);
}
al_set_path_filename(path, ".allegro5rc");
temp = al_load_config_file(al_path_cstr(path, '/'));
if (temp) {
al_merge_config_into(sys_config, temp);
al_destroy_config(temp);
}
al_destroy_path(path);
}
#endif
path = early_get_exename_path();
if (path) {
al_set_path_filename(path, "allegro5.cfg");
temp = al_load_config_file(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP));
if (temp) {
al_merge_config_into(sys_config, temp);
al_destroy_config(temp);
}
al_destroy_path(path);
}
/* Reconfigure logging in case something changed. */
_al_configure_logging();
}
/*
* Can a binary with version a use a library with version b?
*
* Let a = xa.ya.za.*
* Let b = xb.yb.zb.*
*
* When a has the unstable bit, a is compatible with b if xa.ya.za = xb.yb.zb.
* Otherwise, a is compatible with b if xa.ya = xb.yb and zb >= za.
*
* Otherwise a and b are incompatible.
*/
static bool compatible_versions(int a, int b)
{
int a_unstable = a & (1 << 31);
int a_major = (a & 0x7f000000) >> 24;
int a_sub = (a & 0x00ff0000) >> 16;
int a_wip = (a & 0x0000ff00) >> 8;
int b_major = (b & 0x7f000000) >> 24;
int b_sub = (b & 0x00ff0000) >> 16;
int b_wip = (b & 0x0000ff00) >> 8;
if (a_major != b_major) {
return false;
}
if (a_unstable && a_wip != b_wip) {
return false;
}
if (a_sub != b_sub) {
return false;
}
if (a_wip > b_wip) {
return false;
}
return true;
}
/* Function: al_install_system
*/
bool al_install_system(int version, int (*atexit_ptr)(void (*)(void)))
{
ALLEGRO_SYSTEM bootstrap;
ALLEGRO_SYSTEM *real_system;
int library_version = al_get_allegro_version();
if (active_sysdrv) {
return true;
}
/* Note: We cannot call logging functions yet.
* TODO: Maybe we want to do the check after the "bootstrap" system
* is available at least?
*/
if (!compatible_versions(version, library_version))
return false;
_al_tls_init_once();
_al_reinitialize_tls_values();
_al_vector_init(&_al_system_interfaces, sizeof(ALLEGRO_SYSTEM_INTERFACE *));
/* Set up a bootstrap system so the calls expecting it don't freak out */
memset(&bootstrap, 0, sizeof(bootstrap));
active_sysdrv = &bootstrap;
read_allegro_cfg();
#ifdef ALLEGRO_BCC32
/* This supresses exceptions on floating point divide by zero */
_control87(MCW_EM, MCW_EM);
#endif
/* Register builtin system drivers */
_al_register_system_interfaces();
/* Check for a user-defined system driver first */
real_system = find_system(&_user_system_interfaces);
/* If a user-defined driver is not found, look for a builtin one */
if (real_system == NULL) {
real_system = find_system(&_al_system_interfaces);
}
if (real_system == NULL) {
active_sysdrv = NULL;
return false;
}
active_sysdrv = real_system;
active_sysdrv->mouse_wheel_precision = 1;
ALLEGRO_INFO("Allegro version: %s\n", ALLEGRO_VERSION_STR);
if (strcmp(al_get_app_name(), "") == 0) {
al_set_app_name(NULL);
}
_al_add_exit_func(shutdown_system_driver, "shutdown_system_driver");
_al_dtor_list = _al_init_destructors();
_al_init_events();
_al_init_pixels();
_al_init_iio_table();
_al_init_convert_bitmap_list();
_al_init_timers();
#ifdef ALLEGRO_CFG_SHADER_GLSL
_al_glsl_init_shaders();
#endif
if (active_sysdrv->vt->heartbeat_init)
active_sysdrv->vt->heartbeat_init();
if (atexit_ptr && atexit_virgin) {
#ifndef ALLEGRO_ANDROID
atexit_ptr(al_uninstall_system);
#endif
atexit_virgin = false;
}
/* Clear errnos set while searching for config files. */
al_set_errno(0);
active_sysdrv->installed = true;
_al_srand(time(NULL));
return true;
}
/* Function: al_uninstall_system
*/
void al_uninstall_system(void)
{
/* Note: al_uninstall_system may get called multiple times without an
* al_install_system in between. For example if the user manually
* calls it at the end of the program it is called right again
* because it's installed as an atexit function by al_init.
*/
_al_run_destructors(_al_dtor_list);
_al_run_exit_funcs();
_al_shutdown_destructors(_al_dtor_list);
_al_dtor_list = NULL;
#ifdef ALLEGRO_CFG_SHADER_GLSL
_al_glsl_shutdown_shaders();
#endif
_al_shutdown_logging();
/* shutdown_system_driver is registered as an exit func so we don't need
* to do any more here.
*/
ASSERT(active_sysdrv == NULL);
}
/* Function: al_is_system_installed
*/
bool al_is_system_installed(void)
{
return (active_sysdrv && active_sysdrv->installed) ? true : false;
}
/* Hidden function: al_get_system_driver
* This was exported and documented in 5.0rc1 but probably shouldn't have been
* as ALLEGRO_SYSTEM is not documented.
*/
ALLEGRO_SYSTEM *al_get_system_driver(void)
{
return active_sysdrv;
}
/* Function: al_get_system_id
*/
ALLEGRO_SYSTEM_ID al_get_system_id(void)
{
ASSERT(active_sysdrv);
return active_sysdrv->vt->id;
}
/* Function: al_get_system_config
*/
ALLEGRO_CONFIG *al_get_system_config(void)
{
if (!sys_config)
sys_config = al_create_config();
return sys_config;
}
/* Function: al_get_standard_path
*/
ALLEGRO_PATH *al_get_standard_path(int id)
{
ASSERT(active_sysdrv);
ASSERT(active_sysdrv->vt);
ASSERT(active_sysdrv->vt->get_path);
if (id == ALLEGRO_EXENAME_PATH && active_sysdrv->user_exe_path)
return al_clone_path(active_sysdrv->user_exe_path);
if (id == ALLEGRO_RESOURCES_PATH && active_sysdrv->user_exe_path) {
ALLEGRO_PATH *exe_dir = al_clone_path(active_sysdrv->user_exe_path);
al_set_path_filename(exe_dir, NULL);
return exe_dir;
}
if (active_sysdrv->vt->get_path)
return active_sysdrv->vt->get_path(id);
return NULL;
}
/* Function: al_set_exe_name
*/
void al_set_exe_name(char const *path)
{
ASSERT(active_sysdrv);
if (active_sysdrv->user_exe_path) {
al_destroy_path(active_sysdrv->user_exe_path);
}
active_sysdrv->user_exe_path = al_create_path(path);
}
/* Function: al_set_org_name
*/
void al_set_org_name(const char *org_name)
{
if (!org_name)
org_name = "";
_al_sane_strncpy(_al_org_name, org_name, sizeof(_al_org_name));
}
/* Function: al_set_app_name
*/
void al_set_app_name(const char *app_name)
{
if (app_name) {
_al_sane_strncpy(_al_app_name, app_name, sizeof(_al_app_name));
}
else {
ALLEGRO_PATH *path;
path = al_get_standard_path(ALLEGRO_EXENAME_PATH);
_al_sane_strncpy(_al_app_name, al_get_path_filename(path), sizeof(_al_app_name));
al_destroy_path(path);
}
}
/* Function: al_get_org_name
*/
const char *al_get_org_name(void)
{
return _al_org_name;
}
/* Function: al_get_app_name
*/
const char *al_get_app_name(void)
{
return _al_app_name;
}
/* Function: al_inhibit_screensaver
*/
bool al_inhibit_screensaver(bool inhibit)
{
ASSERT(active_sysdrv);
if (active_sysdrv->vt->inhibit_screensaver)
return active_sysdrv->vt->inhibit_screensaver(inhibit);
else
return false;
}
void *_al_open_library(const char *filename)
{
ASSERT(active_sysdrv);
if (active_sysdrv->vt->open_library)
return active_sysdrv->vt->open_library(filename);
else
return NULL;
}
void *_al_import_symbol(void *library, const char *symbol)
{
ASSERT(active_sysdrv);
if (active_sysdrv->vt->import_symbol)
return active_sysdrv->vt->import_symbol(library, symbol);
else
return NULL;
}
void _al_close_library(void *library)
{
ASSERT(active_sysdrv);
if (active_sysdrv->vt->close_library)
active_sysdrv->vt->close_library(library);
}
/* vim: set sts=3 sw=3 et: */
You can’t perform that action at this time.