config: Migrate to genconfig system

This commit is contained in:
Matt Borgerson 2022-04-22 01:32:28 -07:00 committed by mborgerson
parent 30fa9e1df1
commit d14cdbc7ba
15 changed files with 330 additions and 731 deletions

68
config_spec.yml Normal file
View File

@ -0,0 +1,68 @@
general:
updates:
check:
type: bool
default: true
misc:
skip_boot_anim: bool
user_token: string
input:
bindings:
port1: string
port2: string
port3: string
port4: string
display:
quality:
surface_scale:
type: integer
default: 1
window:
last_width: integer
last_height: integer
ui:
fit:
type: enum
values: [center, scale, scale_16_9, scale_4_3, stretch]
default: scale
scale:
type: integer
default: 1
audio:
use_dsp: bool
net:
enable: bool
backend:
type: enum
values: [nat, udp, pcap]
default: nat
pcap:
netif: string
udp:
bind_addr:
type: string
default: 0.0.0.0:9368
remote_addr:
type: string
default: 1.2.3.4:9368
sys:
mem_limit:
type: enum
values: ['64', '128']
default: '64'
files:
bootrom_path: string
flashrom_path: string
eeprom_path: string
hdd_path: string
dvd_path: string
perf:
hard_fpu:
type: bool
default: true

@ -1 +1 @@
Subproject commit 218d283f65b96232518c252c792a9ff197aca995
Subproject commit 8220e8748922ddd9bba4cbacd608601586c9a4bb

View File

@ -2624,9 +2624,7 @@ void mcpx_apu_init(PCIBus *bus, int devfn, MemoryRegion *ram)
/* Until DSP is more performant, a switch to decide whether or not we should
* use the full audio pipeline or not.
*/
int use_dsp;
xemu_settings_get_bool(XEMU_SETTINGS_AUDIO_USE_DSP, &use_dsp);
if (use_dsp) {
if (g_config.audio.use_dsp) {
d->mon = MCPX_APU_DEBUG_MON_GP_OR_EP;
d->gp.realtime = true;
d->ep.realtime = true;

View File

@ -3707,9 +3707,7 @@ void nv2a_set_surface_scale_factor(unsigned int scale)
{
NV2AState *d = g_nv2a;
xemu_settings_set_int(XEMU_SETTINGS_DISPLAY_RENDER_SCALE,
scale < 1 ? 1 : scale);
xemu_settings_save();
g_config.display.quality.surface_scale = scale < 1 ? 1 : scale;
qemu_mutex_unlock_iothread();
@ -3750,8 +3748,7 @@ unsigned int nv2a_get_surface_scale_factor(void)
static void pgraph_reload_surface_scale_factor(NV2AState *d)
{
int factor;
xemu_settings_get_int(XEMU_SETTINGS_DISPLAY_RENDER_SCALE, &factor);
int factor = g_config.display.quality.surface_scale;
d->pgraph.surface_scale_factor = factor < 1 ? 1 : factor;
}

View File

@ -837,6 +837,9 @@ if 'CONFIG_OPENGL' in config_host
link_args: config_host['OPENGL_LIBS'].split())
endif
tomlpp = declare_dependency(include_directories: 'tomlplusplus')
genconfig = declare_dependency(include_directories: 'genconfig')
xemu_gtk = declare_dependency(compile_args: config_host['XEMU_GTK_CFLAGS'].split(),
link_args: config_host['XEMU_GTK_LIBS'].split())
@ -2056,8 +2059,20 @@ qemu_version = custom_target('qemu-version.h',
build_by_default: true,
build_always_stale: true)
genconfig_cmd = [
python, files('genconfig/gen_config.py'),
meson.source_root() / 'config_spec.yml', 'xemu-config.h'
]
xemu_config = custom_target('xemu-config.h',
output: 'xemu-config.h',
input: [ files('config_spec.yml') ],
command: genconfig_cmd,
depend_files: files('config_spec.yml'))
genh += qemu_version
genh += xemu_version
genh += xemu_config
hxdep = []
hx_headers = [
@ -2300,6 +2315,9 @@ specific_ss.add(files('xemu-xbe.c', 'xemu-version.c'))
common_ss.add(files('cpus-common.c'))
common_ss.add(tomlpp)
common_ss.add(genconfig)
subdir('softmmu')
common_ss.add(capstone)

View File

@ -1970,9 +1970,7 @@ static void qemu_create_late_backends(void)
net_init_clients(&error_fatal);
#ifdef XBOX
int xemu_net_enabled;
xemu_settings_get_bool(XEMU_SETTINGS_NETWORK_ENABLED, &xemu_net_enabled);
if (xemu_net_enabled) {
if (g_config.net.enable) {
xemu_net_enable();
}
#endif
@ -2801,8 +2799,7 @@ void qemu_init(int argc, char **argv, char **envp)
fake_argv[fake_argc++] = strdup("-machine");
char *bootrom_arg = NULL;
const char *bootrom_path;
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_BOOTROM_PATH, &bootrom_path);
const char *bootrom_path = g_config.sys.files.bootrom_path;
if (strlen(bootrom_path) > 0) {
int bootrom_size = get_image_size(bootrom_path);
@ -2828,12 +2825,9 @@ void qemu_init(int argc, char **argv, char **envp)
}
}
int short_animation;
xemu_settings_get_bool(XEMU_SETTINGS_SYSTEM_SHORTANIM, &short_animation);
fake_argv[fake_argc++] = g_strdup_printf("xbox%s%s%s",
(bootrom_arg != NULL) ? bootrom_arg : "",
short_animation ? ",short-animation=on" : "",
g_config.general.misc.skip_boot_anim ? ",short-animation=on" : "",
",kernel-irqchip=off"
);
@ -2841,8 +2835,7 @@ void qemu_init(int argc, char **argv, char **envp)
g_free(bootrom_arg);
}
const char *eeprom_path;
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_EEPROM_PATH, &eeprom_path);
const char *eeprom_path = g_config.sys.files.eeprom_path;
// Sanity check EEPROM file
if (strlen(eeprom_path) > 0) {
@ -2875,8 +2868,7 @@ void qemu_init(int argc, char **argv, char **envp)
if (strlen(eeprom_path) == 0) {
eeprom_path = xemu_settings_get_default_eeprom_path();
if (xbox_eeprom_generate(eeprom_path, XBOX_EEPROM_VERSION_R1)) {
xemu_settings_set_string(XEMU_SETTINGS_SYSTEM_EEPROM_PATH, eeprom_path);
xemu_settings_save();
xemu_settings_set_string(&g_config.sys.files.eeprom_path, eeprom_path);
fake_argv[fake_argc++] = strdup("-device");
char *escaped_eeprom_path = strdup_double_commas(eeprom_path);
fake_argv[fake_argc++] = g_strdup_printf("smbus-storage,file=%s",
@ -2889,29 +2881,26 @@ void qemu_init(int argc, char **argv, char **envp)
}
}
const char *flash_path;
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_FLASH_PATH, &flash_path);
const char *flashrom_path = g_config.sys.files.flashrom_path;
autostart = 0; // Do not auto-start the machine without a valid BIOS file
if (first_boot) {
// Don't display an error if this is the first boot. Give user a chance
// to configure the path.
} else if (xemu_check_file(flash_path)) {
char *msg = g_strdup_printf("Failed to open flash file '%s'. Please check machine settings.", flash_path);
} else if (xemu_check_file(flashrom_path)) {
char *msg = g_strdup_printf("Failed to open flash file '%s'. Please check machine settings.", flashrom_path);
xemu_queue_error_message(msg);
g_free(msg);
} else {
fake_argv[fake_argc++] = strdup("-bios");
fake_argv[fake_argc++] = strdup(flash_path);
fake_argv[fake_argc++] = strdup(flashrom_path);
autostart = 1;
}
int mem;
xemu_settings_get_int(XEMU_SETTINGS_SYSTEM_MEMORY, &mem);
int mem = ((int)g_config.sys.mem_limit + 1) * 64;
fake_argv[fake_argc++] = strdup("-m");
fake_argv[fake_argc++] = g_strdup_printf("%d", mem);
const char *hdd_path;
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_HDD_PATH, &hdd_path);
const char *hdd_path = g_config.sys.files.hdd_path;
if (strlen(hdd_path) > 0) {
if (xemu_check_file(hdd_path)) {
char *msg = g_strdup_printf("Failed to open hard disk image file '%s'. Please check machine settings.", hdd_path);
@ -2927,9 +2916,7 @@ void qemu_init(int argc, char **argv, char **envp)
}
}
const char *dvd_path = "";
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_DVD_PATH, &dvd_path);
const char *dvd_path = g_config.sys.files.dvd_path;
// Allow overriding the dvd path from command line
for (int i = 1; i < argc; i++) {
if (argv[i] && strcmp(argv[i], "-dvd_path") == 0) {

View File

@ -9046,7 +9046,7 @@ void tcg_x86_init(void)
offsetof(CPUX86State, fpstt), "fpstt");
#if defined(XBOX) && defined(__x86_64__)
xemu_settings_get_bool(XEMU_SETTINGS_SYSTEM_HARD_FPU, &g_use_hard_fpu);
g_use_hard_fpu = g_config.perf.hard_fpu;
#endif
}

