/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * BeOS system driver routines. * * By Jason Wilkins. * * desktop_color_depth() and yield_timeslice() support added by * Angelo Mottola. * * Synchronization functions added by Eric Botcazou. * * See readme.txt for copyright information. */ #include "bealleg.h" #include "allegro/internal/aintern.h" #include "allegro/platform/aintbeos.h" #ifndef SCAN_DEPEND #include #endif #ifndef ALLEGRO_BEOS #error something is wrong with the makefile #endif #define SYS_THREAD_PRIORITY B_NORMAL_PRIORITY #define SYS_THREAD_NAME "system driver" #define EXE_NAME_UNKNOWN "./UNKNOWN" #define PREFIX_I "al-bsys INFO: " #define PREFIX_W "al-bsys WARNING: " #define PREFIX_E "al-bsys ERROR: " status_t ignore_result = 0; volatile int _be_focus_count = 0; BeAllegroApp *_be_allegro_app = NULL; static thread_id system_thread_id = -1; static thread_id main_thread_id = -1; static sem_id system_started = -1; static char app_path[MAXPATHLEN] = "."; char wnd_title[WND_TITLE_SIZE]; static bool using_custom_allegro_app; /* BeAllegroApp::BeAllegroApp: */ BeAllegroApp::BeAllegroApp(const char *signature) : BApplication(signature) { } /* BeAllegroApp::QuitRequested: */ bool BeAllegroApp::QuitRequested(void) { return false; } /* BeAllegroApp::ReadyToRun: */ void BeAllegroApp::ReadyToRun() { release_sem(system_started); } /* _be_sys_get_executable_name: */ extern "C" void _be_sys_get_executable_name(char *output, int size) { image_info info; int32 cookie; cookie = 0; if (get_next_image_info(0, &cookie, &info) == B_NO_ERROR) { _al_sane_strncpy(output, info.name, size); } else { _al_sane_strncpy(output, EXE_NAME_UNKNOWN, size); } output[size-1] = '\0'; } /* system_thread: */ static int32 system_thread(void *data) { (void)data; if (_be_allegro_app == NULL) { char sig[MAXPATHLEN] = "application/x-vnd.Allegro-"; char exe[MAXPATHLEN]; char *term, *p; _be_sys_get_executable_name(exe, sizeof(exe)); strncat(sig, get_filename(exe), sizeof(sig)-1); sig[sizeof(sig)-1] = '\0'; _be_allegro_app = new BeAllegroApp(sig); using_custom_allegro_app = false; term = getenv("TERM"); if (!strcmp(term, "dumb")) { /* The TERM environmental variable is set to "dumb" if the app was * not started from a terminal. */ p = &exe[strlen(exe) - 1]; while (*p != '/') p--; *(p + 1) = '\0'; _al_sane_strncpy(app_path, exe, MAXPATHLEN); } } else { using_custom_allegro_app = true; } _be_allegro_app->Run(); TRACE(PREFIX_I "system thread exited\n"); return 0; } /* be_sys_init: */ extern "C" int be_sys_init(void) { int32 cookie; thread_info info; struct utsname os_name; char path[MAXPATHLEN]; cookie = 0; if (get_next_thread_info(0, &cookie, &info) == B_OK) { main_thread_id = info.thread; } else { goto cleanup; } _be_mouse_view_attached = create_sem(0, "waiting for mouse view attach..."); if (_be_mouse_view_attached < 0) { goto cleanup; } _be_sound_stream_lock = create_sem(1, "audiostream lock"); if (_be_sound_stream_lock < 0) { goto cleanup; } system_started = create_sem(0, "starting system driver..."); if(system_started < 0) { goto cleanup; } system_thread_id = spawn_thread(system_thread, SYS_THREAD_NAME, SYS_THREAD_PRIORITY, NULL); if (system_thread_id < 0) { goto cleanup; } resume_thread(system_thread_id); acquire_sem(system_started); delete_sem(system_started); uname(&os_name); os_type = OSTYPE_BEOS; os_multitasking = TRUE; os_version = atoi(strtok(os_name.release, ".")); os_revision = atoi(strtok(NULL, ".")); chdir(app_path); _be_sys_get_executable_name(path, sizeof(path)); path[sizeof(path)-1] = '\0'; do_uconvert(get_filename(path), U_CURRENT, wnd_title, U_UTF8, WND_TITLE_SIZE); return 0; cleanup: { be_sys_exit(); return 1; } } /* be_sys_exit: */ extern "C" void be_sys_exit(void) { if (main_thread_id > 0) { main_thread_id = -1; } if (system_started > 0) { delete_sem(system_started); system_started = -1; } if (system_thread_id > 0) { ASSERT(_be_allegro_app != NULL); _be_allegro_app->Lock(); _be_allegro_app->Quit(); _be_allegro_app->Unlock(); wait_for_thread(system_thread_id, &ignore_result); system_thread_id = -1; } if (_be_mouse_view_attached > 0) { delete_sem(_be_mouse_view_attached); _be_mouse_view_attached = -1; } if (_be_sound_stream_lock > 0) { delete_sem(_be_sound_stream_lock); _be_sound_stream_lock = -1; } if (!using_custom_allegro_app) { delete _be_allegro_app; _be_allegro_app = NULL; } } /* be_sys_get_executable_name: */ extern "C" void be_sys_get_executable_name(char *output, int size) { char *buffer; buffer = (char *)malloc(size); if (buffer != NULL) { _be_sys_get_executable_name(buffer, size); do_uconvert(buffer, U_UTF8, output, U_CURRENT, size); free(buffer); } else { do_uconvert(EXE_NAME_UNKNOWN, U_ASCII, output, U_CURRENT, size); } } /* be_sys_find_resource: * This is the same of the unix resource finder; it looks into the * home directory and in /etc. */ int be_sys_find_resource(char *dest, AL_CONST char *resource, int size) { char buf[256], tmp[256], *last; char *home = getenv("HOME"); if (home) { /* look for ~/file */ append_filename(buf, uconvert_ascii(home, tmp), resource, sizeof(buf)); if (exists(buf)) { ustrzcpy(dest, size, buf); return 0; } /* if it is a .cfg, look for ~/.filerc */ if (ustricmp(get_extension(resource), uconvert_ascii("cfg", tmp)) == 0) { ustrzcpy(buf, sizeof(buf) - ucwidth(OTHER_PATH_SEPARATOR), uconvert_ascii(home, tmp)); put_backslash(buf); ustrzcat(buf, sizeof(buf), uconvert_ascii(".", tmp)); ustrzcpy(tmp, sizeof(tmp), resource); ustrzcat(buf, sizeof(buf), ustrtok_r(tmp, ".", &last)); ustrzcat(buf, sizeof(buf), uconvert_ascii("rc", tmp)); if (file_exists(buf, FA_ARCH | FA_RDONLY | FA_HIDDEN, NULL)) { ustrzcpy(dest, size, buf); return 0; } } } /* look for /etc/file */ append_filename(buf, uconvert_ascii("/etc/", tmp), resource, sizeof(buf)); if (exists(buf)) { ustrzcpy(dest, size, buf); return 0; } /* if it is a .cfg, look for /etc/filerc */ if (ustricmp(get_extension(resource), uconvert_ascii("cfg", tmp)) == 0) { ustrzcpy(buf, sizeof(buf), uconvert_ascii("/etc/", tmp)); ustrzcpy(tmp, sizeof(tmp), resource); ustrzcat(buf, sizeof(buf), ustrtok_r(tmp, ".", &last)); ustrzcat(buf, sizeof(buf), uconvert_ascii("rc", tmp)); if (exists(buf)) { ustrzcpy(dest, size, buf); return 0; } } return -1; } extern "C" void be_sys_set_window_title(AL_CONST char *name) { do_uconvert(name, U_CURRENT, wnd_title, U_UTF8, WND_TITLE_SIZE); if (_be_window) _be_window->SetTitle(wnd_title); } extern "C" int be_sys_set_close_button_callback(void (*proc)(void)) { if (!_be_window) return -1; _be_window_close_hook = proc; if (proc) _be_window->SetFlags(_be_window->Flags() & ~B_NOT_CLOSABLE); else _be_window->SetFlags(_be_window->Flags() | B_NOT_CLOSABLE); return 0; } extern "C" void be_sys_message(AL_CONST char *msg) { char filename[MAXPATHLEN]; char *title; char tmp[ALLEGRO_MESSAGE_SIZE]; char tmp2[ALLEGRO_MESSAGE_SIZE]; get_executable_name(filename, sizeof(filename)); title = get_filename(filename); BAlert *alert = new BAlert(title, uconvert(msg, U_CURRENT, tmp, U_UTF8, ALLEGRO_MESSAGE_SIZE), uconvert(get_config_text("Ok"), U_CURRENT, tmp2, U_UTF8, ALLEGRO_MESSAGE_SIZE)); alert->SetShortcut(0, B_ESCAPE); be_app->ShowCursor(); alert->Go(); be_app->HideCursor(); } extern "C" int be_sys_desktop_color_depth(void) { display_mode current_mode; BScreen().GetMode(¤t_mode); switch(current_mode.space) { case B_CMAP8: return 8; case B_RGB15: case B_RGBA15: return 15; case B_RGB16: return 16; case B_RGB32: case B_RGBA32: return 32; } return -1; } extern "C" int be_sys_get_desktop_resolution(int *width, int *height) { BScreen screen(B_MAIN_SCREEN_ID); *width = screen.Frame().IntegerWidth() + 1; *height = screen.Frame().IntegerHeight() + 1; return 0; } extern "C" void be_sys_get_gfx_safe_mode(int *driver, struct GFX_MODE *mode) { *driver = GFX_BWINDOW; mode->width = 320; mode->height = 200; mode->bpp = 8; } extern "C" void be_sys_yield_timeslice(void) { snooze(0); } /* custom mutex that supports nested locking */ struct my_mutex { int lock_count; /* level of nested locking */ thread_id owner; /* thread which owns the mutex */ sem_id actual_mutex; /* underlying mutex object */ }; /* be_sys_create_mutex: * Creates a mutex and returns a pointer to it. */ extern "C" void *be_sys_create_mutex(void) { struct my_mutex *mx; mx = (struct my_mutex *)malloc(sizeof(struct my_mutex)); if (!mx) { *allegro_errno = ENOMEM; return NULL; } mx->lock_count = 0; mx->owner = (thread_id) 0; mx->actual_mutex = create_sem(1, "internal mutex"); if (mx->actual_mutex < 0) { free(mx); return NULL; } return (void *)mx; } /* be_sys_destroy_mutex: * Destroys a mutex. */ extern "C" void be_sys_destroy_mutex(void *handle) { struct my_mutex *mx = (struct my_mutex *)handle; delete_sem(mx->actual_mutex); free(mx); } /* be_sys_lock_mutex: * Locks a mutex. */ extern "C" void be_sys_lock_mutex(void *handle) { struct my_mutex *mx = (struct my_mutex *)handle; if (mx->owner != find_thread(NULL)) { acquire_sem(mx->actual_mutex); mx->owner = find_thread(NULL); } mx->lock_count++; } /* be_sys_unlock_mutex: * Unlocks a mutex. */ extern "C" void be_sys_unlock_mutex(void *handle) { struct my_mutex *mx = (struct my_mutex *)handle; mx->lock_count--; if (mx->lock_count == 0) { mx->owner = (thread_id) 0; release_sem(mx->actual_mutex); } } extern "C" void be_sys_suspend(void) { if (system_thread_id > 0) { suspend_thread(system_thread_id); } } extern "C" void be_sys_resume(void) { if (system_thread_id > 0) { resume_thread(system_thread_id); } } extern "C" void be_main_suspend(void) { if (main_thread_id > 0) { suspend_thread(main_thread_id); } } extern "C" void be_main_resume(void) { if (main_thread_id > 0) { resume_thread(main_thread_id); } } int32 killer_thread(void *data) { int32 cookie; team_info info; kill_thread(main_thread_id); allegro_exit(); cookie = 0; get_next_team_info(&cookie, &info); kill_team(info.team); return 1; } void _be_terminate(thread_id caller, bool exit_caller) { thread_id killer; killer = spawn_thread(killer_thread, "son of sam", 120, NULL); resume_thread(killer); if (exit_caller) exit_thread(1); }