544 lines
17 KiB
C
544 lines
17 KiB
C
#include "config.h"
|
|
|
|
#define get_object(id) gtk_builder_get_object(builder, id)
|
|
#define builder_get(type, id) type(get_object(id))
|
|
|
|
gchar* config_file_path;
|
|
GKeyFile *key_file;
|
|
|
|
static void print_config_error(GError *error) {
|
|
if (error == NULL) return;
|
|
|
|
if (!g_error_matches(error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND) && !g_error_matches(error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) {
|
|
g_warning("Config error: %s", error->message);
|
|
}
|
|
}
|
|
|
|
void _print_config(config_t *config, GLogLevelFlags log_level) {
|
|
#define EXPAND_GROUP(name, members) { \
|
|
g_log(G_LOG_DOMAIN, log_level, "[%s]", #name); \
|
|
struct config_ ## name ## _t *group = &config->name; \
|
|
members \
|
|
}
|
|
|
|
#define EXPAND_GROUP_MEMBER(member, key_type, default_value) \
|
|
g_log(G_LOG_DOMAIN, log_level, "%s="FORMAT_FOR_KEY_TYPE(key_type)"", #member, group->member);
|
|
|
|
EXPAND_CONFIG
|
|
#undef EXPAND_GROUP
|
|
#undef EXPAND_GROUP_MEMBER
|
|
}
|
|
|
|
// Duplicates the input and converts the first character to uppercase
|
|
gchar* ascii_ucfirst(gchar *str) {
|
|
gchar *out = g_strdup(str);
|
|
out[0] = g_ascii_toupper(str[0]);
|
|
|
|
return out;
|
|
}
|
|
|
|
void load_config_from_key_file(config_t *config, GKeyFile *key_file) {
|
|
g_message("Loading config from key file");
|
|
GError *error = NULL;
|
|
|
|
#define EXPAND_GROUP(name_arg, members) { \
|
|
struct config_ ## name_arg ## _t *group = &config->name_arg; \
|
|
g_autofree gchar *group_name = ascii_ucfirst(#name_arg); \
|
|
members \
|
|
}
|
|
|
|
#define EXPAND_GROUP_MEMBER(member, key_type, default_value) \
|
|
group->member = g_key_file_get_##key_type(key_file, group_name, #member, &error); \
|
|
if (error != NULL) { \
|
|
group->member = default_value; \
|
|
print_config_error(error); \
|
|
g_clear_error(&error); \
|
|
}
|
|
|
|
EXPAND_CONFIG
|
|
|
|
if (config->emulation.rewind_duration > 600) {
|
|
g_warning("Setting Emulation.rewind_duration too high might affect performance.");
|
|
}
|
|
|
|
#undef EXPAND_GROUP
|
|
#undef EXPAND_GROUP_MEMBER
|
|
}
|
|
|
|
void print_config(config_t *config) {
|
|
_print_config(config, G_LOG_LEVEL_MESSAGE);
|
|
}
|
|
|
|
void save_config_to_key_file(config_t *config, GKeyFile *key_file) {
|
|
g_message("Saving config to key file");
|
|
GError *error = NULL;
|
|
gchar *group_name;
|
|
|
|
#define EXPAND_GROUP(name_arg, members) { \
|
|
struct config_ ## name_arg ## _t *group = &config->name_arg; \
|
|
g_autofree gchar *group_name = ascii_ucfirst(#name_arg); \
|
|
members \
|
|
}
|
|
|
|
#define EXPAND_GROUP_MEMBER_IF_0(member, key_type, default_value) \
|
|
g_key_file_set_##key_type(key_file, group_name, #member, group->member);
|
|
|
|
#define EXPAND_GROUP_MEMBER_IF_1(member, key_type, default_value) \
|
|
if (group->member != NULL) { \
|
|
g_key_file_set_##key_type(key_file, group_name, #member, group->member); \
|
|
} \
|
|
else if (g_key_file_has_key(key_file, group_name, #member, &error)) { \
|
|
if (error != NULL) { \
|
|
g_warning("%s", error->message); \
|
|
g_clear_error(&error); \
|
|
} \
|
|
g_key_file_remove_key(key_file, group_name, #member, &error); \
|
|
if (error != NULL) { \
|
|
g_warning("%s", error->message); \
|
|
g_clear_error(&error); \
|
|
} \
|
|
}
|
|
|
|
#define EXPAND_GROUP_MEMBER_IF_EVAL(y, member, key_type, default_value) EXPAND_GROUP_MEMBER_IF_ ## y(member, key_type, default_value)
|
|
#define EXPAND_GROUP_MEMBER_IF(member, key_type, is_pointer, default_value) EXPAND_GROUP_MEMBER_IF_EVAL(is_pointer, member, key_type, default_value)
|
|
#define EXPAND_GROUP_MEMBER(member, key_type, default_value) EXPAND_GROUP_MEMBER_IF(member, key_type, GTYPE_IS_POINTER(key_type), default_value)
|
|
|
|
EXPAND_CONFIG
|
|
|
|
#undef EXPAND_GROUP
|
|
#undef EXPAND_GROUP_MEMBER
|
|
#undef EXPAND_GROUP_MEMBER_IF
|
|
#undef EXPAND_GROUP_MEMBER_IF_EVAL
|
|
#undef EXPAND_GROUP_MEMBER_IF_0
|
|
#undef EXPAND_GROUP_MEMBER_IF_1
|
|
|
|
// Save config to disk
|
|
if (!g_key_file_save_to_file(key_file, config_file_path, &error)) {
|
|
g_warning ("Failed to save %s: %s", config_file_path, error->message);
|
|
g_error_free(error);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void init_config(GApplication *app, gchar *path, GDateTime **modification_date) {
|
|
free_config();
|
|
key_file = g_key_file_new();
|
|
|
|
if (path != NULL) {
|
|
config_file_path = path;
|
|
}
|
|
else {
|
|
config_file_path = g_build_filename(g_get_user_config_dir(), CONFIG_FILE, NULL);
|
|
}
|
|
|
|
load_config(app, modification_date);
|
|
}
|
|
|
|
void load_config(GApplication *app, GDateTime **modification_date) {
|
|
GError *error = NULL;
|
|
|
|
g_message("Trying to load config from %s", config_file_path);
|
|
|
|
g_autoptr(GFile) file = g_file_new_for_path(config_file_path);
|
|
g_autoptr(GFileInfo) file_info = g_file_query_info(file, "time::*", G_FILE_QUERY_INFO_NONE, NULL, NULL);
|
|
|
|
#if GLIB_CHECK_VERSION(2,62,0)
|
|
*modification_date = g_file_info_get_modification_date_time(file_info);
|
|
#else
|
|
GTimeVal tv;
|
|
g_file_info_get_modification_time(file_info, &tv);
|
|
*modification_date = g_date_time_new_from_timeval_utc(&tv);
|
|
#endif
|
|
|
|
if (!g_key_file_load_from_file(key_file, config_file_path, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error)) {
|
|
if (error->domain == G_FILE_ERROR) {
|
|
g_warning("Unable to load %s: %s", config_file_path, error->message);
|
|
}
|
|
else if (error->domain == G_KEY_FILE_ERROR) {
|
|
g_warning("Failed to parse %s: %s", config_file_path, error->message);
|
|
}
|
|
|
|
g_error_free(error);
|
|
}
|
|
|
|
load_config_from_key_file(&config, key_file);
|
|
_print_config(&config, G_LOG_LEVEL_DEBUG);
|
|
|
|
// Update GAction states
|
|
g_action_group_change_action_state(G_ACTION_GROUP(app), "toggle_mute", g_variant_new_boolean(config.audio.muted));
|
|
}
|
|
|
|
void save_config(GtkWindow *main_window, GDateTime *saved_modification_date) {
|
|
GError *error = NULL;
|
|
|
|
g_message("Trying to save config to %s", config_file_path);
|
|
|
|
g_autoptr(GFile) file = g_file_new_for_path(config_file_path);
|
|
g_autoptr(GFileInfo) file_info = g_file_query_info(file, "time::*", G_FILE_QUERY_INFO_NONE, NULL, NULL);
|
|
|
|
#if GLIB_CHECK_VERSION(2,62,0)
|
|
GDateTime *modification_date = g_file_info_get_modification_date_time(file_info);
|
|
#else
|
|
GTimeVal tv;
|
|
g_file_info_get_modification_time(file_info, &tv);
|
|
GDateTime *modification_date = g_date_time_new_from_timeval_utc(&tv);
|
|
#endif
|
|
|
|
if (!g_date_time_equal(saved_modification_date, modification_date)) {
|
|
GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(
|
|
main_window,
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_QUESTION,
|
|
GTK_BUTTONS_YES_NO,
|
|
"It looks like the configuration has changed on disk. Overwrite?"
|
|
));
|
|
|
|
gtk_window_set_title(GTK_WINDOW(dialog), "SameBoy");
|
|
|
|
gint result = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
|
|
switch (result) {
|
|
case GTK_RESPONSE_YES:
|
|
save_config_to_key_file(&config, key_file);
|
|
break;
|
|
|
|
default:
|
|
// Action has been canceled
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
save_config_to_key_file(&config, key_file);
|
|
}
|
|
}
|
|
|
|
void free_config(void) {
|
|
if (key_file != NULL) {
|
|
g_key_file_free(key_file);
|
|
key_file = NULL;
|
|
}
|
|
}
|
|
|
|
void update_boot_rom_selector(GtkBuilder *builder) {
|
|
GtkComboBoxText *combo_box = builder_get(GTK_COMBO_BOX_TEXT, "boot_rom_selector");
|
|
gtk_combo_box_text_remove_all(combo_box);
|
|
gtk_combo_box_text_append(combo_box, "auto", "Use Built-in Boot ROMs");
|
|
if (config.emulation.boot_rom_path != NULL && !g_str_equal(config.emulation.boot_rom_path, "auto") && !g_str_equal(config.emulation.boot_rom_path, "other")) {
|
|
gtk_combo_box_text_append(combo_box, config.emulation.boot_rom_path, config.emulation.boot_rom_path);
|
|
gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo_box), config.emulation.boot_rom_path);
|
|
}
|
|
else {
|
|
gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo_box), "auto");
|
|
}
|
|
gtk_combo_box_text_append_text(combo_box, "<separator>");
|
|
gtk_combo_box_text_append(combo_box, "other", "Other");
|
|
}
|
|
|
|
GB_color_correction_mode_t config_get_color_correction_mode(void) {
|
|
if (config.video.color_correction_id == NULL) goto default_value;
|
|
|
|
if (g_strcmp0(config.video.color_correction_id, "disabled") == 0) {
|
|
return GB_COLOR_CORRECTION_DISABLED;
|
|
}
|
|
else if (g_strcmp0(config.video.color_correction_id, "correct_color_curves") == 0) {
|
|
return GB_COLOR_CORRECTION_CORRECT_CURVES;
|
|
}
|
|
else if (g_strcmp0(config.video.color_correction_id, "emulate_hardware") == 0) {
|
|
return GB_COLOR_CORRECTION_EMULATE_HARDWARE;
|
|
}
|
|
else if (g_strcmp0(config.video.color_correction_id, "preserve_brightness") == 0) {
|
|
return GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS;
|
|
}
|
|
else if (g_strcmp0(config.video.color_correction_id, "reduce_contrast") == 0) {
|
|
return GB_COLOR_CORRECTION_REDUCE_CONTRAST;
|
|
}
|
|
|
|
// This should not happen
|
|
g_warning("Unknown color correction mode: %s\nFalling back to “Emulate Hardware”", config.video.color_correction_id);
|
|
default_value: return GB_COLOR_CORRECTION_EMULATE_HARDWARE;
|
|
}
|
|
|
|
void config_set_color_correction_mode(GB_color_correction_mode_t mode) {
|
|
switch (mode) {
|
|
case GB_COLOR_CORRECTION_DISABLED:
|
|
config.video.color_correction_id = "disabled";
|
|
break;
|
|
case GB_COLOR_CORRECTION_CORRECT_CURVES:
|
|
config.video.color_correction_id = "correct_color_curves";
|
|
break;
|
|
case GB_COLOR_CORRECTION_EMULATE_HARDWARE:
|
|
config.video.color_correction_id = "emulate_hardware";
|
|
break;
|
|
case GB_COLOR_CORRECTION_PRESERVE_BRIGHTNESS:
|
|
config.video.color_correction_id = "preserve_brightness";
|
|
break;
|
|
case GB_COLOR_CORRECTION_REDUCE_CONTRAST:
|
|
config.video.color_correction_id = "reduce_contrast";
|
|
break;
|
|
}
|
|
}
|
|
|
|
GB_frame_blending_mode_t config_get_frame_blending_mode(void) {
|
|
if (config.video.frame_blending_mode == NULL) goto default_value;
|
|
|
|
if (g_strcmp0(config.video.frame_blending_mode, "disabled") == 0) {
|
|
return GB_FRAME_BLENDING_MODE_DISABLED;
|
|
}
|
|
else if (g_strcmp0(config.video.frame_blending_mode, "simple") == 0) {
|
|
return GB_FRAME_BLENDING_MODE_SIMPLE;
|
|
}
|
|
else if (g_strcmp0(config.video.frame_blending_mode, "accurate") == 0) {
|
|
return GB_FRAME_BLENDING_MODE_ACCURATE;
|
|
}
|
|
|
|
// This should not happen
|
|
g_warning("Unknown frame blending mode: %s\nFalling back to “Disabled”", config.video.frame_blending_mode);
|
|
default_value: return GB_FRAME_BLENDING_MODE_DISABLED;
|
|
}
|
|
|
|
void config_set_frame_blending_mode(GB_frame_blending_mode_t mode) {
|
|
switch (mode) {
|
|
case GB_FRAME_BLENDING_MODE_DISABLED:
|
|
config.video.frame_blending_mode = "disabled";
|
|
break;
|
|
case GB_FRAME_BLENDING_MODE_SIMPLE:
|
|
config.video.frame_blending_mode = "simple";
|
|
break;
|
|
case GB_FRAME_BLENDING_MODE_ACCURATE:
|
|
case GB_FRAME_BLENDING_MODE_ACCURATE_ODD:
|
|
config.video.frame_blending_mode = "accurate";
|
|
break;
|
|
}
|
|
}
|
|
|
|
GB_border_mode_t config_get_display_border_mode(void) {
|
|
if (config.video.display_border_mode == NULL) goto default_value;
|
|
|
|
if (g_strcmp0(config.video.display_border_mode, "never") == 0) {
|
|
return GB_BORDER_NEVER;
|
|
}
|
|
else if (g_strcmp0(config.video.display_border_mode, "sgb_only") == 0) {
|
|
return GB_BORDER_SGB;
|
|
}
|
|
else if (g_strcmp0(config.video.display_border_mode, "always") == 0) {
|
|
return GB_BORDER_ALWAYS;
|
|
}
|
|
|
|
// This should not happen
|
|
g_warning("Unknown SGB border mode: %s\nFalling back to “Never”", config.video.display_border_mode);
|
|
default_value: return GB_BORDER_NEVER;
|
|
}
|
|
|
|
void config_set_display_border_mode(GB_border_mode_t mode) {
|
|
switch (mode) {
|
|
case GB_BORDER_NEVER:
|
|
config.video.display_border_mode = "never";
|
|
break;
|
|
case GB_BORDER_SGB:
|
|
config.video.display_border_mode = "sgb_only";
|
|
break;
|
|
case GB_BORDER_ALWAYS:
|
|
config.video.display_border_mode = "always";
|
|
break;
|
|
}
|
|
}
|
|
|
|
const GB_palette_t* config_get_monochrome_palette(void) {
|
|
if (config.video.monochrome_palette_id == NULL) goto default_value;
|
|
|
|
if (g_strcmp0(config.video.monochrome_palette_id, "greyscale") == 0) {
|
|
return &GB_PALETTE_GREY;
|
|
}
|
|
else if (g_strcmp0(config.video.monochrome_palette_id, "lime") == 0) {
|
|
return &GB_PALETTE_DMG;
|
|
}
|
|
else if (g_strcmp0(config.video.monochrome_palette_id, "olive") == 0) {
|
|
return &GB_PALETTE_MGB;
|
|
}
|
|
else if (g_strcmp0(config.video.monochrome_palette_id, "teal") == 0) {
|
|
return &GB_PALETTE_GBL;
|
|
}
|
|
|
|
// This should not happen
|
|
g_warning("Unknown monochrome palette: %s\nFalling back to “Greyscale”", config.video.monochrome_palette_id);
|
|
default_value: return &GB_PALETTE_GREY;
|
|
}
|
|
|
|
void config_set_monochrome_palette(const GB_palette_t *mode) {
|
|
g_message("%p | %p | %p | %p | %p", mode, &GB_PALETTE_GREY, &GB_PALETTE_DMG, &GB_PALETTE_MGB, &GB_PALETTE_GBL);
|
|
|
|
if (mode == &GB_PALETTE_GREY) {
|
|
config.video.monochrome_palette_id = "greyscale";
|
|
}
|
|
else if (mode == &GB_PALETTE_DMG) {
|
|
config.video.monochrome_palette_id = "lime";
|
|
}
|
|
else if (mode == &GB_PALETTE_MGB) {
|
|
config.video.monochrome_palette_id = "olive";
|
|
}
|
|
else if (mode == &GB_PALETTE_GBL) {
|
|
config.video.monochrome_palette_id = "teal";
|
|
}
|
|
}
|
|
|
|
GB_highpass_mode_t config_get_highpass_mode(void) {
|
|
if (config.audio.high_pass_filter_id == NULL) goto default_value;
|
|
|
|
if (g_strcmp0(config.audio.high_pass_filter_id, "disabled") == 0) {
|
|
return GB_HIGHPASS_OFF;
|
|
}
|
|
else if (g_strcmp0(config.audio.high_pass_filter_id, "emulate_hardware") == 0) {
|
|
return GB_HIGHPASS_ACCURATE;
|
|
}
|
|
else if (g_strcmp0(config.audio.high_pass_filter_id, "preserve_waveform") == 0) {
|
|
return GB_HIGHPASS_REMOVE_DC_OFFSET;
|
|
}
|
|
|
|
// This should not happen
|
|
g_warning("Unknown highpass mode: %s\nFalling back to “Accurate”", config.audio.high_pass_filter_id);
|
|
default_value: return GB_HIGHPASS_ACCURATE;
|
|
}
|
|
|
|
void config_set_highpass_mode(GB_highpass_mode_t mode) {
|
|
switch (mode) {
|
|
case GB_HIGHPASS_OFF:
|
|
config.audio.high_pass_filter_id = "disabled";
|
|
break;
|
|
case GB_HIGHPASS_MAX:
|
|
g_warning("GB_HIGHPASS_MAX is not a valid highpass mode, falling back to “Accurate”.");
|
|
case GB_HIGHPASS_ACCURATE:
|
|
config.audio.high_pass_filter_id = "emulate_hardware";
|
|
break;
|
|
case GB_HIGHPASS_REMOVE_DC_OFFSET:
|
|
config.audio.high_pass_filter_id = "preserve_waveform";
|
|
break;
|
|
}
|
|
}
|
|
|
|
const GB_rumble_mode_t config_get_rumble_mode(void) {
|
|
if (config.controls.rumble_mode == NULL) goto default_value;
|
|
|
|
if (g_strcmp0(config.controls.rumble_mode, "never") == 0) {
|
|
return GB_RUMBLE_DISABLED;
|
|
}
|
|
else if (g_strcmp0(config.controls.rumble_mode, "rumble_cartridges") == 0) {
|
|
return GB_RUMBLE_CARTRIDGE_ONLY;
|
|
}
|
|
else if (g_strcmp0(config.controls.rumble_mode, "always") == 0) {
|
|
return GB_RUMBLE_ALL_GAMES;
|
|
}
|
|
|
|
// This should not happen
|
|
g_warning("Unknown rumble mode: %s\nFalling back to “Never”", config.controls.rumble_mode);
|
|
default_value: return GB_RUMBLE_DISABLED;
|
|
}
|
|
|
|
void config_set_rumble_mode(GB_rumble_mode_t mode) {
|
|
switch (mode) {
|
|
case GB_RUMBLE_DISABLED:
|
|
config.controls.rumble_mode = "never";
|
|
break;
|
|
case GB_RUMBLE_CARTRIDGE_ONLY:
|
|
config.controls.rumble_mode = "rumble_cartridges";
|
|
break;
|
|
case GB_RUMBLE_ALL_GAMES:
|
|
config.controls.rumble_mode = "always";
|
|
break;
|
|
}
|
|
}
|
|
|
|
GB_model_t config_get_model(void) {
|
|
if (g_strcmp0(config.emulation.model, "DMG") == 0) {
|
|
return config_get_dmg_model();
|
|
}
|
|
else if (g_strcmp0(config.emulation.model, "MGB") == 0) {
|
|
g_warning("Emulation of MGBs is unsupported, falling back to DMG.");
|
|
|
|
return config_get_dmg_model();
|
|
}
|
|
else if (g_strcmp0(config.emulation.model, "AGB") == 0) {
|
|
return GB_MODEL_AGB;
|
|
}
|
|
else if (g_strcmp0(config.emulation.model, "SGB") == 0) {
|
|
return config_get_sgb_model();
|
|
}
|
|
|
|
return config_get_cgb_model();
|
|
}
|
|
|
|
GB_model_t config_get_model_type(struct CliOptionData *cli_options) {
|
|
if (cli_options->model != -1) {
|
|
return cli_options->model;
|
|
}
|
|
|
|
return config_get_model();
|
|
}
|
|
|
|
void config_set_model(GB_model_t model) {
|
|
switch (model & GB_MODEL_FAMILY_MASK) {
|
|
case GB_MODEL_DMG_FAMILY:
|
|
if (model & GB_MODEL_SGB) {
|
|
config.emulation.model = "SGB";
|
|
}
|
|
else {
|
|
config.emulation.model = "DMG";
|
|
}
|
|
break;
|
|
|
|
case GB_MODEL_MGB_FAMILY:
|
|
config.emulation.model = "MGB";
|
|
break;
|
|
|
|
case GB_MODEL_CGB_FAMILY:
|
|
if (model & GB_MODEL_AGB) {
|
|
config.emulation.model = "AGB";
|
|
}
|
|
else {
|
|
config.emulation.model = "CGB";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
GB_model_t config_get_dmg_model(void) {
|
|
if (config.emulation.dmg_revision_name == NULL) goto default_value;
|
|
|
|
// TODO: Synchronize with GB_model_t (Core/gb.h)
|
|
if (g_strcmp0(config.emulation.dmg_revision_name, "DMG_CPU_B") == 0) {
|
|
return GB_MODEL_DMG_B;
|
|
}
|
|
|
|
default_value: return GB_MODEL_DMG_B;
|
|
}
|
|
|
|
GB_model_t config_get_sgb_model(void) {
|
|
if (config.emulation.sgb_revision_name == NULL) goto default_value;
|
|
|
|
// TODO: Synchronize with GB_model_t (Core/gb.h)
|
|
if (g_strcmp0(config.emulation.sgb_revision_name, "SGB1_NTSC") == 0) {
|
|
return GB_MODEL_SGB_NTSC;
|
|
}
|
|
else if (g_strcmp0(config.emulation.sgb_revision_name, "SGB1_PAL") == 0) {
|
|
return GB_MODEL_SGB_PAL;
|
|
}
|
|
else if (g_strcmp0(config.emulation.sgb_revision_name, "SGB2") == 0) {
|
|
return GB_MODEL_SGB2;
|
|
}
|
|
|
|
default_value: return GB_MODEL_SGB2;
|
|
}
|
|
|
|
GB_model_t config_get_cgb_model(void) {
|
|
if (config.emulation.cgb_revision_name == NULL) goto default_value;
|
|
|
|
// TODO: Synchronize with GB_model_t (Core/gb.h)
|
|
if (g_strcmp0(config.emulation.cgb_revision_name, "CPU_CGB_C") == 0) {
|
|
return GB_MODEL_CGB_C;
|
|
}
|
|
else if (g_strcmp0(config.emulation.cgb_revision_name, "CPU_CGB_E") == 0) {
|
|
return GB_MODEL_CGB_E;
|
|
}
|
|
|
|
default_value: return GB_MODEL_CGB_E;
|
|
}
|