View File

@ -47,7 +47,7 @@ xemu_ss.add(files(
'xemu-input.c',
'xemu-monitor.c',
'xemu-net.c',
'xemu-settings.c',
'xemu-settings.cc',
'xemu-shaders.c',
'xemu-hud.cc',
'xemu-reporting.cc',

View File

@ -632,15 +632,10 @@ private:
bool dirty;
bool pending_restart;
char flash_path[MAX_STRING_LEN];
char flashrom_path[MAX_STRING_LEN];
char bootrom_path[MAX_STRING_LEN];
char hdd_path[MAX_STRING_LEN];
char eeprom_path[MAX_STRING_LEN];
int memory_idx;
bool short_animation;
#if defined(_WIN32)
bool check_for_update;
#endif
public:
SettingsWindow()
@ -649,12 +644,10 @@ public:
dirty = false;
pending_restart = false;
flash_path[0] = '\0';
flashrom_path[0] = '\0';
bootrom_path[0] = '\0';
hdd_path[0] = '\0';
eeprom_path[0] = '\0';
memory_idx = 0;
short_animation = false;
}
~SettingsWindow()
@ -663,57 +656,20 @@ public:
void Load()
{
const char *tmp;
int tmp_int;
size_t len;
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_FLASH_PATH, &tmp);
len = strlen(tmp);
assert(len < MAX_STRING_LEN);
strncpy(flash_path, tmp, sizeof(flash_path));
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_BOOTROM_PATH, &tmp);
len = strlen(tmp);
assert(len < MAX_STRING_LEN);
strncpy(bootrom_path, tmp, sizeof(bootrom_path));
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_HDD_PATH, &tmp);
len = strlen(tmp);
assert(len < MAX_STRING_LEN);
strncpy(hdd_path, tmp, sizeof(hdd_path));
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_EEPROM_PATH, &tmp);
len = strlen(tmp);
assert(len < MAX_STRING_LEN);
strncpy(eeprom_path, tmp, sizeof(eeprom_path));
xemu_settings_get_int(XEMU_SETTINGS_SYSTEM_MEMORY, &tmp_int);
memory_idx = (tmp_int-64)/64;
xemu_settings_get_bool(XEMU_SETTINGS_SYSTEM_SHORTANIM, &tmp_int);
short_animation = !!tmp_int;
#if defined(_WIN32)
xemu_settings_get_bool(XEMU_SETTINGS_MISC_CHECK_FOR_UPDATE, &tmp_int);
check_for_update = !!tmp_int;
#endif
strncpy(flashrom_path, g_config.sys.files.flashrom_path, sizeof(flashrom_path)-1);
strncpy(bootrom_path, g_config.sys.files.bootrom_path, sizeof(bootrom_path)-1);
strncpy(hdd_path, g_config.sys.files.hdd_path, sizeof(hdd_path)-1);
strncpy(eeprom_path, g_config.sys.files.eeprom_path, sizeof(eeprom_path)-1);
dirty = false;
}
void Save()
{
xemu_settings_set_string(XEMU_SETTINGS_SYSTEM_FLASH_PATH, flash_path);
xemu_settings_set_string(XEMU_SETTINGS_SYSTEM_BOOTROM_PATH, bootrom_path);
xemu_settings_set_string(XEMU_SETTINGS_SYSTEM_HDD_PATH, hdd_path);
xemu_settings_set_string(XEMU_SETTINGS_SYSTEM_EEPROM_PATH, eeprom_path);
xemu_settings_set_int(XEMU_SETTINGS_SYSTEM_MEMORY, 64+memory_idx*64);
xemu_settings_set_bool(XEMU_SETTINGS_SYSTEM_SHORTANIM, short_animation);
#if defined(_WIN32)
xemu_settings_set_bool(XEMU_SETTINGS_MISC_CHECK_FOR_UPDATE, check_for_update);
#endif
xemu_settings_save();
xemu_queue_notification("Settings saved! Restart to apply updates.");
xemu_settings_set_string(&g_config.sys.files.flashrom_path, flashrom_path);
xemu_settings_set_string(&g_config.sys.files.bootrom_path, bootrom_path);
xemu_settings_set_string(&g_config.sys.files.hdd_path, hdd_path);
xemu_settings_set_string(&g_config.sys.files.eeprom_path, eeprom_path);
xemu_queue_notification("Settings saved. Restart to apply updates.");
pending_restart = true;
}
@ -759,7 +715,7 @@ public:
ImGui::NextColumn();
float picker_width = ImGui::GetColumnWidth()-120*g_ui_scale;
ImGui::SetNextItemWidth(picker_width);
FilePicker("###Flash", flash_path, sizeof(flash_path), rom_file_filters);
FilePicker("###Flash", flashrom_path, sizeof(flashrom_path), rom_file_filters);
ImGui::NextColumn();
ImGui::Text("MCPX Boot ROM File");
@ -783,24 +739,18 @@ public:
ImGui::Text("System Memory");
ImGui::NextColumn();
ImGui::SetNextItemWidth(ImGui::GetColumnWidth()*0.5);
if (ImGui::Combo("###mem", &memory_idx, "64 MiB\0" "128 MiB\0")) {
dirty = true;
}
ImGui::Combo("###mem", &g_config.sys.mem_limit, "64 MiB\0" "128 MiB\0");
ImGui::NextColumn();
ImGui::Dummy(ImVec2(0,0));
ImGui::NextColumn();
if (ImGui::Checkbox("Skip startup animation", &short_animation)) {
dirty = true;
}
ImGui::Checkbox("Skip startup animation", &g_config.general.misc.skip_boot_anim);
ImGui::NextColumn();
#if defined(_WIN32)
ImGui::Dummy(ImVec2(0,0));
ImGui::NextColumn();
if (ImGui::Checkbox("Check for updates on startup", &check_for_update)) {
dirty = true;
}
ImGui::Checkbox("Check for updates on startup", &g_config.general.updates.check);
ImGui::NextColumn();
#endif
@ -943,14 +893,11 @@ class NetworkInterfaceManager
public:
std::vector<std::unique_ptr<NetworkInterface>> ifaces;
NetworkInterface *current_iface;
const char *current_iface_name;
bool failed_to_load_lib;
NetworkInterfaceManager()
{
current_iface = NULL;
xemu_settings_get_string(XEMU_SETTINGS_NETWORK_PCAP_INTERFACE,
&current_iface_name);
failed_to_load_lib = false;
}
@ -987,7 +934,7 @@ public:
#else
ifaces.emplace_back(new NetworkInterface(iter));
#endif
if (!strcmp(current_iface_name, iter->name)) {
if (!strcmp(g_config.net.pcap.netif, iter->name)) {
current_iface = ifaces.back().get();
}
}
@ -998,10 +945,8 @@ public:
void select(NetworkInterface &iface)
{
current_iface = &iface;
xemu_settings_set_string(XEMU_SETTINGS_NETWORK_PCAP_INTERFACE,
xemu_settings_set_string(&g_config.net.pcap.netif,
iface.pcap_name.c_str());
xemu_settings_get_string(XEMU_SETTINGS_NETWORK_PCAP_INTERFACE,
&current_iface_name);
}
bool is_current(NetworkInterface &iface)
@ -1015,7 +960,6 @@ class NetworkWindow
{
public:
bool is_open;
int backend;
char remote_addr[64];
char local_addr[64];
std::unique_ptr<NetworkInterfaceManager> iface_mgr;
@ -1040,12 +984,8 @@ public:
}
if (ImGui::IsWindowAppearing()) {
const char *tmp;
xemu_settings_get_string(XEMU_SETTINGS_NETWORK_REMOTE_ADDR, &tmp);
strncpy(remote_addr, tmp, sizeof(remote_addr)-1);
xemu_settings_get_string(XEMU_SETTINGS_NETWORK_LOCAL_ADDR, &tmp);
strncpy(local_addr, tmp, sizeof(local_addr)-1);
xemu_settings_get_enum(XEMU_SETTINGS_NETWORK_BACKEND, &backend);
strncpy(remote_addr, g_config.net.udp.remote_addr, sizeof(remote_addr)-1);
strncpy(local_addr, g_config.net.udp.bind_addr, sizeof(local_addr)-1);
}
ImGuiInputTextFlags flg = 0;
@ -1061,23 +1001,20 @@ public:
ImGui::SameLine(); HelpMarker("The network backend which the emulated NIC interacts with");
ImGui::NextColumn();
if (is_enabled) ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.6f);
int temp_backend = backend; // Temporary to make backend combo read-only (FIXME: surely there's a nicer way)
if (ImGui::Combo("##backend", is_enabled ? &temp_backend : &backend, "NAT\0UDP Tunnel\0Bridged Adapter\0") && !is_enabled) {
xemu_settings_set_enum(XEMU_SETTINGS_NETWORK_BACKEND, backend);
xemu_settings_save();
}
int temp_backend = g_config.net.backend; // Temporary to make backend combo read-only (FIXME: surely there's a nicer way)
ImGui::Combo("##backend", is_enabled ? &temp_backend : &g_config.net.backend, "NAT\0UDP Tunnel\0Bridged Adapter\0");
if (is_enabled) ImGui::PopStyleVar();
ImGui::SameLine();
if (backend == XEMU_NET_BACKEND_USER) {
if (g_config.net.backend == CONFIG_NET_BACKEND_NAT) {
HelpMarker("User-mode TCP/IP stack with network address translation");
} else if (backend == XEMU_NET_BACKEND_SOCKET_UDP) {
} else if (g_config.net.backend == CONFIG_NET_BACKEND_UDP) {
HelpMarker("Tunnels link-layer traffic to a remote host via UDP");
} else if (backend == XEMU_NET_BACKEND_PCAP) {
} else if (g_config.net.backend == CONFIG_NET_BACKEND_PCAP) {
HelpMarker("Bridges with a host network interface");
}
ImGui::NextColumn();
if (backend == XEMU_NET_BACKEND_SOCKET_UDP) {
if (g_config.net.backend == CONFIG_NET_BACKEND_UDP) {
ImGui::Text("Remote Host");
ImGui::SameLine(); HelpMarker("The remote <IP address>:<Port> to forward packets to (e.g. 1.2.3.4:9368)");
ImGui::NextColumn();
@ -1096,7 +1033,7 @@ public:
ImGui::InputText("###local_host", local_addr, sizeof(local_addr), flg);
if (is_enabled) ImGui::PopStyleVar();
ImGui::NextColumn();
} else if (backend == XEMU_NET_BACKEND_PCAP) {
} else if (g_config.net.backend == CONFIG_NET_BACKEND_PCAP) {
static bool should_refresh = true;
if (iface_mgr.get() == nullptr) {
iface_mgr.reset(new NetworkInterfaceManager());
@ -1128,7 +1065,7 @@ public:
const char *selected_display_name = (
iface_mgr->current_iface
? iface_mgr->current_iface->friendlyname.c_str()
: iface_mgr->current_iface_name
: g_config.net.pcap.netif
);
if (is_enabled) ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.6f);
if (ImGui::BeginCombo("###network_iface", selected_display_name)) {
@ -1169,14 +1106,12 @@ public:
ImGui::SetItemDefaultFocus();
if (ImGui::Button(is_enabled ? "Disable" : "Enable", ImVec2(120*g_ui_scale, 0))) {
if (!is_enabled) {
xemu_settings_set_string(XEMU_SETTINGS_NETWORK_REMOTE_ADDR, remote_addr);
xemu_settings_set_string(XEMU_SETTINGS_NETWORK_LOCAL_ADDR, local_addr);
xemu_settings_set_string(&g_config.net.udp.remote_addr, remote_addr);
xemu_settings_set_string(&g_config.net.udp.bind_addr, local_addr);
xemu_net_enable();
} else {
xemu_net_disable();
}
xemu_settings_set_bool(XEMU_SETTINGS_NETWORK_ENABLED, xemu_net_is_enabled());
xemu_settings_save();
}
ImGui::End();
@ -1290,10 +1225,7 @@ public:
description[0] = '\x00';
report.compat_comments = description;
const char *tmp;
xemu_settings_get_string(XEMU_SETTINGS_MISC_USER_TOKEN, &tmp);
assert(strlen(tmp) < sizeof(token_buf));
strncpy(token_buf, tmp, sizeof(token_buf));
strncpy(token_buf, g_config.general.user_token, sizeof(token_buf)-1);
report.token = token_buf;
dirty = true;
@ -1411,12 +1343,8 @@ public:
did_send = true;
send_result = report.Send();
if (send_result) {
// Close window on success
is_open = false;
// Save user token if it was used
xemu_settings_set_string(XEMU_SETTINGS_MISC_USER_TOKEN, token_buf);
xemu_settings_save();
xemu_settings_set_string(&g_config.general.user_token, token_buf);
}
}
@ -1772,37 +1700,6 @@ public:
{
}
void save_auto_update_selection(bool preference)
{
xemu_settings_set_bool(XEMU_SETTINGS_MISC_CHECK_FOR_UPDATE, preference);
xemu_settings_save();
should_prompt_auto_update_selection = false;
}
void prompt_auto_update_selection()
{
ImGui::Text("Would you like xemu to check for updates on startup?");
ImGui::SetNextItemWidth(-1.0f);
ImGui::Dummy(ImVec2(0.0f, ImGui::GetStyle().WindowPadding.y));
ImGui::Separator();
ImGui::Dummy(ImVec2(0.0f, ImGui::GetStyle().WindowPadding.y));
float w = (130)*g_ui_scale;
float bw = w + (10)*g_ui_scale;
ImGui::SetCursorPosX(ImGui::GetWindowWidth()-2*bw);
if (ImGui::Button("No", ImVec2(w, 0))) {
save_auto_update_selection(false);
is_open = false;
}
ImGui::SameLine();
if (ImGui::Button("Yes", ImVec2(w, 0))) {
save_auto_update_selection(true);
check_for_updates_and_prompt_if_available();
}
}
void check_for_updates_and_prompt_if_available()
{
updater.check_for_update([this](){
@ -1819,12 +1716,6 @@ public:
return;
}
if (should_prompt_auto_update_selection) {
prompt_auto_update_selection();
ImGui::End();
return;
}
if (ImGui::IsWindowAppearing() && !updater.is_update_available()) {
updater.check_for_update();
}
@ -1993,23 +1884,19 @@ static bool is_shortcut_key_pressed(int scancode)
static void action_eject_disc(void)
{
xemu_settings_set_string(XEMU_SETTINGS_SYSTEM_DVD_PATH, "");
xemu_settings_save();
xemu_settings_set_string(&g_config.sys.files.dvd_path, "");
xemu_eject_disc();
}
static void action_load_disc(void)
{
const char *iso_file_filters = ".iso Files\0*.iso\0All Files\0*.*\0";
const char *current_disc_path;
xemu_settings_get_string(XEMU_SETTINGS_SYSTEM_DVD_PATH, &current_disc_path);
const char *new_disc_path = paused_file_open(NOC_FILE_DIALOG_OPEN, iso_file_filters, current_disc_path, NULL);
const char *new_disc_path = paused_file_open(NOC_FILE_DIALOG_OPEN, iso_file_filters, g_config.sys.files.dvd_path, NULL);
if (new_disc_path == NULL) {
/* Cancelled */
return;
}
xemu_settings_set_string(XEMU_SETTINGS_SYSTEM_DVD_PATH, new_disc_path);
xemu_settings_save();
xemu_settings_set_string(&g_config.sys.files.dvd_path, new_disc_path);
xemu_load_disc(new_disc_path);
}
@ -2120,8 +2007,7 @@ static void ShowMainMenu()
if (ui_scale_combo > 1) ui_scale_combo = 1;
if (ImGui::Combo("UI Scale", &ui_scale_combo, "1x\0" "2x\0")) {
g_ui_scale = ui_scale_combo + 1;
xemu_settings_set_int(XEMU_SETTINGS_DISPLAY_UI_SCALE, g_ui_scale);
xemu_settings_save();
g_config.display.ui.scale = g_ui_scale;
g_trigger_style_update = true;
}
@ -2131,9 +2017,7 @@ static void ShowMainMenu()
}
if (ImGui::Combo(
"Scaling Mode", &scaling_mode, "Center\0Scale\0Scale (Widescreen 16:9)\0Scale (4:3)\0Stretch\0")) {
xemu_settings_set_enum(XEMU_SETTINGS_DISPLAY_SCALE, scaling_mode);
xemu_settings_save();
"Scaling Mode", &g_config.display.ui.fit, "Center\0Scale\0Scale (Widescreen 16:9)\0Scale (4:3)\0Stretch\0")) {
}
ImGui::SameLine(); HelpMarker("Controls how the rendered content should be scaled into the window");
if (ImGui::MenuItem("Fullscreen", SHORTCUT_MENU_TEXT(Alt+F), xemu_is_fullscreen(), true)) {
@ -2289,8 +2173,7 @@ void xemu_hud_init(SDL_Window* window, void* sdl_gl_context)
first_boot_window.is_open = xemu_settings_did_fail_to_load();
int ui_scale_int = 1;
xemu_settings_get_int(XEMU_SETTINGS_DISPLAY_UI_SCALE, &ui_scale_int);
int ui_scale_int = g_config.display.ui.scale;
if (ui_scale_int < 1) ui_scale_int = 1;
g_ui_scale = ui_scale_int;
@ -2299,13 +2182,7 @@ void xemu_hud_init(SDL_Window* window, void* sdl_gl_context)
ImPlot::CreateContext();
#if defined(_WIN32)
int should_check_for_update;
xemu_settings_get_bool(XEMU_SETTINGS_MISC_CHECK_FOR_UPDATE, &should_check_for_update);
if (should_check_for_update == -1) {
update_window.should_prompt_auto_update_selection =
update_window.is_open = !xemu_settings_did_fail_to_load();
} else if (should_check_for_update) {
if (g_config.general.updates.check) {
update_window.check_for_updates_and_prompt_if_available();
}
#endif

View File

@ -87,11 +87,11 @@ ControllerStateList available_controllers =
ControllerState *bound_controllers[4] = { NULL, NULL, NULL, NULL };
int test_mode;
static const enum xemu_settings_keys port_index_to_settings_key_map[] = {
XEMU_SETTINGS_INPUT_CONTROLLER_1_GUID,
XEMU_SETTINGS_INPUT_CONTROLLER_2_GUID,
XEMU_SETTINGS_INPUT_CONTROLLER_3_GUID,
XEMU_SETTINGS_INPUT_CONTROLLER_4_GUID,
static const char **port_index_to_settings_key_map[] = {
&g_config.input.bindings.port1,
&g_config.input.bindings.port2,
&g_config.input.bindings.port3,
&g_config.input.bindings.port4,
};
void xemu_input_init(void)
@ -141,9 +141,7 @@ int xemu_input_get_controller_default_bind_port(ControllerState *state, int star
}
for (int i = start; i < 4; i++) {
const char *this_port;
xemu_settings_get_string(port_index_to_settings_key_map[i], &this_port);
if (strcmp(guid, this_port) == 0) {
if (strcmp(guid, *port_index_to_settings_key_map[i]) == 0) {
return i;
}
}
@ -434,7 +432,6 @@ void xemu_input_bind(int index, ControllerState *state, int save)
}
}
xemu_settings_set_string(port_index_to_settings_key_map[index], guid_buf);
xemu_settings_save();
}
// Bind new controller

View File

@ -50,36 +50,28 @@ void xemu_net_enable(void)
return;
}
int backend;
const char *local_addr, *remote_addr;
xemu_settings_get_enum(XEMU_SETTINGS_NETWORK_BACKEND, &backend);
xemu_settings_get_string(XEMU_SETTINGS_NETWORK_REMOTE_ADDR, &remote_addr);
xemu_settings_get_string(XEMU_SETTINGS_NETWORK_LOCAL_ADDR, &local_addr);
// Create the netdev
QDict *qdict;
if (backend == XEMU_NET_BACKEND_USER) {
if (g_config.net.backend == CONFIG_NET_BACKEND_NAT) {
qdict = qdict_new();
qdict_put_str(qdict, "id", id);
qdict_put_str(qdict, "type", "user");
} else if (backend == XEMU_NET_BACKEND_SOCKET_UDP) {
} else if (g_config.net.backend == CONFIG_NET_BACKEND_UDP) {
qdict = qdict_new();
qdict_put_str(qdict, "id", id);
qdict_put_str(qdict, "type", "socket");
qdict_put_str(qdict, "udp", remote_addr);
qdict_put_str(qdict, "localaddr", local_addr);
} else if (backend == XEMU_NET_BACKEND_PCAP) {
qdict_put_str(qdict, "udp", g_config.net.udp.remote_addr);
qdict_put_str(qdict, "localaddr", g_config.net.udp.bind_addr);
} else if (g_config.net.backend == CONFIG_NET_BACKEND_PCAP) {
#if defined(_WIN32)
if (pcap_load_library()) {
return;
}
#endif
const char *iface;
xemu_settings_get_string(XEMU_SETTINGS_NETWORK_PCAP_INTERFACE, &iface);
qdict = qdict_new();
qdict_put_str(qdict, "id", id);
qdict_put_str(qdict, "type", "pcap");
qdict_put_str(qdict, "ifname", iface);
qdict_put_str(qdict, "ifname", g_config.net.pcap.netif);
} else {
// Unsupported backend type
return;
@ -111,6 +103,8 @@ void xemu_net_enable(void)
xemu_queue_error_message(error_get_pretty(local_err));
error_report_err(local_err);
}
g_config.net.enable = true;
}
static void remove_netdev(const char *name)
@ -139,11 +133,13 @@ void xemu_net_disable(void)
{
remove_netdev(id);
remove_netdev(id_hubport);
g_config.net.enable = false;
}
int xemu_net_is_enabled(void)
{
NetClientState *nc;
nc = qemu_find_netdev(id);
return (nc != NULL);
g_config.net.enable = (nc != NULL);
return g_config.net.enable;
}

View File

@ -1,441 +0,0 @@
/*
* xemu Settings Management
*
* Copyright (C) 2020-2021 Matt Borgerson
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include <stdlib.h>
#include <SDL_filesystem.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include <assert.h>
#include <glib.h>
#include "xemu-settings.h"
#include "inih/ini.c" // FIXME
enum config_types {
CONFIG_TYPE_STRING,
CONFIG_TYPE_INT,
CONFIG_TYPE_BOOL,
CONFIG_TYPE_ENUM,
CONFIG_TYPE__MAX
};
struct xemu_settings {
// [system]
char *flash_path;
char *bootrom_path;
char *hdd_path;
char *dvd_path;
char *eeprom_path;
int memory;
int short_animation; // Boolean
int hard_fpu; // Boolean
// [audio]
int use_dsp; // Boolean
// [display]
int scale;
int ui_scale;
int render_scale;
int window_width;
int window_height;
// [input]
char *controller_1_guid;
char *controller_2_guid;
char *controller_3_guid;
char *controller_4_guid;
// [network]
int net_enabled; // Boolean
int net_backend;
char *net_local_addr;
char *net_remote_addr;
char *net_pcap_iface;
// [misc]
char *user_token;
int check_for_update; // Boolean
};
struct enum_str_map {
int value;
const char *str;
};
static const struct enum_str_map display_scale_map[DISPLAY_SCALE__COUNT+1] = {
{ DISPLAY_SCALE_CENTER, "center" },
{ DISPLAY_SCALE_SCALE, "scale" },
{ DISPLAY_SCALE_WS169, "scale_ws169" },
{ DISPLAY_SCALE_FS43, "scale_fs43" },
{ DISPLAY_SCALE_STRETCH, "stretch" },
{ 0, NULL },
};
static const struct enum_str_map net_backend_map[XEMU_NET_BACKEND__COUNT+1] = {
{ XEMU_NET_BACKEND_USER, "user" },
{ XEMU_NET_BACKEND_SOCKET_UDP, "udp" },
{ XEMU_NET_BACKEND_PCAP, "pcap" },
{ 0, NULL },
};
struct config_offset_table {
enum config_types type;
const char *section;
const char *name;
ptrdiff_t offset;
union {
const char *default_str;
int default_int;
int default_bool;
};
const struct enum_str_map *enum_map;
} config_items[XEMU_SETTINGS__COUNT] = {
// Please keep organized by section
[XEMU_SETTINGS_SYSTEM_FLASH_PATH] = { CONFIG_TYPE_STRING, "system", "flash_path", offsetof(struct xemu_settings, flash_path), { .default_str = "" } },
[XEMU_SETTINGS_SYSTEM_BOOTROM_PATH] = { CONFIG_TYPE_STRING, "system", "bootrom_path", offsetof(struct xemu_settings, bootrom_path), { .default_str = "" } },
[XEMU_SETTINGS_SYSTEM_HDD_PATH] = { CONFIG_TYPE_STRING, "system", "hdd_path", offsetof(struct xemu_settings, hdd_path), { .default_str = "" } },
[XEMU_SETTINGS_SYSTEM_DVD_PATH] = { CONFIG_TYPE_STRING, "system", "dvd_path", offsetof(struct xemu_settings, dvd_path), { .default_str = "" } },
[XEMU_SETTINGS_SYSTEM_EEPROM_PATH] = { CONFIG_TYPE_STRING, "system", "eeprom_path", offsetof(struct xemu_settings, eeprom_path), { .default_str = "" } },
[XEMU_SETTINGS_SYSTEM_MEMORY] = { CONFIG_TYPE_INT, "system", "memory", offsetof(struct xemu_settings, memory), { .default_int = 64 } },
[XEMU_SETTINGS_SYSTEM_SHORTANIM] = { CONFIG_TYPE_BOOL, "system", "shortanim", offsetof(struct xemu_settings, short_animation), { .default_bool = 0 } },
[XEMU_SETTINGS_SYSTEM_HARD_FPU] = { CONFIG_TYPE_BOOL, "system", "hard_fpu", offsetof(struct xemu_settings, hard_fpu), { .default_bool = 1 } },
[XEMU_SETTINGS_AUDIO_USE_DSP] = { CONFIG_TYPE_BOOL, "audio", "use_dsp", offsetof(struct xemu_settings, use_dsp), { .default_bool = 0 } },
[XEMU_SETTINGS_DISPLAY_SCALE] = { CONFIG_TYPE_ENUM, "display", "scale", offsetof(struct xemu_settings, scale), { .default_int = DISPLAY_SCALE_SCALE }, display_scale_map },
[XEMU_SETTINGS_DISPLAY_UI_SCALE] = { CONFIG_TYPE_INT, "display", "ui_scale", offsetof(struct xemu_settings, ui_scale), { .default_int = 1 } },
[XEMU_SETTINGS_DISPLAY_RENDER_SCALE] = { CONFIG_TYPE_INT, "display", "render_scale", offsetof(struct xemu_settings, render_scale), { .default_int = 1 } },
[XEMU_SETTINGS_DISPLAY_WINDOW_WIDTH] = { CONFIG_TYPE_INT, "display", "window_width", offsetof(struct xemu_settings, window_width), { .default_int = 1280 } },
[XEMU_SETTINGS_DISPLAY_WINDOW_HEIGHT] = { CONFIG_TYPE_INT, "display", "window_height", offsetof(struct xemu_settings, window_height), { .default_int = 960 } },
[XEMU_SETTINGS_INPUT_CONTROLLER_1_GUID] = { CONFIG_TYPE_STRING, "input", "controller_1_guid", offsetof(struct xemu_settings, controller_1_guid), { .default_str = "" } },
[XEMU_SETTINGS_INPUT_CONTROLLER_2_GUID] = { CONFIG_TYPE_STRING, "input", "controller_2_guid", offsetof(struct xemu_settings, controller_2_guid), { .default_str = "" } },
[XEMU_SETTINGS_INPUT_CONTROLLER_3_GUID] = { CONFIG_TYPE_STRING, "input", "controller_3_guid", offsetof(struct xemu_settings, controller_3_guid), { .default_str = "" } },
[XEMU_SETTINGS_INPUT_CONTROLLER_4_GUID] = { CONFIG_TYPE_STRING, "input", "controller_4_guid", offsetof(struct xemu_settings, controller_4_guid), { .default_str = "" } },
[XEMU_SETTINGS_NETWORK_ENABLED] = { CONFIG_TYPE_BOOL, "network", "enabled", offsetof(struct xemu_settings, net_enabled), { .default_bool = 0 } },
[XEMU_SETTINGS_NETWORK_BACKEND] = { CONFIG_TYPE_ENUM, "network", "backend", offsetof(struct xemu_settings, net_backend), { .default_int = XEMU_NET_BACKEND_USER }, net_backend_map },
[XEMU_SETTINGS_NETWORK_LOCAL_ADDR] = { CONFIG_TYPE_STRING, "network", "local_addr", offsetof(struct xemu_settings, net_local_addr), { .default_str = "0.0.0.0:9368" } },
[XEMU_SETTINGS_NETWORK_REMOTE_ADDR] = { CONFIG_TYPE_STRING, "network", "remote_addr", offsetof(struct xemu_settings, net_remote_addr), { .default_str = "1.2.3.4:9368" } },
[XEMU_SETTINGS_NETWORK_PCAP_INTERFACE] = { CONFIG_TYPE_STRING, "network", "pcap_iface", offsetof(struct xemu_settings, net_pcap_iface), { .default_str = "" } },
[XEMU_SETTINGS_MISC_USER_TOKEN] = { CONFIG_TYPE_STRING, "misc", "user_token", offsetof(struct xemu_settings, user_token), { .default_str = "" } },
[XEMU_SETTINGS_MISC_CHECK_FOR_UPDATE] = { CONFIG_TYPE_BOOL, "misc", "check_for_update", offsetof(struct xemu_settings, check_for_update), { .default_bool = -1 } },
};
static const char *settings_path;
static const char *filename = "xemu.ini";
static struct xemu_settings *g_settings;
static int settings_failed_to_load = 0;
static void *xemu_settings_get_field(enum xemu_settings_keys key, enum config_types type)
{
assert(key < XEMU_SETTINGS__COUNT);
assert(config_items[key].type == type);
return (void *)((char*)g_settings + config_items[key].offset);
}
int xemu_settings_set_string(enum xemu_settings_keys key, const char *str)
{
char **field_str = (char **)xemu_settings_get_field(key, CONFIG_TYPE_STRING);
if (*field_str) {
free(*field_str);
}
*field_str = strdup(str);
return 0;
}
int xemu_settings_get_string(enum xemu_settings_keys key, const char **str)
{
*str = *(const char **)xemu_settings_get_field(key, CONFIG_TYPE_STRING);
return 0;
}
int xemu_settings_set_int(enum xemu_settings_keys key, int val)
{
int *field_int = (int *)xemu_settings_get_field(key, CONFIG_TYPE_INT);
*field_int = val;
return 0;
}
int xemu_settings_get_int(enum xemu_settings_keys key, int *val)
{
*val = *(int *)xemu_settings_get_field(key, CONFIG_TYPE_INT);
return 0;
}
int xemu_settings_set_bool(enum xemu_settings_keys key, int val)
{
int *field_int = (int *)xemu_settings_get_field(key, CONFIG_TYPE_BOOL);
*field_int = val;
return 0;
}
int xemu_settings_get_bool(enum xemu_settings_keys key, int *val)
{
*val = *(int *)xemu_settings_get_field(key, CONFIG_TYPE_BOOL);
return 0;
}
int xemu_settings_set_enum(enum xemu_settings_keys key, int val)
{
int *field_int = (int *)xemu_settings_get_field(key, CONFIG_TYPE_ENUM);
*field_int = val;
return 0;
}
int xemu_settings_get_enum(enum xemu_settings_keys key, int *val)
{
*val = *(int *)xemu_settings_get_field(key, CONFIG_TYPE_ENUM);
return 0;
}
static bool xemu_settings_detect_portable_mode(void)
{
bool val = false;
char *portable_path = g_strdup_printf("%s%s", SDL_GetBasePath(), filename);
FILE *tmpfile;
if ((tmpfile = qemu_fopen(portable_path, "r"))) {
fclose(tmpfile);
val = true;
}
free(portable_path);
return val;
}
void xemu_settings_set_path(const char *path)
{
assert(path != NULL);
assert(settings_path == NULL);
settings_path = path;
fprintf(stderr, "%s: config path: %s\n", __func__, settings_path);
}
const char *xemu_settings_get_path(void)
{
if (settings_path != NULL) {
return settings_path;
}
char *base = xemu_settings_detect_portable_mode()
? SDL_GetBasePath()
: SDL_GetPrefPath("xemu", "xemu");
assert(base != NULL);
settings_path = g_strdup_printf("%s%s", base, filename);
SDL_free(base);
fprintf(stderr, "%s: config path: %s\n", __func__, settings_path);
return settings_path;
}
const char *xemu_settings_get_default_eeprom_path(void)
{
static char *eeprom_path = NULL;
if (eeprom_path != NULL) {
return eeprom_path;
}
char *base = xemu_settings_detect_portable_mode()
? SDL_GetBasePath()
: SDL_GetPrefPath("xemu", "xemu");
assert(base != NULL);
eeprom_path = g_strdup_printf("%s%s", base, "eeprom.bin");
SDL_free(base);
return eeprom_path;
}
static int xemu_enum_str_to_int(const struct enum_str_map *map, const char *str, int *value)
{
for (int i = 0; map[i].str != NULL; i++) {
if (strcmp(map[i].str, str) == 0) {
*value = map[i].value;
return 0;
}
}
return -1;
}
static int xemu_enum_int_to_str(const struct enum_str_map *map, int value, const char **str)
{
for (int i = 0; map[i].str != NULL; i++) {
if (map[i].value == value) {
*str = map[i].str;
return 0;
}
}
return -1;
}
static enum xemu_settings_keys xemu_key_from_name(const char *section, const char *name)
{
for (int i = 0; i < XEMU_SETTINGS__COUNT; i++) {
if ((strcmp(section, config_items[i].section) == 0) &&
(strcmp(name, config_items[i].name) == 0)) {
return i; // Found
}
}
return XEMU_SETTINGS_INVALID;
}
static int config_parse_callback(void *user, const char *section, const char *name, const char *value)
{
// struct xemu_settings *settings = (struct xemu_settings *)user;
fprintf(stderr, "%s: [%s] %s = %s\n", __func__, section, name, value);
enum xemu_settings_keys key = xemu_key_from_name(section, name);
if (key == XEMU_SETTINGS_INVALID) {
fprintf(stderr, "Ignoring unknown key %s.%s\n", section, name);
return 1;
}
if (config_items[key].type == CONFIG_TYPE_STRING) {
xemu_settings_set_string(key, value);
} else if (config_items[key].type == CONFIG_TYPE_INT) {
int int_val;
int converted = sscanf(value, "%d", &int_val);
if (converted != 1) {
fprintf(stderr, "Error parsing %s.%s as integer. Got '%s'\n", section, name, value);
return 0;
}
xemu_settings_set_int(key, int_val);
} else if (config_items[key].type == CONFIG_TYPE_BOOL) {
int int_val;
if (strcmp(value, "true") == 0) {
int_val = 1;
} else if (strcmp(value, "false") == 0) {
int_val = 0;
} else if (strcmp(value, "") == 0) {
return 1;
} else {
fprintf(stderr, "Error parsing %s.%s as boolean. Got '%s'\n", section, name, value);
return 0;
}
xemu_settings_set_bool(key, int_val);
} else if (config_items[key].type == CONFIG_TYPE_ENUM) {
int int_val;
int status = xemu_enum_str_to_int(config_items[key].enum_map, value, &int_val);
if (status != 0) {
fprintf(stderr, "Error parsing %s.%s as enum. Got '%s'\n", section, name, value);
return 0;
}
xemu_settings_set_enum(key, int_val);
} else {
// Unimplemented
assert(0);
}
// Success
return 1;
}
static void xemu_settings_init_default(struct xemu_settings *settings)
{
memset(settings, 0, sizeof(struct xemu_settings));
for (int i = 0; i < XEMU_SETTINGS__COUNT; i++) {
if (config_items[i].type == CONFIG_TYPE_STRING) {
xemu_settings_set_string(i, config_items[i].default_str);
} else if (config_items[i].type == CONFIG_TYPE_INT) {
xemu_settings_set_int(i, config_items[i].default_int);
} else if (config_items[i].type == CONFIG_TYPE_BOOL) {
xemu_settings_set_bool(i, config_items[i].default_bool);
} else if (config_items[i].type == CONFIG_TYPE_ENUM) {
xemu_settings_set_enum(i, config_items[i].default_int);
} else {
// Unimplemented
assert(0);
}
}
}
int xemu_settings_did_fail_to_load(void)
{
return settings_failed_to_load;
}
void xemu_settings_load(void)
{
// Should only call this once, at startup
assert(g_settings == NULL);
g_settings = malloc(sizeof(struct xemu_settings));
assert(g_settings != NULL);
memset(g_settings, 0, sizeof(struct xemu_settings));
xemu_settings_init_default(g_settings);
// Parse configuration file
int status = ini_parse(xemu_settings_get_path(),
config_parse_callback,
g_settings);
if (status < 0) {
// fprintf(stderr, "Failed to load config! Using defaults\n");
settings_failed_to_load = 1;
}
}
void xemu_settings_save(void)
{
FILE *fd = qemu_fopen(xemu_settings_get_path(), "wb");
assert(fd != NULL);
const char *last_section = "";
for (int i = 0; i < XEMU_SETTINGS__COUNT; i++) {
if (strcmp(last_section, config_items[i].section)) {
fprintf(fd, "[%s]\n", config_items[i].section);
last_section = config_items[i].section;
}
fprintf(fd, "%s = ", config_items[i].name);
if (config_items[i].type == CONFIG_TYPE_STRING) {
const char *v;
xemu_settings_get_string(i, &v);
fprintf(fd, "%s\n", v);
} else if (config_items[i].type == CONFIG_TYPE_INT) {
int v;
xemu_settings_get_int(i, &v);
fprintf(fd, "%d\n", v);
} else if (config_items[i].type == CONFIG_TYPE_BOOL) {
int v;
xemu_settings_get_bool(i, &v);
if (v == 0 || v == 1) {
fprintf(fd, "%s\n", !!(v) ? "true" : "false");
} else {
// Other values are considered unset
}
} else if (config_items[i].type == CONFIG_TYPE_ENUM) {
int v;
xemu_settings_get_enum(i, &v);
const char *str = "";
xemu_enum_int_to_str(config_items[i].enum_map, v, &str);
fprintf(fd, "%s\n", str);
} else {
// Unimplemented
assert(0);
}
}
fclose(fd);
}

152
ui/xemu-settings.cc Normal file
View File

@ -0,0 +1,152 @@
/*
* xemu Settings Management
*
* Copyright (C) 2020-2021 Matt Borgerson
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include <stdlib.h>
#include <SDL_filesystem.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include <assert.h>
#include <stdio.h>
#include <iostream>
#include <toml.hpp>
#include <cnode.h>
#include "xemu-settings.h"
#define DEFINE_CONFIG_TREE
#include "xemu-config.h"
struct config g_config;
static bool settings_failed_to_load = true;
static const char *filename = "xemu.ini";
static const char *settings_path;
static bool xemu_settings_detect_portable_mode(void)
{
bool val = false;
char *portable_path = g_strdup_printf("%s%s", SDL_GetBasePath(), filename);
FILE *tmpfile;
if ((tmpfile = qemu_fopen(portable_path, "r"))) {
fclose(tmpfile);
val = true;
}
free(portable_path);
return val;
}
void xemu_settings_set_path(const char *path)
{
assert(path != NULL);
assert(settings_path == NULL);
settings_path = path;
fprintf(stderr, "%s: config path: %s\n", __func__, settings_path);
}
const char *xemu_settings_get_path(void)
{
if (settings_path != NULL) {
return settings_path;
}
char *base = xemu_settings_detect_portable_mode()
? SDL_GetBasePath()
: SDL_GetPrefPath("xemu", "xemu");
assert(base != NULL);
settings_path = g_strdup_printf("%s%s", base, filename);
SDL_free(base);
fprintf(stderr, "%s: config path: %s\n", __func__, settings_path);
return settings_path;
}
const char *xemu_settings_get_default_eeprom_path(void)
{
static char *eeprom_path = NULL;
if (eeprom_path != NULL) {
return eeprom_path;
}
char *base = xemu_settings_detect_portable_mode()
? SDL_GetBasePath()
: SDL_GetPrefPath("xemu", "xemu");
assert(base != NULL);
eeprom_path = g_strdup_printf("%s%s", base, "eeprom.bin");
SDL_free(base);
return eeprom_path;
}
void xemu_settings_load(void)
{
FILE *fd;
size_t file_size = 0;
char *file_buf = NULL;
const char *settings_path = xemu_settings_get_path();
fd = qemu_fopen(settings_path, "rb");
if (!fd) {
fprintf(stderr, "Failed to open settings path %s for reading\n", settings_path);
goto out;
}
fseek(fd, 0, SEEK_END);
file_size = ftell(fd);
fseek(fd, 0, SEEK_SET);
file_buf = (char *)malloc(file_size + 1);
if (fread(file_buf, file_size, 1, fd) != 1) {
fprintf(stderr, "Failed to read settings\n");
fclose(fd);
fd = NULL;
free(file_buf);
file_buf = NULL;
goto out;
}
file_buf[file_size] = '\x00';
try
{
auto tbl = toml::parse(file_buf);
config_tree.update_from_table(tbl);
settings_failed_to_load = false;
}
catch (const toml::parse_error& err)
{
std::cerr
<< "Error parsing file '" << *err.source().path
<< "':\n" << err.description()
<< "\n (" << err.source().begin << ")\n";
}
out:
config_tree.store_to_struct(&g_config);
}
bool xemu_settings_did_fail_to_load(void)
{
return settings_failed_to_load;
}
void xemu_settings_save(void)
{
FILE *fd = qemu_fopen(xemu_settings_get_path(), "wb");
assert(fd != NULL);
config_tree.update_from_struct(&g_config);
fprintf(fd, "%s", config_tree.generate_delta_toml().c_str());
fclose(fd);
}

View File

@ -28,57 +28,12 @@
extern "C" {
#endif
enum xemu_settings_keys {
XEMU_SETTINGS_SYSTEM_FLASH_PATH,
XEMU_SETTINGS_SYSTEM_BOOTROM_PATH,
XEMU_SETTINGS_SYSTEM_HDD_PATH,
XEMU_SETTINGS_SYSTEM_EEPROM_PATH,
XEMU_SETTINGS_SYSTEM_DVD_PATH,
XEMU_SETTINGS_SYSTEM_MEMORY,
XEMU_SETTINGS_SYSTEM_SHORTANIM,
XEMU_SETTINGS_SYSTEM_HARD_FPU,
XEMU_SETTINGS_AUDIO_USE_DSP,
XEMU_SETTINGS_DISPLAY_SCALE,
XEMU_SETTINGS_DISPLAY_UI_SCALE,
XEMU_SETTINGS_DISPLAY_RENDER_SCALE,
XEMU_SETTINGS_DISPLAY_WINDOW_WIDTH,
XEMU_SETTINGS_DISPLAY_WINDOW_HEIGHT,
XEMU_SETTINGS_INPUT_CONTROLLER_1_GUID,
XEMU_SETTINGS_INPUT_CONTROLLER_2_GUID,
XEMU_SETTINGS_INPUT_CONTROLLER_3_GUID,
XEMU_SETTINGS_INPUT_CONTROLLER_4_GUID,
XEMU_SETTINGS_NETWORK_ENABLED,
XEMU_SETTINGS_NETWORK_BACKEND,
XEMU_SETTINGS_NETWORK_LOCAL_ADDR,
XEMU_SETTINGS_NETWORK_REMOTE_ADDR,
XEMU_SETTINGS_NETWORK_PCAP_INTERFACE,
XEMU_SETTINGS_MISC_USER_TOKEN,
XEMU_SETTINGS_MISC_CHECK_FOR_UPDATE,
XEMU_SETTINGS__COUNT,
XEMU_SETTINGS_INVALID = -1
};
#include "xemu-config.h"
enum DISPLAY_SCALE
{
DISPLAY_SCALE_CENTER,
DISPLAY_SCALE_SCALE,
DISPLAY_SCALE_WS169,
DISPLAY_SCALE_FS43,
DISPLAY_SCALE_STRETCH,
DISPLAY_SCALE__COUNT,
DISPLAY_SCALE_INVALID = -1
};
enum xemu_net_backend {
XEMU_NET_BACKEND_USER,
XEMU_NET_BACKEND_SOCKET_UDP,
XEMU_NET_BACKEND_PCAP,
XEMU_NET_BACKEND__COUNT,
XEMU_NET_BACKEND_INVALID = -1
};
extern struct config g_config;
// Determine whether settings were loaded or not
int xemu_settings_did_fail_to_load(void);
bool xemu_settings_did_fail_to_load(void);
// Override the default config file paths
void xemu_settings_set_path(const char *path);
@ -95,15 +50,14 @@ void xemu_settings_load(void);
// Save config file to disk
void xemu_settings_save(void);
// Config item setters/getters
int xemu_settings_set_string(enum xemu_settings_keys key, const char *str);
int xemu_settings_get_string(enum xemu_settings_keys key, const char **str);
int xemu_settings_set_int(enum xemu_settings_keys key, int val);
int xemu_settings_get_int(enum xemu_settings_keys key, int *val);
int xemu_settings_set_bool(enum xemu_settings_keys key, int val);
int xemu_settings_get_bool(enum xemu_settings_keys key, int *val);
int xemu_settings_set_enum(enum xemu_settings_keys key, int val);
int xemu_settings_get_enum(enum xemu_settings_keys key, int *val);
#include <stdlib.h>
#include <string.h>
static inline void xemu_settings_set_string(const char **str, const char *new_str)
{
free((char*)*str);
*str = strdup(new_str);
}
#ifdef __cplusplus
}

View File

@ -108,7 +108,6 @@ static SDL_Cursor *guest_sprite;
static Notifier mouse_mode_notifier;
static SDL_Window *m_window;
static SDL_GLContext m_context;
int scaling_mode = 1;
struct decal_shader *blit;
static QemuSemaphore display_init_sem;
@ -593,8 +592,8 @@ static void handle_windowevent(SDL_Event *ev)
dpy_set_ui_info(scon->dcl.con, &info);
if (!gui_fullscreen) {
xemu_settings_set_int(XEMU_SETTINGS_DISPLAY_WINDOW_WIDTH, ev->window.data1);
xemu_settings_set_int(XEMU_SETTINGS_DISPLAY_WINDOW_HEIGHT, ev->window.data2);
g_config.display.window.last_width = ev->window.data1;
g_config.display.window.last_height = ev->window.data2;
}
}
sdl2_redraw(scon);
@ -860,9 +859,8 @@ static void sdl2_display_very_early_init(DisplayOptions *o)
SDL_DisplayMode disp_mode;
SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(m_window), &disp_mode);
int win_w, win_h;
xemu_settings_get_int(XEMU_SETTINGS_DISPLAY_WINDOW_WIDTH, &win_w);
xemu_settings_get_int(XEMU_SETTINGS_DISPLAY_WINDOW_HEIGHT, &win_h);
int win_w = g_config.display.window.last_width,
win_h = g_config.display.window.last_height;
if (win_w > 0 && win_h > 0) {
if (disp_mode.w >= win_w && disp_mode.h >= win_h) {
@ -938,8 +936,6 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
assert(o->type == DISPLAY_TYPE_XEMU);
SDL_GL_MakeCurrent(m_window, m_context);
xemu_settings_get_enum(XEMU_SETTINGS_DISPLAY_SCALE, &scaling_mode);
memset(&info, 0, sizeof(info));
SDL_VERSION(&info.version);
@ -1177,20 +1173,20 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl)
// Calculate scaling factors
float scale[2];
if (scaling_mode == DISPLAY_SCALE_STRETCH) {
if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_STRETCH) {
// Stretch to fit
scale[0] = 1.0;
scale[1] = 1.0;
} else if (scaling_mode == DISPLAY_SCALE_CENTER) {
} else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_CENTER) {
// Centered
scale[0] = (float)tw/(float)ww;
scale[1] = (float)th/(float)wh;
} else {
float t_ratio;
if (scaling_mode == DISPLAY_SCALE_WS169) {
if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_16_9) {
// Scale to fit window using a fixed 16:9 aspect ratio
t_ratio = 16.0f/9.0f;
} else if (scaling_mode == DISPLAY_SCALE_FS43) {
} else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_4_3) {
t_ratio = 4.0f/3.0f;
} else {
// Scale to fit, preserving framebuffer aspect ratio