From cdc36f329e5867fa59a99eb7658c9d0bb3c7ff7c Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sat, 1 Jun 2019 14:29:46 +0300 Subject: [PATCH] Added open dialog to the SDL GUI, misc fixes --- BootROMs/sgb_boot.asm | 16 +++---- Core/sm83_cpu.c | 2 +- Makefile | 19 ++++++-- OpenDialog/cocoa.m | 20 +++++++++ OpenDialog/gtk.c | 96 ++++++++++++++++++++++++++++++++++++++++ OpenDialog/open_dialog.h | 6 +++ OpenDialog/windows.c | 28 ++++++++++++ SDL/gui.c | 34 +++++++++++--- SDL/gui.h | 6 +++ SDL/main.c | 29 +++++++----- 10 files changed, 227 insertions(+), 29 deletions(-) create mode 100644 OpenDialog/cocoa.m create mode 100644 OpenDialog/gtk.c create mode 100644 OpenDialog/open_dialog.h create mode 100644 OpenDialog/windows.c diff --git a/BootROMs/sgb_boot.asm b/BootROMs/sgb_boot.asm index 0574d29c..108af18b 100644 --- a/BootROMs/sgb_boot.asm +++ b/BootROMs/sgb_boot.asm @@ -82,9 +82,9 @@ Start: .sendCommand xor a - ldh [c], a + ld [c], a ld a, $30 - ldh [c], a + ld [c], a ldh a, [$80] call SendByte @@ -112,9 +112,9 @@ Start: ; Done bit ld a, $20 - ldh [c], a + ld [c], a ld a, $30 - ldh [c], a + ld [c], a ; Update command ldh a, [$80] @@ -128,10 +128,10 @@ Start: ; Write to sound registers for DMG compatibility ld c, $13 ld a, $c1 - ldh [c], a + ld [c], a inc c ld a, 7 - ldh [c], a + ld [c], a ; Init BG palette ld a, $fc @@ -168,9 +168,9 @@ SendByte: jr c, .zeroBit add a ; 10 -> 20 .zeroBit - ldh [c], a + ld [c], a ld a, $30 - ldh [c], a + ld [c], a dec d ret z jr .loop diff --git a/Core/sm83_cpu.c b/Core/sm83_cpu.c index fdf357ce..1416000c 100644 --- a/Core/sm83_cpu.c +++ b/Core/sm83_cpu.c @@ -606,7 +606,7 @@ static void ld_dhl_d8(GB_gameboy_t *gb, uint8_t opcode) cycle_write(gb, gb->registers[GB_REGISTER_HL], data); } -uint8_t get_src_value(GB_gameboy_t *gb, uint8_t opcode) +static uint8_t get_src_value(GB_gameboy_t *gb, uint8_t opcode) { uint8_t src_register_id; uint8_t src_low; diff --git a/Makefile b/Makefile index a2df8bf8..38b3e832 100644 --- a/Makefile +++ b/Makefile @@ -65,14 +65,25 @@ endif # Set compilation and linkage flags based on target, platform and configuration +OPEN_DIALOG = OpenDialog/gtk.c + +ifeq ($(PLATFORM),windows32) +OPEN_DIALOG = OpenDialog/windows.c +endif + +ifeq ($(PLATFORM),Darwin) +OPEN_DIALOG = OpenDialog/cocoa.m +endif + + CFLAGS += -Werror -Wall -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES SDL_LDFLAGS := -lSDL2 -lGL ifeq ($(PLATFORM),windows32) -CFLAGS += -IWindows -LDFLAGS += -lmsvcrt -lSDL2main -Wl,/MANIFESTFILE:NUL +CFLAGS += -IWindows -Drandom=rand +LDFLAGS += -lmsvcrt -lcomdlg32 -lSDL2main -Wl,/MANIFESTFILE:NUL SDL_LDFLAGS := -lSDL2 -lopengl32 else -LDFLAGS += -lc -lm +LDFLAGS += -lc -lm -ldl endif ifeq ($(PLATFORM),Darwin) @@ -120,7 +131,7 @@ all: cocoa sdl tester libretro # Get a list of our source files and their respective object file targets CORE_SOURCES := $(shell ls Core/*.c) -SDL_SOURCES := $(shell ls SDL/*.c) +SDL_SOURCES := $(shell ls SDL/*.c) $(OPEN_DIALOG) TESTER_SOURCES := $(shell ls Tester/*.c) ifeq ($(PLATFORM),Darwin) diff --git a/OpenDialog/cocoa.m b/OpenDialog/cocoa.m new file mode 100644 index 00000000..29a722cb --- /dev/null +++ b/OpenDialog/cocoa.m @@ -0,0 +1,20 @@ +#import +#include "open_dialog.h" + + +char *do_open_rom_dialog(void) +{ + @autoreleasepool { + NSWindow *key = [NSApp keyWindow]; + NSOpenPanel *dialog = [NSOpenPanel openPanel]; + dialog.title = @"Open ROM"; + dialog.allowedFileTypes = @[@"gb", @"gbc", @"sgb"]; + [dialog runModal]; + [key makeKeyAndOrderFront:nil]; + NSString *ret = [[[dialog URLs] firstObject] path]; + if (ret) { + return strdup(ret.UTF8String); + } + return NULL; + } +} diff --git a/OpenDialog/gtk.c b/OpenDialog/gtk.c new file mode 100644 index 00000000..2c3bfe76 --- /dev/null +++ b/OpenDialog/gtk.c @@ -0,0 +1,96 @@ +#include "open_dialog.h" +#include +#include +#include +#include +#include + +#define GTK_FILE_CHOOSER_ACTION_OPEN 0 + + +void *_gtk_file_chooser_dialog_new (const char *title, + void *parent, + int action, + const char *first_button_text, + ...); +bool _gtk_init_check (int *argc, char ***argv); +int _gtk_dialog_run(void *); +void _g_free(void *); +void _g_object_unref(void *); +char *_gtk_file_chooser_get_filename(void *); +void _g_log_set_default_handler (void *function, void *data); +void *_gtk_file_filter_new(void); +void _gtk_file_filter_add_pattern(void *filter, const char *pattern); +void _gtk_file_filter_set_name(void *filter, const char *name); +void _gtk_file_chooser_add_filter(void *dialog, void *filter); + +#define LAZY(symbol) static typeof(_##symbol) *symbol = NULL;\ +if (symbol == NULL) symbol = dlsym(handle, #symbol);\ +if (symbol == NULL) goto lazy_error +#define TRY_DLOPEN(name) handle = handle? handle : dlopen(name, RTLD_NOW) + +void nop(){} + +char *do_open_rom_dialog(void) +{ + static void *handle = NULL; + + TRY_DLOPEN("libgtk-3.so"); + TRY_DLOPEN("libgtk-3.so.0"); + TRY_DLOPEN("libgtk-2.so"); + TRY_DLOPEN("libgtk-2.so.0"); + + if (!handle) { + goto lazy_error; + } + + + LAZY(gtk_init_check); + LAZY(gtk_file_chooser_dialog_new); + LAZY(gtk_dialog_run); + LAZY(g_free); + LAZY(g_object_unref); + LAZY(gtk_file_chooser_get_filename); + LAZY(g_log_set_default_handler); + LAZY(gtk_file_filter_new); + LAZY(gtk_file_filter_add_pattern); + LAZY(gtk_file_filter_set_name); + LAZY(gtk_file_chooser_add_filter); + + /* Shut up GTK */ + g_log_set_default_handler(nop, NULL); + + gtk_init_check(0, 0); + + + void *dialog = gtk_file_chooser_dialog_new("Open ROM", + 0, + GTK_FILE_CHOOSER_ACTION_OPEN, + "Open", 0, NULL); + + + void *filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*.gb"); + gtk_file_filter_add_pattern(filter, "*.gbc"); + gtk_file_filter_add_pattern(filter, "*.sgb"); + gtk_file_filter_set_name(filter, "Game Boy ROMs"); + gtk_file_chooser_add_filter(dialog, filter); + + int res = gtk_dialog_run (dialog); + char *ret = NULL; + + if (res == 0) + { + char *filename; + filename = gtk_file_chooser_get_filename(dialog); + ret = strdup(filename); + g_free(filename); + } + + g_object_unref(dialog); + return ret; + +lazy_error: + fprintf(stderr, "Failed to display GTK dialog\n"); + return NULL; +} diff --git a/OpenDialog/open_dialog.h b/OpenDialog/open_dialog.h new file mode 100644 index 00000000..85e5721f --- /dev/null +++ b/OpenDialog/open_dialog.h @@ -0,0 +1,6 @@ +#ifndef open_rom_h +#define open_rom_h + +char *do_open_rom_dialog(void); + +#endif /* open_rom_h */ diff --git a/OpenDialog/windows.c b/OpenDialog/windows.c new file mode 100644 index 00000000..75fe7674 --- /dev/null +++ b/OpenDialog/windows.c @@ -0,0 +1,28 @@ +#include +#include "open_dialog.h" + +char *do_open_rom_dialog(void) +{ + OPENFILENAMEW dialog; + wchar_t filename[MAX_PATH] = {0}; + + memset(&dialog, 0, sizeof(dialog)); + dialog.lStructSize = sizeof(dialog); + dialog.lpstrFile = filename; + dialog.nMaxFile = sizeof(filename); + dialog.lpstrFilter = L"Game Boy ROMs\0*.gb;*.gbc;*.sgb\0All files\0*.*\0\0"; + dialog.nFilterIndex = 1; + dialog.lpstrFileTitle = NULL; + dialog.nMaxFileTitle = 0; + dialog.lpstrInitialDir = NULL; + dialog.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + if (GetOpenFileNameW(&dialog) == TRUE) + { + char *ret = malloc(MAX_PATH * 4); + WideCharToMultiByte(CP_UTF8, 0, filename, sizeof(filename), ret, MAX_PATH * 4, NULL, NULL); + return ret; + } + + return NULL; +} diff --git a/SDL/gui.c b/SDL/gui.c index 39d73571..77167602 100644 --- a/SDL/gui.c +++ b/SDL/gui.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -97,11 +98,11 @@ configuration_t configuration = static const char *help[] ={ -"Drop a GB or GBC ROM\n" -"file to play.\n" +"Drop a ROM to play.\n" "\n" "Keyboard Shortcuts:\n" " Open Menu: Escape\n" +" Open ROM: " MODIFIER_NAME "+O\n" " Reset: " MODIFIER_NAME "+R\n" " Pause: " MODIFIER_NAME "+P\n" " Save state: " MODIFIER_NAME "+(0-9)\n" @@ -267,8 +268,19 @@ static void enter_controls_menu(unsigned index); static void enter_joypad_menu(unsigned index); static void enter_audio_menu(unsigned index); +extern void set_filename(const char *new_filename, typeof(free) *new_free_function); +static void open_rom(unsigned index) +{ + char *filename = do_open_rom_dialog(); + if (filename) { + set_filename(filename, free); + pending_command = GB_SDL_NEW_FILE_COMMAND; + } +} + static const struct menu_item paused_menu[] = { {"Resume", NULL}, + {"Open ROM", open_rom}, {"Emulation Options", enter_emulation_menu}, {"Graphic Options", enter_graphics_menu}, {"Audio Options", enter_audio_menu}, @@ -778,7 +790,6 @@ void connect_joypad(void) } } -extern void set_filename(const char *new_filename, bool new_should_free); void run_gui(bool is_running) { connect_joypad(); @@ -818,6 +829,9 @@ void run_gui(bool is_running) /* Convert Joypad and mouse events (We only generate down events) */ if (gui_state != WAITING_FOR_KEY && gui_state != WAITING_FOR_JBUTTON) { switch (event.type) { + case SDL_WINDOWEVENT: + should_render = true; + break; case SDL_MOUSEBUTTONDOWN: if (gui_state == SHOWING_HELP) { event.type = SDL_KEYDOWN; @@ -957,7 +971,7 @@ void run_gui(bool is_running) break; } case SDL_DROPFILE: { - set_filename(event.drop.file, true); + set_filename(event.drop.file, SDL_free); pending_command = GB_SDL_NEW_FILE_COMMAND; return; } @@ -995,7 +1009,17 @@ void run_gui(bool is_running) } case SDL_KEYDOWN: - if (event.key.keysym.scancode == SDL_SCANCODE_RETURN && gui_state == WAITING_FOR_JBUTTON) { + if (event.key.keysym.scancode == SDL_SCANCODE_O) { + if (event.key.keysym.mod & MODIFIER) { + char *filename = do_open_rom_dialog(); + if (filename) { + set_filename(filename, free); + pending_command = GB_SDL_NEW_FILE_COMMAND; + return; + } + } + } + else if (event.key.keysym.scancode == SDL_SCANCODE_RETURN && gui_state == WAITING_FOR_JBUTTON) { should_render = true; if (joypad_configuration_progress != JOYPAD_BUTTONS_MAX) { configuration.joypad_configuration[joypad_configuration_progress] = -1; diff --git a/SDL/gui.h b/SDL/gui.h index de7ddaa6..6974849a 100644 --- a/SDL/gui.h +++ b/SDL/gui.h @@ -9,6 +9,12 @@ #define JOYSTICK_HIGH 0x4000 #define JOYSTICK_LOW 0x3800 +#ifdef __APPLE__ +#define MODIFIER KMOD_GUI +#else +#define MODIFIER KMOD_CTRL +#endif + extern GB_gameboy_t gb; extern SDL_Window *window; diff --git a/SDL/main.c b/SDL/main.c index 6506a3e6..451ac9c2 100755 --- a/SDL/main.c +++ b/SDL/main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include "utils.h" @@ -30,18 +31,18 @@ static bool underclock_down = false, rewind_down = false, do_rewind = false, rew static double clock_mutliplier = 1.0; static char *filename = NULL; -static bool should_free_filename = false; +static typeof(free) *free_function = NULL; static char *battery_save_path_ptr; SDL_AudioDeviceID device_id; -void set_filename(const char *new_filename, bool new_should_free) +void set_filename(const char *new_filename, typeof(free) *new_free_function) { - if (filename && should_free_filename) { - SDL_free(filename); + if (filename && free_function) { + free_function(filename); } filename = (char *) new_filename; - should_free_filename = new_should_free; + free_function = new_free_function; } static SDL_AudioSpec want_aspec, have_aspec; @@ -101,11 +102,6 @@ static void open_menu(void) static void handle_events(GB_gameboy_t *gb) { -#ifdef __APPLE__ -#define MODIFIER KMOD_GUI -#else -#define MODIFIER KMOD_CTRL -#endif SDL_Event event; while (SDL_PollEvent(&event)) { @@ -115,7 +111,7 @@ static void handle_events(GB_gameboy_t *gb) break; case SDL_DROPFILE: { - set_filename(event.drop.file, true); + set_filename(event.drop.file, SDL_free); pending_command = GB_SDL_NEW_FILE_COMMAND; break; } @@ -226,6 +222,17 @@ static void handle_events(GB_gameboy_t *gb) pending_command = GB_SDL_RESET_COMMAND; } break; + + case SDL_SCANCODE_O: { + if (event.key.keysym.mod & MODIFIER) { + char *filename = do_open_rom_dialog(); + if (filename) { + set_filename(filename, free); + pending_command = GB_SDL_NEW_FILE_COMMAND; + } + } + break; + } case SDL_SCANCODE_P: if (event.key.keysym.mod & MODIFIER) {