diff --git a/targets/mega65/io_mapper.c b/targets/mega65/io_mapper.c index d1c8178f..42e98fba 100644 --- a/targets/mega65/io_mapper.c +++ b/targets/mega65/io_mapper.c @@ -410,6 +410,7 @@ void io_write ( unsigned int addr, Uint8 data ) eth65_write_reg(addr, data); return; } + static int d6cf_exit_status = 0x42; switch (addr) { case 0x10: // ASCII kbd last press value to zero whatever the written data would be hwa_kbd_move_next_ascii(); @@ -453,16 +454,18 @@ void io_write ( unsigned int addr, Uint8 data ) case 0xCF: // $D6CF - FPGA reconfiguration reg (if $42 is written). In testing mode, Xemu invents some new values here, though! if (data == 0x42) { if (configdb.testing) { // in testing mode, writing $42 would mean to exit emulation! + if (!emu_exit_code) + emu_exit_code = d6cf_exit_status; if (configdb.screenshot_and_exit) vic4_registered_screenshot_request = 1; // this will cause also to exit (as configdb.screenshot_and_exit is not NULL) else XEMUEXIT(0); return; - } - if (ARE_YOU_SURE("FPGA reconfiguration request. System must be reset.\nIs it OK to do now?\nAnswering NO may crash your program requesting this task though,\nor can result in endless loop of trying.", ARE_YOU_SURE_DEFAULT_YES)) { + } else if (ARE_YOU_SURE("FPGA reconfiguration request. System must be reset.\nIs it OK to do now?\nAnswering NO may crash your program requesting this task though,\nor can result in endless loop of trying.", ARE_YOU_SURE_DEFAULT_YES)) { reset_mega65(); } } + d6cf_exit_status = data; return; default: DEBUG("MEGA65: this I/O port is not emulated in Xemu yet: $D6%02X (tried to be written with $%02X)" NL, addr, data); diff --git a/xemu/emutools.c b/xemu/emutools.c index aacb2477..425e512f 100644 --- a/xemu/emutools.c +++ b/xemu/emutools.c @@ -73,6 +73,7 @@ const char *str_are_you_sure_to_exit = "Are you sure to exit Xemu?"; char **xemu_initial_argv = NULL; int xemu_initial_argc = -1; +int emu_exit_code = 0; Uint64 buildinfo_cdate_uts = 0; const char *xemu_initial_cwd = NULL; SDL_Window *sdl_win = NULL; @@ -96,6 +97,7 @@ int texture_x_size_in_bytes; int emu_is_fullscreen = 0; int emu_is_headless = 0; int emu_is_sleepless = 0; +int dialogs_allowed = 1; static int win_xsize, win_ysize; char *sdl_pref_dir = NULL, *sdl_base_dir = NULL, *sdl_inst_dir = NULL; Uint32 sdl_winid; @@ -1008,6 +1010,10 @@ int xemu_post_init ( int locked_texture_update, // use locked texture method [non zero], or malloc'ed stuff [zero]. NOTE: locked access doesn't allow to _READ_ pixels and you must fill ALL pixels! void (*shutdown_callback)(void) // callback function called on exit (can be nULL to not have any emulator specific stuff) ) { + if (emu_is_headless) { + dialogs_allowed = 0; + i_am_sure_override = 1; + } srand((unsigned int)time(NULL)); if (!debug_fp) xemu_init_debug(getenv("XEMU_DEBUG_FILE")); @@ -1321,7 +1327,7 @@ int ARE_YOU_SURE ( const char *s, int flags ) int _sdl_emu_secured_modal_box_ ( const char *items_in, const char *msg ) { char items_buf[512], *items = items_buf; - int buttonid; + int buttonid = 0; SDL_MessageBoxButtonData buttons[16]; SDL_MessageBoxData messageboxdata = { SDL_MESSAGEBOX_WARNING // .flags @@ -1344,6 +1350,7 @@ int _sdl_emu_secured_modal_box_ ( const char *items_in, const char *msg ) switch (*items) { case '!': buttons[messageboxdata.numbuttons].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT; + buttonid = messageboxdata.numbuttons; items++; break; case '?': @@ -1352,6 +1359,7 @@ int _sdl_emu_secured_modal_box_ ( const char *items_in, const char *msg ) break; case '*': buttons[messageboxdata.numbuttons].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT | SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT; + buttonid = messageboxdata.numbuttons; items++; break; default: @@ -1372,13 +1380,16 @@ int _sdl_emu_secured_modal_box_ ( const char *items_in, const char *msg ) *p = 0; items = p + 1; } - save_mouse_grab(); - SDL_ShowMessageBox_custom(&messageboxdata, &buttonid); - xemu_drop_events(); - clear_emu_events(); - SDL_RaiseWindow(sdl_win); - restore_mouse_grab(); - xemu_timekeeping_start(); + if (dialogs_allowed) { + save_mouse_grab(); + SDL_ShowMessageBox_custom(&messageboxdata, &buttonid); + xemu_drop_events(); + clear_emu_events(); + SDL_RaiseWindow(sdl_win); + restore_mouse_grab(); + xemu_timekeeping_start(); + } else + DEBUGPRINT("UI: returning #%d (%s) for choice in dialog box, as dialogs are NOT allowed!" NL, buttonid, buttons[buttonid].text); return buttonid; } diff --git a/xemu/emutools.h b/xemu/emutools.h index 6dfd02b7..15f534ac 100644 --- a/xemu/emutools.h +++ b/xemu/emutools.h @@ -88,22 +88,26 @@ static XEMU_INLINE int CHECK_SNPRINTF( int ret, int limit ) return 0; } +extern int dialogs_allowed; + #define _REPORT_WINDOW_(sdlflag, str, ...) do { \ char _buf_for_win_msg_[4096]; \ CHECK_SNPRINTF(snprintf(_buf_for_win_msg_, sizeof _buf_for_win_msg_, __VA_ARGS__), sizeof _buf_for_win_msg_); \ fprintf(stderr, str ": %s" NL, _buf_for_win_msg_); \ if (debug_fp) \ fprintf(debug_fp, str ": %s" NL, _buf_for_win_msg_); \ - if (sdl_win) { \ - save_mouse_grab(); \ - MSG_POPUP_WINDOW(sdlflag, sdl_window_title, _buf_for_win_msg_, sdl_win); \ - clear_emu_events(); \ - xemu_drop_events(); \ - SDL_RaiseWindow(sdl_win); \ - restore_mouse_grab(); \ - xemu_timekeeping_start(); \ - } else \ - MSG_POPUP_WINDOW(sdlflag, sdl_window_title, _buf_for_win_msg_, sdl_win); \ + if (dialogs_allowed) { \ + if (sdl_win) { \ + save_mouse_grab(); \ + MSG_POPUP_WINDOW(sdlflag, sdl_window_title, _buf_for_win_msg_, sdl_win); \ + clear_emu_events(); \ + xemu_drop_events(); \ + SDL_RaiseWindow(sdl_win); \ + restore_mouse_grab(); \ + xemu_timekeeping_start(); \ + } else \ + MSG_POPUP_WINDOW(sdlflag, sdl_window_title, _buf_for_win_msg_, sdl_win); \ + } \ } while (0) #define INFO_WINDOW(...) _REPORT_WINDOW_(SDL_MESSAGEBOX_INFORMATION, "INFO", __VA_ARGS__) diff --git a/xemu/emutools_basicdefs.h b/xemu/emutools_basicdefs.h index 77b6496e..8bfac832 100644 --- a/xemu/emutools_basicdefs.h +++ b/xemu/emutools_basicdefs.h @@ -238,12 +238,19 @@ static inline int xemu_byte_order_test ( void ) return (r.b.l != ENDIAN_CHECKER_BYTE_L || r.b.h != ENDIAN_CHECKER_BYTE_H || r.w.w != ENDIAN_CHECKER_WORD || r.d != ENDIAN_CHECKER_DWORD); } +extern int emu_exit_code; + +static inline int _get_emu_exit_code ( const int input ) +{ + return input ? input : emu_exit_code; +} + #ifdef __EMSCRIPTEN__ #include -#define XEMUEXIT(n) do { emscripten_cancel_main_loop(); emscripten_force_exit(n); exit(n); } while (0) +#define XEMUEXIT(n) do { const int e = _get_emu_exit_code(n); emscripten_cancel_main_loop(); emscripten_force_exit(e); exit(e); } while (0) #else #include -#define XEMUEXIT(n) exit(n) +#define XEMUEXIT(n) exit(_get_emu_exit_code(n)) #endif #define BOOLEAN_VALUE(n) (!!(n)) diff --git a/xemu/emutools_gui.c b/xemu/emutools_gui.c index 6b7121a0..ee34028d 100644 --- a/xemu/emutools_gui.c +++ b/xemu/emutools_gui.c @@ -1,5 +1,5 @@ /* Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu - Copyright (C)2016,2019-2022 LGB (Gábor Lénárt) + Copyright (C)2016-2023 LGB (Gábor Lénárt) 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 @@ -92,11 +92,15 @@ static const struct xemugui_descriptor_st *xemugui_descriptor_list[] = { int xemugui_init ( const char *name ) { - char avail[256]; // "should be enough" (yeah, I know, the 640K ...) for some names ... - avail[0] = 0; is_xemugui_ok = 0; if (name && name[0] == '\0') // make sure that empty string means the same as NULL pointer passed name = NULL; + if (emu_is_headless) { + name = xemunullgui_descriptor.name; + DEBUGPRINT("GUI: forcing \"%s\" because of headless mode" NL, name); + } + char avail[256]; // "should be enough" (yeah, I know, the 640K ...) for some names ... + avail[0] = 0; for (int a = 0 ;; a++) { strcat(avail, " "); strcat(avail, xemugui_descriptor_list[a]->name); diff --git a/xemu/emutools_gui.h b/xemu/emutools_gui.h index b02d8314..4cc2a0bc 100644 --- a/xemu/emutools_gui.h +++ b/xemu/emutools_gui.h @@ -1,5 +1,5 @@ /* Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu - Copyright (C)2016-2022 LGB (Gábor Lénárt) + Copyright (C)2016-2023 LGB (Gábor Lénárt) 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