Merge branch 'master' into feature/global-config
This commit is contained in:
@@ -32,6 +32,16 @@ set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(86Box Threads::Threads)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
include_directories(${SDL2_INCLUDE_DIRS})
|
||||
if(STATIC_BUILD AND TARGET SDL2::SDL2-static)
|
||||
target_link_libraries(86Box SDL2::SDL2-static)
|
||||
elseif(TARGET SDL2::SDL2)
|
||||
target_link_libraries(86Box SDL2::SDL2)
|
||||
else()
|
||||
target_link_libraries(86Box ${SDL2_LIBRARIES})
|
||||
endif()
|
||||
|
||||
add_library(ui OBJECT
|
||||
unix_sdl.c
|
||||
unix_cdrom.c
|
||||
|
||||
@@ -162,6 +162,7 @@ ioctl_is_empty(const void *local)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
ioctl_ext_medium_changed(UNUSED(void *local))
|
||||
{
|
||||
@@ -174,6 +175,7 @@ ioctl_ext_medium_changed(UNUSED(void *local))
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ioctl_close(void *local)
|
||||
|
||||
376
src/unix/gamemode/gamemode_client.h
Normal file
376
src/unix/gamemode/gamemode_client.h
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Feral Interactive nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef CLIENT_GAMEMODE_H
|
||||
#define CLIENT_GAMEMODE_H
|
||||
/*
|
||||
* GameMode supports the following client functions
|
||||
* Requests are refcounted in the daemon
|
||||
*
|
||||
* int gamemode_request_start() - Request gamemode starts
|
||||
* 0 if the request was sent successfully
|
||||
* -1 if the request failed
|
||||
*
|
||||
* int gamemode_request_end() - Request gamemode ends
|
||||
* 0 if the request was sent successfully
|
||||
* -1 if the request failed
|
||||
*
|
||||
* GAMEMODE_AUTO can be defined to make the above two functions apply during static init and
|
||||
* destruction, as appropriate. In this configuration, errors will be printed to stderr
|
||||
*
|
||||
* int gamemode_query_status() - Query the current status of gamemode
|
||||
* 0 if gamemode is inactive
|
||||
* 1 if gamemode is active
|
||||
* 2 if gamemode is active and this client is registered
|
||||
* -1 if the query failed
|
||||
*
|
||||
* int gamemode_request_start_for(pid_t pid) - Request gamemode starts for another process
|
||||
* 0 if the request was sent successfully
|
||||
* -1 if the request failed
|
||||
* -2 if the request was rejected
|
||||
*
|
||||
* int gamemode_request_end_for(pid_t pid) - Request gamemode ends for another process
|
||||
* 0 if the request was sent successfully
|
||||
* -1 if the request failed
|
||||
* -2 if the request was rejected
|
||||
*
|
||||
* int gamemode_query_status_for(pid_t pid) - Query status of gamemode for another process
|
||||
* 0 if gamemode is inactive
|
||||
* 1 if gamemode is active
|
||||
* 2 if gamemode is active and this client is registered
|
||||
* -1 if the query failed
|
||||
*
|
||||
* const char* gamemode_error_string() - Get an error string
|
||||
* returns a string describing any of the above errors
|
||||
*
|
||||
* Note: All the above requests can be blocking - dbus requests can and will block while the daemon
|
||||
* handles the request. It is not recommended to make these calls in performance critical code
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
static char internal_gamemode_client_error_string[512] = { 0 };
|
||||
|
||||
/**
|
||||
* Load libgamemode dynamically to dislodge us from most dependencies.
|
||||
* This allows clients to link and/or use this regardless of runtime.
|
||||
* See SDL2 for an example of the reasoning behind this in terms of
|
||||
* dynamic versioning as well.
|
||||
*/
|
||||
static volatile int internal_libgamemode_loaded = 1;
|
||||
|
||||
/* Typedefs for the functions to load */
|
||||
typedef int (*api_call_return_int)(void);
|
||||
typedef const char *(*api_call_return_cstring)(void);
|
||||
typedef int (*api_call_pid_return_int)(pid_t);
|
||||
|
||||
/* Storage for functors */
|
||||
static api_call_return_int REAL_internal_gamemode_request_start = NULL;
|
||||
static api_call_return_int REAL_internal_gamemode_request_end = NULL;
|
||||
static api_call_return_int REAL_internal_gamemode_query_status = NULL;
|
||||
static api_call_return_cstring REAL_internal_gamemode_error_string = NULL;
|
||||
static api_call_pid_return_int REAL_internal_gamemode_request_start_for = NULL;
|
||||
static api_call_pid_return_int REAL_internal_gamemode_request_end_for = NULL;
|
||||
static api_call_pid_return_int REAL_internal_gamemode_query_status_for = NULL;
|
||||
|
||||
/**
|
||||
* Internal helper to perform the symbol binding safely.
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
__attribute__((always_inline)) static inline int internal_bind_libgamemode_symbol(
|
||||
void *handle, const char *name, void **out_func, size_t func_size, bool required)
|
||||
{
|
||||
void *symbol_lookup = NULL;
|
||||
char *dl_error = NULL;
|
||||
|
||||
/* Safely look up the symbol */
|
||||
symbol_lookup = dlsym(handle, name);
|
||||
dl_error = dlerror();
|
||||
if (required && (dl_error || !symbol_lookup)) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"dlsym failed - %s",
|
||||
dl_error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Have the symbol correctly, copy it to make it usable */
|
||||
memcpy(out_func, &symbol_lookup, func_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads libgamemode and needed functions
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
__attribute__((always_inline)) static inline int internal_load_libgamemode(void)
|
||||
{
|
||||
/* We start at 1, 0 is a success and -1 is a fail */
|
||||
if (internal_libgamemode_loaded != 1) {
|
||||
return internal_libgamemode_loaded;
|
||||
}
|
||||
|
||||
/* Anonymous struct type to define our bindings */
|
||||
struct binding {
|
||||
const char *name;
|
||||
void **functor;
|
||||
size_t func_size;
|
||||
bool required;
|
||||
} bindings[] = {
|
||||
{ "real_gamemode_request_start",
|
||||
(void **)&REAL_internal_gamemode_request_start,
|
||||
sizeof(REAL_internal_gamemode_request_start),
|
||||
true },
|
||||
{ "real_gamemode_request_end",
|
||||
(void **)&REAL_internal_gamemode_request_end,
|
||||
sizeof(REAL_internal_gamemode_request_end),
|
||||
true },
|
||||
{ "real_gamemode_query_status",
|
||||
(void **)&REAL_internal_gamemode_query_status,
|
||||
sizeof(REAL_internal_gamemode_query_status),
|
||||
false },
|
||||
{ "real_gamemode_error_string",
|
||||
(void **)&REAL_internal_gamemode_error_string,
|
||||
sizeof(REAL_internal_gamemode_error_string),
|
||||
true },
|
||||
{ "real_gamemode_request_start_for",
|
||||
(void **)&REAL_internal_gamemode_request_start_for,
|
||||
sizeof(REAL_internal_gamemode_request_start_for),
|
||||
false },
|
||||
{ "real_gamemode_request_end_for",
|
||||
(void **)&REAL_internal_gamemode_request_end_for,
|
||||
sizeof(REAL_internal_gamemode_request_end_for),
|
||||
false },
|
||||
{ "real_gamemode_query_status_for",
|
||||
(void **)&REAL_internal_gamemode_query_status_for,
|
||||
sizeof(REAL_internal_gamemode_query_status_for),
|
||||
false },
|
||||
};
|
||||
|
||||
void *libgamemode = NULL;
|
||||
|
||||
/* Try and load libgamemode */
|
||||
libgamemode = dlopen("libgamemode.so.0", RTLD_NOW);
|
||||
if (!libgamemode) {
|
||||
/* Attempt to load unversioned library for compatibility with older
|
||||
* versions (as of writing, there are no ABI changes between the two -
|
||||
* this may need to change if ever ABI-breaking changes are made) */
|
||||
libgamemode = dlopen("libgamemode.so", RTLD_NOW);
|
||||
if (!libgamemode) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"dlopen failed - %s",
|
||||
dlerror());
|
||||
internal_libgamemode_loaded = -1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to bind all symbols */
|
||||
for (size_t i = 0; i < sizeof(bindings) / sizeof(bindings[0]); i++) {
|
||||
struct binding *binder = &bindings[i];
|
||||
|
||||
if (internal_bind_libgamemode_symbol(libgamemode,
|
||||
binder->name,
|
||||
binder->functor,
|
||||
binder->func_size,
|
||||
binder->required)) {
|
||||
internal_libgamemode_loaded = -1;
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
|
||||
/* Success */
|
||||
internal_libgamemode_loaded = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the real libgamemode
|
||||
*/
|
||||
__attribute__((always_inline)) static inline const char *gamemode_error_string(void)
|
||||
{
|
||||
/* If we fail to load the system gamemode, or we have an error string already, return our error
|
||||
* string instead of diverting to the system version */
|
||||
if (internal_load_libgamemode() < 0 || internal_gamemode_client_error_string[0] != '\0') {
|
||||
return internal_gamemode_client_error_string;
|
||||
}
|
||||
|
||||
/* Assert for static analyser that the function is not NULL */
|
||||
assert(REAL_internal_gamemode_error_string != NULL);
|
||||
|
||||
return REAL_internal_gamemode_error_string();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the real libgamemode
|
||||
* Allow automatically requesting game mode
|
||||
* Also prints errors as they happen.
|
||||
*/
|
||||
#ifdef GAMEMODE_AUTO
|
||||
__attribute__((constructor))
|
||||
#else
|
||||
__attribute__((always_inline)) static inline
|
||||
#endif
|
||||
int gamemode_request_start(void)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
#ifdef GAMEMODE_AUTO
|
||||
fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string());
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Assert for static analyser that the function is not NULL */
|
||||
assert(REAL_internal_gamemode_request_start != NULL);
|
||||
|
||||
if (REAL_internal_gamemode_request_start() < 0) {
|
||||
#ifdef GAMEMODE_AUTO
|
||||
fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string());
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
#ifdef GAMEMODE_AUTO
|
||||
__attribute__((destructor))
|
||||
#else
|
||||
__attribute__((always_inline)) static inline
|
||||
#endif
|
||||
int gamemode_request_end(void)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
#ifdef GAMEMODE_AUTO
|
||||
fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string());
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Assert for static analyser that the function is not NULL */
|
||||
assert(REAL_internal_gamemode_request_end != NULL);
|
||||
|
||||
if (REAL_internal_gamemode_request_end() < 0) {
|
||||
#ifdef GAMEMODE_AUTO
|
||||
fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string());
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
__attribute__((always_inline)) static inline int gamemode_query_status(void)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_query_status == NULL) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"gamemode_query_status missing (older host?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return REAL_internal_gamemode_query_status();
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
__attribute__((always_inline)) static inline int gamemode_request_start_for(pid_t pid)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_request_start_for == NULL) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"gamemode_request_start_for missing (older host?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return REAL_internal_gamemode_request_start_for(pid);
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
__attribute__((always_inline)) static inline int gamemode_request_end_for(pid_t pid)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_request_end_for == NULL) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"gamemode_request_end_for missing (older host?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return REAL_internal_gamemode_request_end_for(pid);
|
||||
}
|
||||
|
||||
/* Redirect to the real libgamemode */
|
||||
__attribute__((always_inline)) static inline int gamemode_query_status_for(pid_t pid)
|
||||
{
|
||||
/* Need to load gamemode */
|
||||
if (internal_load_libgamemode() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (REAL_internal_gamemode_query_status_for == NULL) {
|
||||
snprintf(internal_gamemode_client_error_string,
|
||||
sizeof(internal_gamemode_client_error_string),
|
||||
"gamemode_query_status_for missing (older host?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return REAL_internal_gamemode_query_status_for(pid);
|
||||
}
|
||||
|
||||
#endif // CLIENT_GAMEMODE_H
|
||||
148
src/unix/unix.c
148
src/unix/unix.c
@@ -64,8 +64,8 @@ int fixed_size_x = 640;
|
||||
int fixed_size_y = 480;
|
||||
extern int title_set;
|
||||
extern wchar_t sdl_win_title[512];
|
||||
plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS];
|
||||
joystick_t joystick_state[GAMEPORT_MAX][MAX_JOYSTICKS];
|
||||
plat_joystick_state_t plat_joystick_state[MAX_PLAT_JOYSTICKS];
|
||||
joystick_state_t joystick_state[GAMEPORT_MAX][MAX_JOYSTICKS];
|
||||
int joysticks_present;
|
||||
SDL_mutex *blitmtx;
|
||||
SDL_threadID eventthread;
|
||||
@@ -208,22 +208,33 @@ dynld_module(const char *name, dllimp_t *table)
|
||||
return modhandle;
|
||||
}
|
||||
|
||||
#define TMPFILE_BUFSIZE 1024 // Assumed max buffer size
|
||||
void
|
||||
plat_tempfile(char *bufp, char *prefix, char *suffix)
|
||||
{
|
||||
struct tm *calendertime;
|
||||
struct timeval t;
|
||||
time_t curtime;
|
||||
size_t used = 0;
|
||||
|
||||
if (prefix != NULL)
|
||||
sprintf(bufp, "%s-", prefix);
|
||||
else
|
||||
strcpy(bufp, "");
|
||||
used = snprintf(bufp, TMPFILE_BUFSIZE, "%s-", prefix);
|
||||
else if (TMPFILE_BUFSIZE > 0)
|
||||
bufp[0] = '\0';
|
||||
|
||||
gettimeofday(&t, NULL);
|
||||
curtime = time(NULL);
|
||||
calendertime = localtime(&curtime);
|
||||
sprintf(&bufp[strlen(bufp)], "%d%02d%02d-%02d%02d%02d-%03ld%s", calendertime->tm_year, calendertime->tm_mon, calendertime->tm_mday, calendertime->tm_hour, calendertime->tm_min, calendertime->tm_sec, t.tv_usec / 1000, suffix);
|
||||
|
||||
if (used < TMPFILE_BUFSIZE) {
|
||||
snprintf(bufp + used, TMPFILE_BUFSIZE - used,
|
||||
"%d%02d%02d-%02d%02d%02d-%03" PRId32 "%s",
|
||||
calendertime->tm_year, calendertime->tm_mon, calendertime->tm_mday,
|
||||
calendertime->tm_hour, calendertime->tm_min, calendertime->tm_sec,
|
||||
(int32_t)(t.tv_usec / 1000), suffix);
|
||||
}
|
||||
}
|
||||
#undef TMPFILE_BUFSIZE
|
||||
|
||||
int
|
||||
plat_getcwd(char *bufp, int max)
|
||||
@@ -565,7 +576,7 @@ main_thread(UNUSED(void *param))
|
||||
old_time = new_time;
|
||||
if (drawits > 0 && !dopause) {
|
||||
/* Yes, so do one frame now. */
|
||||
drawits -= 10;
|
||||
drawits -= force_10ms ? 10 : 1;
|
||||
if (drawits > 50)
|
||||
drawits = 0;
|
||||
|
||||
@@ -573,7 +584,7 @@ main_thread(UNUSED(void *param))
|
||||
pc_run();
|
||||
|
||||
/* Every 200 frames we save the machine status. */
|
||||
if (++frames >= 200 && nvr_dosave) {
|
||||
if (++frames >= (force_10ms ? 200 : 2000) && nvr_dosave) {
|
||||
nvr_save();
|
||||
nvr_dosave = 0;
|
||||
frames = 0;
|
||||
@@ -783,65 +794,83 @@ plat_pause(int p)
|
||||
}
|
||||
}
|
||||
|
||||
#define TMP_PATH_BUFSIZE 1024
|
||||
void
|
||||
plat_init_rom_paths(void)
|
||||
{
|
||||
#ifndef __APPLE__
|
||||
if (getenv("XDG_DATA_HOME")) {
|
||||
char xdg_rom_path[1024] = { 0 };
|
||||
|
||||
strncpy(xdg_rom_path, getenv("XDG_DATA_HOME"), 1024);
|
||||
path_slash(xdg_rom_path);
|
||||
strncat(xdg_rom_path, "86Box/", 1023);
|
||||
|
||||
if (!plat_dir_check(xdg_rom_path))
|
||||
const char *xdg_data_home = getenv("XDG_DATA_HOME");
|
||||
if (xdg_data_home) {
|
||||
char xdg_rom_path[TMP_PATH_BUFSIZE] = {0};
|
||||
size_t used = snprintf(xdg_rom_path, sizeof(xdg_rom_path), "%s/", xdg_data_home);
|
||||
if (used < sizeof(xdg_rom_path))
|
||||
used += snprintf(xdg_rom_path + used, sizeof(xdg_rom_path) - used, "86Box/");
|
||||
if (used < sizeof(xdg_rom_path) && !plat_dir_check(xdg_rom_path))
|
||||
plat_dir_create(xdg_rom_path);
|
||||
strcat(xdg_rom_path, "roms/");
|
||||
|
||||
if (!plat_dir_check(xdg_rom_path))
|
||||
if (used < sizeof(xdg_rom_path))
|
||||
used += snprintf(xdg_rom_path + used, sizeof(xdg_rom_path) - used, "roms/");
|
||||
if (used < sizeof(xdg_rom_path) && !plat_dir_check(xdg_rom_path))
|
||||
plat_dir_create(xdg_rom_path);
|
||||
rom_add_path(xdg_rom_path);
|
||||
if (used < sizeof(xdg_rom_path))
|
||||
rom_add_path(xdg_rom_path);
|
||||
} else {
|
||||
char home_rom_path[1024] = { 0 };
|
||||
|
||||
snprintf(home_rom_path, 1024, "%s/.local/share/86Box/", getenv("HOME") ? getenv("HOME") : getpwuid(getuid())->pw_dir);
|
||||
|
||||
if (!plat_dir_check(home_rom_path))
|
||||
plat_dir_create(home_rom_path);
|
||||
strcat(home_rom_path, "roms/");
|
||||
|
||||
if (!plat_dir_check(home_rom_path))
|
||||
plat_dir_create(home_rom_path);
|
||||
rom_add_path(home_rom_path);
|
||||
}
|
||||
if (getenv("XDG_DATA_DIRS")) {
|
||||
char *xdg_rom_paths = strdup(getenv("XDG_DATA_DIRS"));
|
||||
char *xdg_rom_paths_orig = xdg_rom_paths;
|
||||
char *cur_xdg_rom_path = NULL;
|
||||
|
||||
if (xdg_rom_paths) {
|
||||
while (xdg_rom_paths[strlen(xdg_rom_paths) - 1] == ':') {
|
||||
xdg_rom_paths[strlen(xdg_rom_paths) - 1] = '\0';
|
||||
}
|
||||
while ((cur_xdg_rom_path = local_strsep(&xdg_rom_paths, ":")) != NULL) {
|
||||
char real_xdg_rom_path[1024] = { '\0' };
|
||||
strcat(real_xdg_rom_path, cur_xdg_rom_path);
|
||||
path_slash(real_xdg_rom_path);
|
||||
strcat(real_xdg_rom_path, "86Box/roms/");
|
||||
rom_add_path(real_xdg_rom_path);
|
||||
}
|
||||
const char *home = getenv("HOME");
|
||||
if (!home) {
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
if (pw)
|
||||
home = pw->pw_dir;
|
||||
}
|
||||
|
||||
if (home) {
|
||||
char home_rom_path[TMP_PATH_BUFSIZE] = {0};
|
||||
size_t used = snprintf(home_rom_path, sizeof(home_rom_path),
|
||||
"%s/.local/share/86Box/", home);
|
||||
if (used < sizeof(home_rom_path) && !plat_dir_check(home_rom_path))
|
||||
plat_dir_create(home_rom_path);
|
||||
if (used < sizeof(home_rom_path))
|
||||
used += snprintf(home_rom_path + used,
|
||||
sizeof(home_rom_path) - used, "roms/");
|
||||
if (used < sizeof(home_rom_path) && !plat_dir_check(home_rom_path))
|
||||
plat_dir_create(home_rom_path);
|
||||
if (used < sizeof(home_rom_path))
|
||||
rom_add_path(home_rom_path);
|
||||
}
|
||||
}
|
||||
|
||||
const char *xdg_data_dirs = getenv("XDG_DATA_DIRS");
|
||||
if (xdg_data_dirs) {
|
||||
char *xdg_rom_paths = strdup(xdg_data_dirs);
|
||||
if (xdg_rom_paths) {
|
||||
// Trim trailing colons
|
||||
size_t len = strlen(xdg_rom_paths);
|
||||
while (len > 0 && xdg_rom_paths[len - 1] == ':')
|
||||
xdg_rom_paths[--len] = '\0';
|
||||
|
||||
char *saveptr = NULL;
|
||||
char *cur_xdg = strtok_r(xdg_rom_paths, ":", &saveptr);
|
||||
while (cur_xdg) {
|
||||
char real_xdg_rom_path[TMP_PATH_BUFSIZE] = {0};
|
||||
size_t used = snprintf(real_xdg_rom_path,
|
||||
sizeof(real_xdg_rom_path),
|
||||
"%s/86Box/roms/", cur_xdg);
|
||||
if (used < sizeof(real_xdg_rom_path))
|
||||
rom_add_path(real_xdg_rom_path);
|
||||
cur_xdg = strtok_r(NULL, ":", &saveptr);
|
||||
}
|
||||
|
||||
free(xdg_rom_paths);
|
||||
}
|
||||
free(xdg_rom_paths_orig);
|
||||
} else {
|
||||
rom_add_path("/usr/local/share/86Box/roms/");
|
||||
rom_add_path("/usr/share/86Box/roms/");
|
||||
}
|
||||
#else
|
||||
char default_rom_path[1024] = { '\0' };
|
||||
char default_rom_path[TMP_PATH_BUFSIZE] = {0};
|
||||
getDefaultROMPath(default_rom_path);
|
||||
rom_add_path(default_rom_path);
|
||||
#endif
|
||||
}
|
||||
#undef TMP_PATH_BUFSIZE
|
||||
|
||||
void
|
||||
plat_get_global_config_dir(char *outbuf, const size_t len)
|
||||
@@ -919,6 +948,11 @@ void (*f_rl_callback_handler_remove)(void) = NULL;
|
||||
# define LIBEDIT_LIBRARY "libedit.so"
|
||||
#endif
|
||||
|
||||
void ui_sb_update_icon_wp(int tag, int state)
|
||||
{
|
||||
/* No-op */
|
||||
}
|
||||
|
||||
uint32_t
|
||||
timer_onesec(uint32_t interval, UNUSED(void *param))
|
||||
{
|
||||
@@ -972,12 +1006,12 @@ monitor_thread(UNUSED(void *param))
|
||||
printf(
|
||||
"fddload <id> <filename> <wp> - Load floppy disk image into drive <id>.\n"
|
||||
"cdload <id> <filename> - Load CD-ROM image into drive <id>.\n"
|
||||
"zipload <id> <filename> <wp> - Load ZIP image into ZIP drive <id>.\n"
|
||||
"rdiskload <id> <filename> <wp> - Load removable disk image into removable disk drive <id>.\n"
|
||||
"cartload <id> <filename> <wp> - Load cartridge image into cartridge drive <id>.\n"
|
||||
"moload <id> <filename> <wp> - Load MO image into MO drive <id>.\n\n"
|
||||
"fddeject <id> - eject disk from floppy drive <id>.\n"
|
||||
"cdeject <id> - eject disc from CD-ROM drive <id>.\n"
|
||||
"zipeject <id> - eject ZIP image from ZIP drive <id>.\n"
|
||||
"rdiskeject <id> - eject removable disk image from removable disk drive <id>.\n"
|
||||
"carteject <id> - eject cartridge from drive <id>.\n"
|
||||
"moeject <id> - eject image from MO drive <id>.\n\n"
|
||||
"hardreset - hard reset the emulated system.\n"
|
||||
@@ -1082,8 +1116,8 @@ monitor_thread(UNUSED(void *param))
|
||||
mo_eject(atoi(xargv[1]));
|
||||
} else if (strncasecmp(xargv[0], "carteject", 8) == 0 && cmdargc >= 2) {
|
||||
cartridge_eject(atoi(xargv[1]));
|
||||
} else if (strncasecmp(xargv[0], "zipeject", 8) == 0 && cmdargc >= 2) {
|
||||
zip_eject(atoi(xargv[1]));
|
||||
} else if (strncasecmp(xargv[0], "rdiskeject", 8) == 0 && cmdargc >= 2) {
|
||||
rdisk_eject(atoi(xargv[1]));
|
||||
} else if (strncasecmp(xargv[0], "fddload", 7) == 0 && cmdargc >= 4) {
|
||||
uint8_t id;
|
||||
uint8_t wp;
|
||||
@@ -1150,7 +1184,7 @@ monitor_thread(UNUSED(void *param))
|
||||
printf("Inserting tape into cartridge holder %hhu: %s\n", id, fn);
|
||||
cartridge_mount(id, fn, wp);
|
||||
}
|
||||
} else if (strncasecmp(xargv[0], "zipload", 7) == 0 && cmdargc >= 4) {
|
||||
} else if (strncasecmp(xargv[0], "rdiskload", 7) == 0 && cmdargc >= 4) {
|
||||
uint8_t id;
|
||||
uint8_t wp;
|
||||
bool err = false;
|
||||
@@ -1169,8 +1203,8 @@ monitor_thread(UNUSED(void *param))
|
||||
if (fn[strlen(fn) - 1] == '\''
|
||||
|| fn[strlen(fn) - 1] == '"')
|
||||
fn[strlen(fn) - 1] = '\0';
|
||||
printf("Inserting disk into ZIP drive %c: %s\n", id + 'A', fn);
|
||||
zip_mount(id, fn, wp);
|
||||
printf("Inserting disk into removable disk drive %c: %s\n", id + 'A', fn);
|
||||
rdisk_mount(id, fn, wp);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Handle the platform-side of CDROM/ZIP/MO drives.
|
||||
* Handle the platform-side of CDROM/RDisk/MO drives.
|
||||
*
|
||||
*
|
||||
*
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <86box/cdrom.h>
|
||||
#include <86box/cdrom_image.h>
|
||||
#include <86box/mo.h>
|
||||
#include <86box/zip.h>
|
||||
#include <86box/rdisk.h>
|
||||
#include <86box/scsi_disk.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/ui.h>
|
||||
@@ -220,58 +220,58 @@ mo_reload(uint8_t id)
|
||||
}
|
||||
|
||||
void
|
||||
zip_eject(uint8_t id)
|
||||
rdisk_eject(uint8_t id)
|
||||
{
|
||||
zip_t *dev = (zip_t *) zip_drives[id].priv;
|
||||
rdisk_t *dev = (rdisk_t *) rdisk_drives[id].priv;
|
||||
|
||||
zip_disk_close(dev);
|
||||
if (zip_drives[id].bus_type) {
|
||||
rdisk_disk_close(dev);
|
||||
if (rdisk_drives[id].bus_type) {
|
||||
/* Signal disk change to the emulated machine. */
|
||||
zip_insert(dev);
|
||||
rdisk_insert(dev);
|
||||
}
|
||||
|
||||
ui_sb_update_icon_state(SB_ZIP | id, 1);
|
||||
ui_sb_update_icon_state(SB_RDISK | id, 1);
|
||||
#if 0
|
||||
media_menu_update_zip(id);
|
||||
media_menu_update_rdisk(id);
|
||||
#endif
|
||||
ui_sb_update_tip(SB_ZIP | id);
|
||||
ui_sb_update_tip(SB_RDISK | id);
|
||||
config_save();
|
||||
}
|
||||
|
||||
void
|
||||
zip_mount(uint8_t id, char *fn, uint8_t wp)
|
||||
rdisk_mount(uint8_t id, char *fn, uint8_t wp)
|
||||
{
|
||||
zip_t *dev = (zip_t *) zip_drives[id].priv;
|
||||
rdisk_t *dev = (rdisk_t *) rdisk_drives[id].priv;
|
||||
|
||||
zip_disk_close(dev);
|
||||
zip_drives[id].read_only = wp;
|
||||
zip_load(dev, fn, 0);
|
||||
rdisk_disk_close(dev);
|
||||
rdisk_drives[id].read_only = wp;
|
||||
rdisk_load(dev, fn, 0);
|
||||
|
||||
ui_sb_update_icon_state(SB_ZIP | id, strlen(zip_drives[id].image_path) ? 0 : 1);
|
||||
ui_sb_update_icon_state(SB_RDISK | id, strlen(rdisk_drives[id].image_path) ? 0 : 1);
|
||||
#if 0
|
||||
media_menu_update_zip(id);
|
||||
media_menu_update_rdisk(id);
|
||||
#endif
|
||||
ui_sb_update_tip(SB_ZIP | id);
|
||||
ui_sb_update_tip(SB_RDISK | id);
|
||||
|
||||
config_save();
|
||||
}
|
||||
|
||||
void
|
||||
zip_reload(uint8_t id)
|
||||
rdisk_reload(uint8_t id)
|
||||
{
|
||||
zip_t *dev = (zip_t *) zip_drives[id].priv;
|
||||
rdisk_t *dev = (rdisk_t *) rdisk_drives[id].priv;
|
||||
|
||||
zip_disk_reload(dev);
|
||||
if (strlen(zip_drives[id].image_path) == 0) {
|
||||
ui_sb_update_icon_state(SB_ZIP | id, 1);
|
||||
rdisk_disk_reload(dev);
|
||||
if (strlen(rdisk_drives[id].image_path) == 0) {
|
||||
ui_sb_update_icon_state(SB_RDISK | id, 1);
|
||||
} else {
|
||||
ui_sb_update_icon_state(SB_ZIP | id, 0);
|
||||
ui_sb_update_icon_state(SB_RDISK | id, 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
media_menu_update_zip(id);
|
||||
media_menu_update_rdisk(id);
|
||||
#endif
|
||||
ui_sb_update_tip(SB_ZIP | id);
|
||||
ui_sb_update_tip(SB_RDISK | id);
|
||||
|
||||
config_save();
|
||||
}
|
||||
|
||||
@@ -94,6 +94,8 @@ plat_netsocket_accept(SOCKET socket)
|
||||
if (clientsocket == -1)
|
||||
return -1;
|
||||
|
||||
fcntl(clientsocket, F_SETFL, fcntl(clientsocket, F_GETFL, 0) | O_NONBLOCK);
|
||||
|
||||
return clientsocket;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* Jasmine Iwanek <jasmine@iwanek.co.uk>
|
||||
*
|
||||
* Copyright 2021 Andreas J. Reichel.
|
||||
* Copyright 2021-2022 Jasmine Iwanek.
|
||||
* Copyright 2021-2025 Jasmine Iwanek.
|
||||
*/
|
||||
|
||||
#ifndef __APPLE__
|
||||
@@ -310,14 +310,12 @@ plat_serpt_open_device(void *priv)
|
||||
|
||||
switch (dev->mode) {
|
||||
case SERPT_MODE_VCON:
|
||||
if (!open_pseudo_terminal(dev)) {
|
||||
if (!open_pseudo_terminal(dev))
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case SERPT_MODE_HOSTSER:
|
||||
if (!open_host_serial_port(dev)) {
|
||||
if (!open_host_serial_port(dev))
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user