From 0ae7ee76473ba8653859bb6b95e5f2fc3a498924 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Wed, 21 Jan 2026 17:20:14 -0700 Subject: [PATCH] ui: Migrate to SDL3 --- include/ui/xemu-display.h | 3 +- ui/xemu-controllers.cc | 26 +++---- ui/xemu-controllers.h | 6 +- ui/xemu-data.c | 4 +- ui/xemu-input.c | 90 +++++++++++----------- ui/xemu-input.h | 14 ++-- ui/xemu-settings.cc | 18 +++-- ui/xemu-snapshots.c | 2 +- ui/xemu.c | 157 +++++++++++++++++++++----------------- ui/xui/common.hh | 4 +- ui/xui/input-manager.cc | 4 +- ui/xui/main-menu.cc | 14 ++-- ui/xui/main.cc | 12 +-- ui/xui/update.cc | 2 +- ui/xui/xemu-hud.h | 2 +- 15 files changed, 187 insertions(+), 171 deletions(-) diff --git a/include/ui/xemu-display.h b/include/ui/xemu-display.h index d47d1fe57d..947fcaa91a 100644 --- a/include/ui/xemu-display.h +++ b/include/ui/xemu-display.h @@ -4,8 +4,7 @@ /* Avoid compiler warning because macro is redefined in SDL_syswm.h. */ #undef WIN32_LEAN_AND_MEAN -#include -#include +#include #include "ui/kbd-state.h" diff --git a/ui/xemu-controllers.cc b/ui/xemu-controllers.cc index 968e9aa00d..427206fdcf 100644 --- a/ui/xemu-controllers.cc +++ b/ui/xemu-controllers.cc @@ -32,8 +32,8 @@ ControllerKeyboardRebindingMap::ConsumeRebindEvent(SDL_Event *event) // Bind on key up // This ensures the UI does not immediately respond once the new binding is // applied - if (event->type == SDL_KEYUP) { - *(g_keyboard_scancode_map[m_table_row]) = event->key.keysym.scancode; + if (event->type == SDL_EVENT_KEY_UP) { + *(g_keyboard_scancode_map[m_table_row]) = event->key.scancode; return RebindEventResult::Complete; } @@ -41,7 +41,7 @@ ControllerKeyboardRebindingMap::ConsumeRebindEvent(SDL_Event *event) } RebindEventResult ControllerGamepadRebindingMap::HandleButtonEvent( - SDL_ControllerButtonEvent *event) + SDL_GamepadButtonEvent *event) { if (m_state->sdl_joystick_id != event->which) { return RebindEventResult::Ignore; @@ -72,7 +72,7 @@ RebindEventResult ControllerGamepadRebindingMap::HandleButtonEvent( // If we only track up events, then we might rebind to a button // that was already held down when the rebinding event began - if (event->type == SDL_CONTROLLERBUTTONDOWN) { + if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { m_seen_key_down = true; return RebindEventResult::Ignore; } @@ -80,7 +80,7 @@ RebindEventResult ControllerGamepadRebindingMap::HandleButtonEvent( // Bind on controller button up // This ensures the UI does not immediately respond once the new binding is // applied - if (event->type != SDL_CONTROLLERBUTTONUP || !m_seen_key_down) { + if (event->type != SDL_EVENT_GAMEPAD_BUTTON_UP || !m_seen_key_down) { return RebindEventResult::Ignore; } @@ -90,7 +90,7 @@ RebindEventResult ControllerGamepadRebindingMap::HandleButtonEvent( } RebindEventResult -ControllerGamepadRebindingMap::HandleAxisEvent(SDL_ControllerAxisEvent *event) +ControllerGamepadRebindingMap::HandleAxisEvent(SDL_GamepadAxisEvent *event) { if (m_state->sdl_joystick_id != event->which) { return RebindEventResult::Ignore; @@ -126,15 +126,15 @@ RebindEventResult ControllerGamepadRebindingMap::ConsumeRebindEvent(SDL_Event *event) { switch (event->type) { - case SDL_CONTROLLERDEVICEREMOVED: - return (m_state->sdl_joystick_id == event->cdevice.which) ? + case SDL_EVENT_GAMEPAD_REMOVED: + return (m_state->sdl_joystick_id == event->gdevice.which) ? RebindEventResult::Complete : RebindEventResult::Ignore; - case SDL_CONTROLLERBUTTONUP: - case SDL_CONTROLLERBUTTONDOWN: - return HandleButtonEvent(&event->cbutton); - case SDL_CONTROLLERAXISMOTION: - return HandleAxisEvent(&event->caxis); + case SDL_EVENT_GAMEPAD_BUTTON_UP: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + return HandleButtonEvent(&event->gbutton); + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + return HandleAxisEvent(&event->gaxis); default: return RebindEventResult::Ignore; } diff --git a/ui/xemu-controllers.h b/ui/xemu-controllers.h index 82f613b61e..5501d7a606 100644 --- a/ui/xemu-controllers.h +++ b/ui/xemu-controllers.h @@ -21,7 +21,7 @@ #define XEMU_CONTROLLERS_H #include "xemu-input.h" -#include +#include enum class RebindEventResult { Ignore, @@ -58,8 +58,8 @@ class ControllerGamepadRebindingMap : public virtual RebindingMap { ControllerState *m_state; bool m_seen_key_down; - RebindEventResult HandleButtonEvent(SDL_ControllerButtonEvent *event); - RebindEventResult HandleAxisEvent(SDL_ControllerAxisEvent *event); + RebindEventResult HandleButtonEvent(SDL_GamepadButtonEvent *event); + RebindEventResult HandleAxisEvent(SDL_GamepadAxisEvent *event); public: RebindEventResult ConsumeRebindEvent(SDL_Event *event) override; diff --git a/ui/xemu-data.c b/ui/xemu-data.c index 171d2c14f3..b0972ce280 100644 --- a/ui/xemu-data.c +++ b/ui/xemu-data.c @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -#include +#include #include #include #include @@ -38,7 +38,7 @@ const char *xemu_get_resource_path(const char *filename) // Allocate an arbitrarily long buffer for resource path storage FIXME: This // could be done better with a growing printf. Keep it simple for now. const size_t resource_path_buffer_len = 1024; - static char *sdl_base_path = NULL; + static const char *sdl_base_path = NULL; static char *resource_path = NULL; if (!sdl_base_path) { diff --git a/ui/xemu-input.c b/ui/xemu-input.c index 8d8388916e..13193f04f5 100644 --- a/ui/xemu-input.c +++ b/ui/xemu-input.c @@ -169,8 +169,8 @@ static void xemu_input_bindings_set_in_range(ControllerState *con) { #define CHECK_RESET_BUTTON(btn) \ check_and_reset_in_range(&con->controller_map->controller_mapping.btn, \ - SDL_CONTROLLER_BUTTON_INVALID, \ - SDL_CONTROLLER_BUTTON_MAX, \ + SDL_GAMEPAD_BUTTON_INVALID, \ + SDL_GAMEPAD_BUTTON_COUNT, \ "Invalid entry for button " #btn ", resetting") CHECK_RESET_BUTTON(a); @@ -193,8 +193,8 @@ static void xemu_input_bindings_set_in_range(ControllerState *con) #define CHECK_RESET_AXIS(axis) \ check_and_reset_in_range(&con->controller_map->controller_mapping.axis, \ - SDL_CONTROLLER_AXIS_INVALID, \ - SDL_CONTROLLER_AXIS_MAX, \ + SDL_GAMEPAD_AXIS_INVALID, \ + SDL_GAMEPAD_AXIS_COUNT, \ "Invalid entry for button " #axis ", resetting") CHECK_RESET_AXIS(axis_trigger_left); @@ -209,10 +209,10 @@ static void xemu_input_bindings_set_in_range(ControllerState *con) static void xemu_input_bindings_reload_map(ControllerState *con) { - assert(con->type == INPUT_DEVICE_SDL_GAMECONTROLLER); + assert(con->type == INPUT_DEVICE_SDL_GAMEPAD); char guid[35] = { 0 }; - SDL_JoystickGetGUIDString(con->sdl_joystick_guid, guid, sizeof(guid)); + SDL_GUIDToString(con->sdl_joystick_guid, guid, sizeof(guid)); if (!xemu_settings_load_gamepad_mapping(guid, &con->controller_map)) { return; } @@ -223,12 +223,12 @@ static void xemu_input_bindings_reload_map(ControllerState *con) ControllerState *iter, *next; bool is_new_mapping; QTAILQ_FOREACH_SAFE (iter, &available_controllers, entry, next) { - if (iter == con || iter->type != INPUT_DEVICE_SDL_GAMECONTROLLER) { + if (iter == con || iter->type != INPUT_DEVICE_SDL_GAMEPAD) { continue; } memset(guid, 0, sizeof(guid)); - SDL_JoystickGetGUIDString(iter->sdl_joystick_guid, guid, sizeof(guid)); + SDL_GUIDToString(iter->sdl_joystick_guid, guid, sizeof(guid)); is_new_mapping = xemu_settings_load_gamepad_mapping(guid, &iter->controller_map); @@ -266,8 +266,8 @@ void xemu_input_init(void) SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); } - if (SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) { - fprintf(stderr, "Failed to initialize SDL gamecontroller subsystem: %s\n", SDL_GetError()); + if (!SDL_Init(SDL_INIT_GAMEPAD)) { + fprintf(stderr, "Failed to initialize SDL gamepad subsystem: %s\n", SDL_GetError()); exit(1); } @@ -289,7 +289,7 @@ void xemu_input_init(void) char buf[128]; snprintf(buf, sizeof(buf), format_str, i); check_and_reset_in_range(g_keyboard_scancode_map[i], - SDL_SCANCODE_UNKNOWN, SDL_NUM_SCANCODES, buf); + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_COUNT, buf); } bound_drivers[0] = get_bound_driver(0); @@ -313,8 +313,8 @@ void xemu_input_init(void) int xemu_input_get_controller_default_bind_port(ControllerState *state, int start) { char guid[35] = { 0 }; - if (state->type == INPUT_DEVICE_SDL_GAMECONTROLLER) { - SDL_JoystickGetGUIDString(state->sdl_joystick_guid, guid, sizeof(guid)); + if (state->type == INPUT_DEVICE_SDL_GAMEPAD) { + SDL_GUIDToString(state->sdl_joystick_guid, guid, sizeof(guid)); } else if (state->type == INPUT_DEVICE_SDL_KEYBOARD) { snprintf(guid, sizeof(guid), "keyboard"); } @@ -348,26 +348,26 @@ void xemu_save_peripheral_settings(int player_index, int peripheral_index, void xemu_input_process_sdl_events(const SDL_Event *event) { - if (event->type == SDL_CONTROLLERDEVICEADDED) { - DPRINTF("Controller Added: %d\n", event->cdevice.which); + if (event->type == SDL_EVENT_GAMEPAD_ADDED) { + DPRINTF("Controller Added: %d\n", event->gdevice.which); // Attempt to open the added controller - SDL_GameController *sdl_con; - sdl_con = SDL_GameControllerOpen(event->cdevice.which); + SDL_Gamepad *sdl_con; + sdl_con = SDL_OpenGamepad(event->gdevice.which); if (sdl_con == NULL) { - DPRINTF("Could not open joystick %d as a game controller\n", event->cdevice.which); + DPRINTF("Could not open joystick %d as a Gamepad\n", event->gdevice.which); return; } // Success! Create a new node to track this controller and continue init ControllerState *new_con = malloc(sizeof(ControllerState)); memset(new_con, 0, sizeof(ControllerState)); - new_con->type = INPUT_DEVICE_SDL_GAMECONTROLLER; - new_con->name = SDL_GameControllerName(sdl_con); - new_con->sdl_gamecontroller = sdl_con; - new_con->sdl_joystick = SDL_GameControllerGetJoystick(new_con->sdl_gamecontroller); - new_con->sdl_joystick_id = SDL_JoystickInstanceID(new_con->sdl_joystick); - new_con->sdl_joystick_guid = SDL_JoystickGetGUID(new_con->sdl_joystick); + new_con->type = INPUT_DEVICE_SDL_GAMEPAD; + new_con->name = SDL_GetGamepadName(sdl_con); + new_con->sdl_gamepad = sdl_con; + new_con->sdl_joystick = SDL_GetGamepadJoystick(new_con->sdl_gamepad); + new_con->sdl_joystick_id = SDL_GetJoystickID(new_con->sdl_joystick); + new_con->sdl_joystick_guid = SDL_GetJoystickGUID(new_con->sdl_joystick); new_con->bound = -1; new_con->peripheral_types[0] = PERIPHERAL_NONE; new_con->peripheral_types[1] = PERIPHERAL_NONE; @@ -375,7 +375,7 @@ void xemu_input_process_sdl_events(const SDL_Event *event) new_con->peripherals[1] = NULL; char guid_buf[35] = { 0 }; - SDL_JoystickGetGUIDString(new_con->sdl_joystick_guid, guid_buf, sizeof(guid_buf)); + SDL_GUIDToString(new_con->sdl_joystick_guid, guid_buf, sizeof(guid_buf)); DPRINTF("Opened %s (%s)\n", new_con->name, guid_buf); QTAILQ_INSERT_TAIL(&available_controllers, new_con, entry); @@ -429,14 +429,14 @@ void xemu_input_process_sdl_events(const SDL_Event *event) xemu_queue_notification(buf); xemu_input_rebind_xmu(port); } - } else if (event->type == SDL_CONTROLLERDEVICEREMOVED) { - DPRINTF("Controller Removed: %d\n", event->cdevice.which); + } else if (event->type == SDL_EVENT_GAMEPAD_REMOVED) { + DPRINTF("Controller Removed: %d\n", event->gdevice.which); int handled = 0; ControllerState *iter, *next; QTAILQ_FOREACH_SAFE(iter, &available_controllers, entry, next) { - if (iter->type != INPUT_DEVICE_SDL_GAMECONTROLLER) continue; + if (iter->type != INPUT_DEVICE_SDL_GAMEPAD) continue; - if (iter->sdl_joystick_id == event->cdevice.which) { + if (iter->sdl_joystick_id == event->gdevice.which) { DPRINTF("Device removed: %s\n", iter->name); // Disconnect @@ -457,8 +457,8 @@ void xemu_input_process_sdl_events(const SDL_Event *event) QTAILQ_REMOVE(&available_controllers, iter, entry); // Deallocate - if (iter->sdl_gamecontroller) { - SDL_GameControllerClose(iter->sdl_gamecontroller); + if (iter->sdl_gamepad) { + SDL_CloseGamepad(iter->sdl_gamepad); } for (int i = 0; i < 2; i++) { @@ -474,8 +474,8 @@ void xemu_input_process_sdl_events(const SDL_Event *event) if (!handled) { DPRINTF("Could not find handle for joystick instance\n"); } - } else if (event->type == SDL_CONTROLLERDEVICEREMAPPED) { - DPRINTF("Controller Remapped: %d\n", event->cdevice.which); + } else if (event->type == SDL_EVENT_GAMEPAD_REMAPPED) { + DPRINTF("Controller Remapped: %d\n", event->gdevice.which); } } @@ -489,7 +489,7 @@ void xemu_input_update_controller(ControllerState *state) if (state->type == INPUT_DEVICE_SDL_KEYBOARD) { xemu_input_update_sdl_kbd_controller_state(state); - } else if (state->type == INPUT_DEVICE_SDL_GAMECONTROLLER) { + } else if (state->type == INPUT_DEVICE_SDL_GAMEPAD) { xemu_input_update_sdl_controller_state(state); } @@ -512,7 +512,7 @@ void xemu_input_update_sdl_kbd_controller_state(ControllerState *state) state->buttons = 0; memset(state->axis, 0, sizeof(state->axis)); - const uint8_t *kbd = SDL_GetKeyboardState(NULL); + const bool *kbd = SDL_GetKeyboardState(NULL); #define KBD_STATE(btn) \ (kbd[g_config.input.keyboard_controller_scancode_map.btn]) @@ -564,8 +564,8 @@ void xemu_input_update_sdl_controller_state(ControllerState *state) memset(state->axis, 0, sizeof(state->axis)); #define SDL_MASK_BUTTON(state, btn, idx) \ - (SDL_GameControllerGetButton( \ - (state)->sdl_gamecontroller, \ + (SDL_GetGamepadButton( \ + (state)->sdl_gamepad, \ (state)->controller_map->controller_mapping.btn) \ << idx) @@ -588,8 +588,8 @@ void xemu_input_update_sdl_controller_state(ControllerState *state) #undef SDL_MASK_BUTTON #define SDL_GET_AXIS(state, axis) \ - SDL_GameControllerGetAxis( \ - (state)->sdl_gamecontroller, \ + SDL_GetGamepadAxis( \ + (state)->sdl_gamepad, \ (state)->controller_map->controller_mapping.axis) state->axis[0] = SDL_GET_AXIS(state, axis_trigger_left); @@ -628,7 +628,7 @@ void xemu_input_update_sdl_controller_state(ControllerState *state) void xemu_input_update_rumble(ControllerState *state) { - if (state->type != INPUT_DEVICE_SDL_GAMECONTROLLER) { + if (state->type != INPUT_DEVICE_SDL_GAMEPAD) { return; } @@ -642,7 +642,7 @@ void xemu_input_update_rumble(ControllerState *state) return; } - SDL_GameControllerRumble(state->sdl_gamecontroller, state->rumble_l, state->rumble_r, 250); + SDL_RumbleGamepad(state->sdl_gamepad, state->rumble_l, state->rumble_r, 250); state->last_rumble_updated_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME); } @@ -688,8 +688,8 @@ void xemu_input_bind(int index, ControllerState *state, int save) if (save) { char guid_buf[35] = { 0 }; if (state) { - if (state->type == INPUT_DEVICE_SDL_GAMECONTROLLER) { - SDL_JoystickGetGUIDString(state->sdl_joystick_guid, guid_buf, sizeof(guid_buf)); + if (state->type == INPUT_DEVICE_SDL_GAMEPAD) { + SDL_GUIDToString(state->sdl_joystick_guid, guid_buf, sizeof(guid_buf)); } else if (state->type == INPUT_DEVICE_SDL_KEYBOARD) { snprintf(guid_buf, sizeof(guid_buf), "keyboard"); } @@ -939,9 +939,9 @@ int xemu_input_get_test_mode(void) void xemu_input_reset_input_mapping(ControllerState *state) { - if (state->type == INPUT_DEVICE_SDL_GAMECONTROLLER) { + if (state->type == INPUT_DEVICE_SDL_GAMEPAD) { char guid[35] = { 0 }; - SDL_JoystickGetGUIDString(state->sdl_joystick_guid, guid, sizeof(guid)); + SDL_GUIDToString(state->sdl_joystick_guid, guid, sizeof(guid)); xemu_settings_reset_controller_mapping(guid); } else if (state->type == INPUT_DEVICE_SDL_KEYBOARD) { xemu_settings_reset_keyboard_mapping(); diff --git a/ui/xemu-input.h b/ui/xemu-input.h index 8b1a742732..0eb2af9d42 100644 --- a/ui/xemu-input.h +++ b/ui/xemu-input.h @@ -2,7 +2,7 @@ * xemu Input Management * * This is the main input abstraction layer for xemu, which is basically just a - * wrapper around SDL2 GameController/Keyboard API to map specifically to an + * wrapper around SDL3 Gamepad/Keyboard API to map specifically to an * Xbox gamepad and support automatic binding, hotplugging, and removal at * runtime. * @@ -25,12 +25,12 @@ #ifndef XEMU_INPUT_H #define XEMU_INPUT_H -#include +#include #include #include "qemu/queue.h" #include "xemu-settings.h" -#include +#include #define DRIVER_DUKE "usb-xbox-gamepad" #define DRIVER_S "usb-xbox-gamepad-s" @@ -70,7 +70,7 @@ enum controller_state_axis_index { enum controller_input_device_type { INPUT_DEVICE_SDL_KEYBOARD, - INPUT_DEVICE_SDL_GAMECONTROLLER, + INPUT_DEVICE_SDL_GAMEPAD, }; enum peripheral_type { PERIPHERAL_NONE, PERIPHERAL_XMU, PERIPHERAL_TYPE_COUNT }; @@ -99,10 +99,10 @@ typedef struct ControllerState { enum controller_input_device_type type; const char *name; - SDL_GameController *sdl_gamecontroller; // if type == INPUT_DEVICE_SDL_GAMECONTROLLER + SDL_Gamepad *sdl_gamepad; // if type == INPUT_DEVICE_SDL_GAMEPAD SDL_Joystick *sdl_joystick; SDL_JoystickID sdl_joystick_id; - SDL_JoystickGUID sdl_joystick_guid; + SDL_GUID sdl_joystick_guid; enum peripheral_type peripheral_types[2]; void *peripherals[2]; @@ -125,7 +125,7 @@ extern "C" { extern int *g_keyboard_scancode_map[25]; void xemu_input_init(void); -void xemu_input_process_sdl_events(const SDL_Event *event); // SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED +void xemu_input_process_sdl_events(const SDL_Event *event); // SDL_EVENT_GAMEPAD_ADDED, SDL_EVENT_GAMEPAD_REMOVED void xemu_input_update_controllers(void); void xemu_input_update_controller(ControllerState *state); void xemu_input_update_sdl_kbd_controller_state(ControllerState *state); diff --git a/ui/xemu-settings.cc b/ui/xemu-settings.cc index 70113c7bc1..5f9148af8a 100644 --- a/ui/xemu-settings.cc +++ b/ui/xemu-settings.cc @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include -#include +#include #include #include #include @@ -77,12 +77,16 @@ const char *xemu_settings_get_base_path(void) return base_path; } - char *base = xemu_settings_detect_portable_mode() - ? SDL_GetBasePath() - : SDL_GetPrefPath("xemu", "xemu"); - assert(base != NULL); - base_path = g_strdup(base); - SDL_free(base); + if (xemu_settings_detect_portable_mode()) { + const char *base = SDL_GetBasePath(); + assert(base != NULL); + base_path = g_strdup(base); + } else { + char *base = SDL_GetPrefPath("xemu", "xemu"); + assert(base != NULL); + base_path = g_strdup(base); + SDL_free(base); + } fprintf(stderr, "%s: base path: %s\n", __func__, base_path); return base_path; } diff --git a/ui/xemu-snapshots.c b/ui/xemu-snapshots.c index 503a7a50b0..a66ff7bac2 100644 --- a/ui/xemu-snapshots.c +++ b/ui/xemu-snapshots.c @@ -21,7 +21,7 @@ #include "xemu-settings.h" #include "xemu-xbe.h" -#include +#include #include #include "block/aio.h" diff --git a/ui/xemu.c b/ui/xemu.c index d998438e5e..ac8311cac9 100644 --- a/ui/xemu.c +++ b/ui/xemu.c @@ -59,6 +59,7 @@ #include #include +#include #ifdef _WIN32 #include "nvapi.h" @@ -106,7 +107,7 @@ static bool alt_grab; static bool ctrl_grab; static int gui_saved_grab; static int gui_fullscreen; -static int gui_grab_code = KMOD_LALT | KMOD_LCTRL; +static int gui_grab_code = SDL_KMOD_LALT | SDL_KMOD_LCTRL; static SDL_Cursor *sdl_cursor_normal; static SDL_Cursor *sdl_cursor_hidden; static int absolute_enabled; @@ -175,11 +176,11 @@ static void sdl_hide_cursor(struct sdl2_console *scon) return; } - SDL_ShowCursor(SDL_DISABLE); + SDL_HideCursor(); SDL_SetCursor(sdl_cursor_hidden); if (!qemu_input_is_absolute(scon->dcl.con)) { - SDL_SetRelativeMouseMode(SDL_TRUE); + SDL_SetWindowRelativeMouseMode(scon->real_window, true); } } @@ -190,7 +191,7 @@ static void sdl_show_cursor(struct sdl2_console *scon) } if (!qemu_input_is_absolute(scon->dcl.con)) { - SDL_SetRelativeMouseMode(SDL_FALSE); + SDL_SetWindowRelativeMouseMode(scon->real_window, false); } if (guest_cursor && @@ -200,7 +201,7 @@ static void sdl_show_cursor(struct sdl2_console *scon) SDL_SetCursor(sdl_cursor_normal); } - SDL_ShowCursor(SDL_ENABLE); + SDL_ShowCursor(); } static void sdl_grab_start(struct sdl2_console *scon) @@ -209,7 +210,8 @@ static void sdl_grab_start(struct sdl2_console *scon) static void sdl_grab_end(struct sdl2_console *scon) { - SDL_SetWindowGrab(scon->real_window, SDL_FALSE); + SDL_SetWindowKeyboardGrab(scon->real_window, false); + SDL_SetWindowMouseGrab(scon->real_window, false); gui_grab = 0; sdl_show_cursor(scon); sdl_update_caption(scon); @@ -217,7 +219,7 @@ static void sdl_grab_end(struct sdl2_console *scon) static void absolute_mouse_grab(struct sdl2_console *scon) { - int mouse_x, mouse_y; + float mouse_x, mouse_y; int scr_w, scr_h; SDL_GetMouseState(&mouse_x, &mouse_y); SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); @@ -232,7 +234,7 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data) if (qemu_input_is_absolute(sdl2_console[0].dcl.con)) { if (!absolute_enabled) { absolute_enabled = 1; - SDL_SetRelativeMouseMode(SDL_FALSE); + SDL_SetWindowRelativeMouseMode(sdl2_console[0].real_window, false); absolute_mouse_grab(&sdl2_console[0]); } } else if (absolute_enabled) { @@ -247,9 +249,9 @@ static void sdl_send_mouse_event(struct sdl2_console *scon, int dx, int dy, int x, int y, int state) { static uint32_t bmap[INPUT_BUTTON__MAX] = { - [INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT), - [INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE), - [INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT), + [INPUT_BUTTON_LEFT] = SDL_BUTTON_MASK(SDL_BUTTON_LEFT), + [INPUT_BUTTON_MIDDLE] = SDL_BUTTON_MASK(SDL_BUTTON_MIDDLE), + [INPUT_BUTTON_RIGHT] = SDL_BUTTON_MASK(SDL_BUTTON_RIGHT), }; static uint32_t prev_state; @@ -283,17 +285,34 @@ static void set_full_screen(struct sdl2_console *scon, bool set) gui_fullscreen = set; if (gui_fullscreen) { - SDL_SetWindowFullscreen(scon->real_window, - (g_config.display.window.fullscreen_exclusive ? - SDL_WINDOW_FULLSCREEN : - SDL_WINDOW_FULLSCREEN_DESKTOP)); + const SDL_DisplayMode *mode = NULL; + SDL_DisplayMode **modes = NULL; + if (g_config.display.window.fullscreen_exclusive) { + SDL_DisplayID display = SDL_GetDisplayForWindow(scon->real_window); + if (display) { + int num_modes = 0; + modes = SDL_GetFullscreenDisplayModes(display, &num_modes); + if (modes && num_modes > 0) { + // First mode is the highest resolution, typically the native resolution + mode = modes[0]; + } + } + if (mode) { + fprintf(stderr, "Selected exclusive fullscreen mode: %dx%d pixel_density=%f refresh_rate=%f\n", mode->w, mode->h, mode->pixel_density, mode->refresh_rate); + } else { + fprintf(stderr, "Failed to get fullscreen display mode: %s\n", SDL_GetError()); + } + } + SDL_SetWindowFullscreenMode(scon->real_window, mode); + SDL_free(modes); + SDL_SetWindowFullscreen(scon->real_window, true); gui_saved_grab = gui_grab; sdl_grab_start(scon); } else { if (!gui_saved_grab) { sdl_grab_end(scon); } - SDL_SetWindowFullscreen(scon->real_window, 0); + SDL_SetWindowFullscreen(scon->real_window, false); } } @@ -307,10 +326,10 @@ static int get_mod_state(void) SDL_Keymod mod = SDL_GetModState(); if (alt_grab) { - return (mod & (gui_grab_code | KMOD_LSHIFT)) == - (gui_grab_code | KMOD_LSHIFT); + return (mod & (gui_grab_code | SDL_KMOD_LSHIFT)) == + (gui_grab_code | SDL_KMOD_LSHIFT); } else if (ctrl_grab) { - return (mod & KMOD_RCTRL) == KMOD_RCTRL; + return (mod & SDL_KMOD_RCTRL) == SDL_KMOD_RCTRL; } else { return (mod & gui_grab_code) == gui_grab_code; } @@ -325,7 +344,7 @@ static void handle_keydown(SDL_Event *ev) int gui_keysym = 0; if (!scon->ignore_hotkeys && gui_key_modifier_pressed && !ev->key.repeat) { - switch (ev->key.keysym.scancode) { + switch (ev->key.scancode) { case SDL_SCANCODE_2: case SDL_SCANCODE_3: case SDL_SCANCODE_4: @@ -338,7 +357,7 @@ static void handle_keydown(SDL_Event *ev) sdl_grab_end(scon); } - win = ev->key.keysym.scancode - SDL_SCANCODE_1; + win = ev->key.scancode - SDL_SCANCODE_1; if (win < sdl2_num_outputs) { sdl2_console[win].hidden = !sdl2_console[win].hidden; if (sdl2_console[win].real_window) { @@ -432,15 +451,15 @@ static void handle_mousebutton(SDL_Event *ev) bev = &ev->button; if (!gui_grab && !qemu_input_is_absolute(scon->dcl.con)) { - if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { + if (ev->type == SDL_EVENT_MOUSE_BUTTON_UP && bev->button == SDL_BUTTON_LEFT) { /* start grabbing all events */ sdl_grab_start(scon); } } else { - if (ev->type == SDL_MOUSEBUTTONDOWN) { - buttonstate |= SDL_BUTTON(bev->button); + if (ev->type == SDL_EVENT_MOUSE_BUTTON_DOWN) { + buttonstate |= SDL_BUTTON_MASK(bev->button); } else { - buttonstate &= ~SDL_BUTTON(bev->button); + buttonstate &= ~SDL_BUTTON_MASK(bev->button); } sdl_send_mouse_event(scon, 0, 0, bev->x, bev->y, buttonstate); } @@ -479,8 +498,8 @@ static void handle_windowevent(SDL_Event *ev) return; } - switch (ev->window.event) { - case SDL_WINDOWEVENT_RESIZED: + switch (ev->type) { + case SDL_EVENT_WINDOW_RESIZED: { QemuUIInfo info; memset(&info, 0, sizeof(info)); @@ -495,11 +514,11 @@ static void handle_windowevent(SDL_Event *ev) } sdl2_redraw(scon); break; - case SDL_WINDOWEVENT_EXPOSED: + case SDL_EVENT_WINDOW_EXPOSED: sdl2_redraw(scon); break; - case SDL_WINDOWEVENT_FOCUS_GAINED: - case SDL_WINDOWEVENT_ENTER: + case SDL_EVENT_WINDOW_FOCUS_GAINED: + case SDL_EVENT_WINDOW_MOUSE_ENTER: if (!gui_grab && (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled)) { absolute_mouse_grab(scon); } @@ -512,16 +531,16 @@ static void handle_windowevent(SDL_Event *ev) */ scon->ignore_hotkeys = get_mod_state(); break; - case SDL_WINDOWEVENT_FOCUS_LOST: + case SDL_EVENT_WINDOW_FOCUS_LOST: if (gui_grab && !gui_fullscreen) { sdl_grab_end(scon); } break; - case SDL_WINDOWEVENT_RESTORED: + case SDL_EVENT_WINDOW_RESTORED: break; - case SDL_WINDOWEVENT_MINIMIZED: + case SDL_EVENT_WINDOW_MINIMIZED: break; - case SDL_WINDOWEVENT_CLOSE: + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: if (qemu_console_is_graphic(scon->dcl.con)) { if (scon->opts->has_window_close && !scon->opts->window_close) { allow_close = false; @@ -535,10 +554,10 @@ static void handle_windowevent(SDL_Event *ev) scon->hidden = true; } break; - case SDL_WINDOWEVENT_SHOWN: + case SDL_EVENT_WINDOW_SHOWN: scon->hidden = false; break; - case SDL_WINDOWEVENT_HIDDEN: + case SDL_EVENT_WINDOW_HIDDEN: scon->hidden = true; break; } @@ -564,19 +583,19 @@ void sdl2_poll_events(struct sdl2_console *scon) xemu_input_process_sdl_events(ev); switch (ev->type) { - case SDL_KEYDOWN: + case SDL_EVENT_KEY_DOWN: if (kbd) break; handle_keydown(ev); break; - case SDL_KEYUP: + case SDL_EVENT_KEY_UP: if (kbd) break; handle_keyup(ev); break; - case SDL_TEXTINPUT: + case SDL_EVENT_TEXT_INPUT: if (kbd) break; handle_textinput(ev); break; - case SDL_QUIT: + case SDL_EVENT_QUIT: if (scon->opts->has_window_close && !scon->opts->window_close) { allow_close = false; } @@ -585,20 +604,20 @@ void sdl2_poll_events(struct sdl2_console *scon) qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI); } break; - case SDL_MOUSEMOTION: + case SDL_EVENT_MOUSE_MOTION: if (mouse) break; handle_mousemotion(ev); break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: if (mouse) break; handle_mousebutton(ev); break; - case SDL_MOUSEWHEEL: + case SDL_EVENT_MOUSE_WHEEL: if (mouse) break; handle_mousewheel(ev); break; - case SDL_WINDOWEVENT: + case SDL_EVENT_WINDOW_FIRST ... SDL_EVENT_WINDOW_LAST: handle_windowevent(ev); break; default: @@ -643,16 +662,15 @@ static void sdl_mouse_define(DisplayChangeListener *dcl, { if (guest_sprite) { - SDL_FreeCursor(guest_sprite); + SDL_DestroyCursor(guest_sprite); } if (guest_sprite_surface) { - SDL_FreeSurface(guest_sprite_surface); + SDL_DestroySurface(guest_sprite_surface); } guest_sprite_surface = - SDL_CreateRGBSurfaceFrom(c->data, c->width, c->height, 32, c->width * 4, - 0xff0000, 0x00ff00, 0xff, 0xff000000); + SDL_CreateSurfaceFrom(c->width, c->height, SDL_PIXELFORMAT_ARGB8888, c->data, c->width * 4); if (!guest_sprite_surface) { fprintf(stderr, "Failed to make rgb surface from %p\n", c); @@ -695,7 +713,7 @@ static void sdl2_display_very_early_init(DisplayOptions *o) setenv("SDL_VIDEODRIVER", "x11", 0); #endif - if (SDL_Init(SDL_INIT_VIDEO)) { + if (!SDL_Init(SDL_INIT_VIDEO)) { fprintf(stderr, "Failed to initialize SDL video subsystem: %s\n", SDL_GetError()); exit(1); @@ -704,7 +722,6 @@ static void sdl2_display_very_early_init(DisplayOptions *o) #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR /* only available since SDL 2.0.8 */ SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); #endif - SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); // Initialize rendering context @@ -761,11 +778,11 @@ static void sdl2_display_very_early_init(DisplayOptions *o) window_height = min_window_height; } - SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); + SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY); // Create main window m_window = SDL_CreateWindow( - title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_width, window_height, + title, window_width, window_height, window_flags); if (m_window == NULL) { fprintf(stderr, "Failed to create main window\n"); @@ -775,9 +792,8 @@ static void sdl2_display_very_early_init(DisplayOptions *o) g_free(title); SDL_SetWindowMinimumSize(m_window, min_window_width, min_window_height); - SDL_DisplayMode disp_mode; - SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(m_window), &disp_mode); - if (disp_mode.w < window_width || disp_mode.h < window_height) { + const SDL_DisplayMode *disp_mode = SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(m_window)); + if (disp_mode && (disp_mode->w < window_width || disp_mode->h < window_height)) { SDL_SetWindowSize(m_window, min_window_width, min_window_height); SDL_SetWindowPosition(m_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); } @@ -786,7 +802,7 @@ static void sdl2_display_very_early_init(DisplayOptions *o) if (m_context != NULL && epoxy_gl_version() < 40) { SDL_GL_MakeCurrent(NULL, NULL); - SDL_GL_DeleteContext(m_context); + SDL_GL_DestroyContext(m_context); m_context = NULL; } @@ -807,8 +823,7 @@ static void sdl2_display_very_early_init(DisplayOptions *o) stbi_set_flip_vertically_on_load(0); unsigned char *icon_data = stbi_load_from_memory(xemu_64x64_data, xemu_64x64_size, &width, &height, &channels, 4); if (icon_data) { - SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(icon_data, width, height, 32, width*4, - 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + SDL_Surface *icon = SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_RGBA32, icon_data, width*4); if (icon) { SDL_SetWindowIcon(m_window, icon); } @@ -845,14 +860,10 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) { uint8_t data = 0; int i; - SDL_SysWMinfo info; assert(o->type == DISPLAY_TYPE_XEMU); SDL_GL_MakeCurrent(m_window, m_context); - memset(&info, 0, sizeof(info)); - SDL_VERSION(&info.version); - gui_fullscreen = o->has_full_screen && o->full_screen; gui_fullscreen |= g_config.display.window.fullscreen_on_startup; @@ -891,13 +902,15 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o) sdl2_console[i].kbd = qkbd_state_init(con); register_displaychangelistener(&sdl2_console[i].dcl); -#if defined(SDL_VIDEO_DRIVER_WINDOWS) || defined(SDL_VIDEO_DRIVER_X11) - if (SDL_GetWindowWMInfo(sdl2_console[i].real_window, &info)) { #if defined(SDL_VIDEO_DRIVER_WINDOWS) - qemu_console_set_window_id(con, (uintptr_t)info.info.win.window); + HWND hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(sdl2_console[i].real_window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); + if (hwnd) { + qemu_console_set_window_id(con, (uintptr_t)hwnd); + } #elif defined(SDL_VIDEO_DRIVER_X11) - qemu_console_set_window_id(con, info.info.x11.window); -#endif + Window xwindow = (Window)SDL_GetNumberProperty(SDL_GetWindowProperties(sdl2_console[i].real_window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); + if (xwindow) { + qemu_console_set_window_id(con, xwindow); } #endif } @@ -1182,7 +1195,7 @@ void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx) { SDL_GLContext sdlctx = (SDL_GLContext)ctx; - SDL_GL_DeleteContext(sdlctx); + SDL_GL_DestroyContext(sdlctx); } int sdl2_gl_make_context_current(DisplayChangeListener *dcl, @@ -1232,11 +1245,11 @@ void sdl2_process_key(struct sdl2_console *scon, { int qcode; - if (ev->keysym.scancode >= qemu_input_map_usb_to_qcode_len) { + if (ev->scancode >= qemu_input_map_usb_to_qcode_len) { return; } - qcode = qemu_input_map_usb_to_qcode[ev->keysym.scancode]; - qkbd_state_key_event(scon->kbd, qcode, ev->type == SDL_KEYDOWN); + qcode = qemu_input_map_usb_to_qcode[ev->scancode]; + qkbd_state_key_event(scon->kbd, qcode, ev->type == SDL_EVENT_KEY_DOWN); } int gArgc; diff --git a/ui/xui/common.hh b/ui/xui/common.hh index 0c674d99b9..5e0bfaf566 100644 --- a/ui/xui/common.hh +++ b/ui/xui/common.hh @@ -18,14 +18,14 @@ // #pragma once -#include +#include #include #include "ui/xemu-settings.h" #define IMGUI_DEFINE_MATH_OPERATORS #include #include -#include +#include #include #include #include diff --git a/ui/xui/input-manager.cc b/ui/xui/input-manager.cc index 5f9de128fc..a18aa9f9ce 100644 --- a/ui/xui/input-manager.cc +++ b/ui/xui/input-manager.cc @@ -23,7 +23,7 @@ void InputManager::Update() if (!g_main_menu.IsInputRebinding()) { ControllerState *iter; QTAILQ_FOREACH (iter, &available_controllers, entry) { - if (iter->type != INPUT_DEVICE_SDL_GAMECONTROLLER) + if (iter->type != INPUT_DEVICE_SDL_GAMEPAD) continue; m_buttons |= iter->buttons; // We simply take any axis that is >10 % activation @@ -62,7 +62,7 @@ void InputManager::Update() #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) #define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, !!(m_buttons & BUTTON_NO)); } #define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(axis[AXIS_NO] - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); } - const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. + const int thumb_dead_zone = 8000; // SDL_gamepad.h suggests using this value. MAP_BUTTON(ImGuiKey_GamepadStart, CONTROLLER_BUTTON_START); MAP_BUTTON(ImGuiKey_GamepadBack, CONTROLLER_BUTTON_BACK); MAP_BUTTON(ImGuiKey_GamepadFaceDown, CONTROLLER_BUTTON_A); // Xbox A, PS Cross diff --git a/ui/xui/main-menu.cc b/ui/xui/main-menu.cc index af290093ec..871b09b294 100644 --- a/ui/xui/main-menu.cc +++ b/ui/xui/main-menu.cc @@ -539,7 +539,7 @@ void MainMenuInputView::Draw() ImGui::PopStyleVar(); } - if (bound_state->type == INPUT_DEVICE_SDL_GAMECONTROLLER) { + if (bound_state->type == INPUT_DEVICE_SDL_GAMEPAD) { Toggle("Enable Rumble", &bound_state->controller_map->enable_rumble); Toggle("Invert Left X Axis", @@ -690,9 +690,9 @@ void MainMenuInputView::PopulateTableController(ControllerState *state) }; int button = *(button_map[i]); - if (button != SDL_CONTROLLER_BUTTON_INVALID) { - remap_button_text = SDL_GameControllerGetStringForButton( - static_cast(button)); + if (button != SDL_GAMEPAD_BUTTON_INVALID) { + remap_button_text = SDL_GetGamepadStringForButton( + static_cast(button)); } } else { int *axis_map[6] = { @@ -706,9 +706,9 @@ void MainMenuInputView::PopulateTableController(ControllerState *state) .axis_trigger_right, }; int axis = *(axis_map[i - num_face_buttons]); - if (axis != SDL_CONTROLLER_AXIS_INVALID) { - remap_button_text = SDL_GameControllerGetStringForAxis( - static_cast(axis)); + if (axis != SDL_GAMEPAD_AXIS_INVALID) { + remap_button_text = SDL_GetGamepadStringForAxis( + static_cast(axis)); } } diff --git a/ui/xui/main.cc b/ui/xui/main.cc index 6039d65b00..9f1c56fa86 100644 --- a/ui/xui/main.cc +++ b/ui/xui/main.cc @@ -17,7 +17,7 @@ // along with this program. If not, see . // -#include +#include #include #include #include @@ -145,7 +145,7 @@ void xemu_hud_init(SDL_Window* window, void* sdl_gl_context) io.IniFilename = NULL; // Setup Platform/Renderer bindings - ImGui_ImplSDL2_InitForOpenGL(window, sdl_gl_context); + ImGui_ImplSDL3_InitForOpenGL(window, sdl_gl_context); ImGui_ImplOpenGL3_Init("#version 150"); g_sdl_window = window; ImPlot::CreateContext(); @@ -164,7 +164,7 @@ void xemu_hud_init(SDL_Window* window, void* sdl_gl_context) void xemu_hud_cleanup(void) { ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplSDL2_Shutdown(); + ImGui_ImplSDL3_Shutdown(); ImGui::DestroyContext(); } @@ -175,7 +175,7 @@ void xemu_hud_process_sdl_events(SDL_Event *event) return; } - ImGui_ImplSDL2_ProcessEvent(event); + ImGui_ImplSDL3_ProcessEvent(event); } void xemu_hud_should_capture_kbd_mouse(int *kbd, int *mouse) @@ -207,13 +207,13 @@ void xemu_hud_render(void) if (!first_boot_window.is_open) { int ww, wh; - SDL_GL_GetDrawableSize(g_sdl_window, &ww, &wh); + SDL_GetWindowSizeInPixels(g_sdl_window, &ww, &wh); RenderFramebuffer(g_tex, ww, wh, g_flip_req); } ImGui_ImplOpenGL3_NewFrame(); io.ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad; - ImGui_ImplSDL2_NewFrame(); + ImGui_ImplSDL3_NewFrame(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; io.BackendFlags |= ImGuiBackendFlags_HasGamepad; g_input_mgr.Update(); diff --git a/ui/xui/update.cc b/ui/xui/update.cc index 29ad11a619..272476e493 100644 --- a/ui/xui/update.cc +++ b/ui/xui/update.cc @@ -22,7 +22,7 @@ #include "viewport-manager.hh" #include #include -#include +#include #include "util/miniz/miniz.h" #include "xemu-version.h" #include diff --git a/ui/xui/xemu-hud.h b/ui/xui/xemu-hud.h index 14e049da68..dc3d913d16 100644 --- a/ui/xui/xemu-hud.h +++ b/ui/xui/xemu-hud.h @@ -23,7 +23,7 @@ #ifndef XEMU_HUD_H #define XEMU_HUD_H -#include +#include #include #ifdef __cplusplus